VirtualBox

Ignore:
Timestamp:
Sep 10, 2010 12:46:23 PM (14 years ago)
Author:
vboxsync
Message:

Main: Save guest dimension in save state; add method for queering this info to IMachine.

File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/DisplayUtils.cpp

    r32332 r32398  
    11/* $Id$ */
    22/** @file
    3  * Implementation of IMachine in VBoxSVC.
     3 * Implementation of IDisplay helpers.
    44 */
    55
    66/*
    7  * Copyright (C) 2006-2010 Oracle Corporation
     7 * Copyright (C) 2010 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1616 */
    1717
    18 /* Make sure all the stdint.h macros are included - must come first! */
    19 #ifndef __STDC_LIMIT_MACROS
    20 # define __STDC_LIMIT_MACROS
    21 #endif
    22 #ifndef __STDC_CONSTANT_MACROS
    23 # define __STDC_CONSTANT_MACROS
    24 #endif
     18#include <DisplayUtils.h>
    2519
    26 #ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER
    27 # include <errno.h>
    28 # include <sys/types.h>
    29 # include <sys/stat.h>
    30 # include <sys/ipc.h>
    31 # include <sys/sem.h>
    32 #endif
     20#include <iprt/log.h>
     21#include <VBox/err.h>
     22#include <VBox/ssm.h>
    3323
    34 #include "Logging.h"
    35 #include "VirtualBoxImpl.h"
    36 #include "MachineImpl.h"
    37 #include "ProgressImpl.h"
    38 #include "ProgressProxyImpl.h"
    39 #include "MediumAttachmentImpl.h"
    40 #include "MediumImpl.h"
    41 #include "MediumLock.h"
    42 #include "USBControllerImpl.h"
    43 #include "HostImpl.h"
    44 #include "SharedFolderImpl.h"
    45 #include "GuestOSTypeImpl.h"
    46 #include "VirtualBoxErrorInfoImpl.h"
    47 #include "GuestImpl.h"
    48 #include "StorageControllerImpl.h"
    49 #include "DisplayImpl.h"
    50 
    51 #ifdef VBOX_WITH_USB
    52 # include "USBProxyService.h"
    53 #endif
    54 
    55 #include "AutoCaller.h"
    56 #include "Performance.h"
    57 
    58 #include <iprt/asm.h>
    59 #include <iprt/path.h>
    60 #include <iprt/dir.h>
    61 #include <iprt/env.h>
    62 #include <iprt/lockvalidator.h>
    63 #include <iprt/process.h>
    64 #include <iprt/cpp/utils.h>
    65 #include <iprt/cpp/xml.h>               /* xml::XmlFileWriter::s_psz*Suff. */
    66 #include <iprt/string.h>
    67 
    68 #include <VBox/com/array.h>
    69 
    70 #include <VBox/err.h>
    71 #include <VBox/param.h>
    72 #include <VBox/settings.h>
    73 #include <VBox/ssm.h>
    74 #include <VBox/feature.h>
    75 
    76 #ifdef VBOX_WITH_GUEST_PROPS
    77 # include <VBox/HostServices/GuestPropertySvc.h>
    78 # include <VBox/com/array.h>
    79 #endif
    80 
    81 #include "VBox/com/MultiResult.h"
    82 
    83 #include <algorithm>
    84 
    85 #include <typeinfo>
    86 
    87 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    88 # define HOSTSUFF_EXE ".exe"
    89 #else /* !RT_OS_WINDOWS */
    90 # define HOSTSUFF_EXE ""
    91 #endif /* !RT_OS_WINDOWS */
    92 
    93 // defines / prototypes
    94 /////////////////////////////////////////////////////////////////////////////
    95 
    96 /////////////////////////////////////////////////////////////////////////////
    97 // Machine::Data structure
    98 /////////////////////////////////////////////////////////////////////////////
    99 
    100 Machine::Data::Data()
    101 {
    102     mRegistered = FALSE;
    103     pMachineConfigFile = NULL;
    104     flModifications = 0;
    105     mAccessible = FALSE;
    106     /* mUuid is initialized in Machine::init() */
    107 
    108     mMachineState = MachineState_PoweredOff;
    109     RTTimeNow(&mLastStateChange);
    110 
    111     mMachineStateDeps = 0;
    112     mMachineStateDepsSem = NIL_RTSEMEVENTMULTI;
    113     mMachineStateChangePending = 0;
    114 
    115     mCurrentStateModified = TRUE;
    116     mGuestPropertiesModified = FALSE;
    117 
    118     mSession.mPid = NIL_RTPROCESS;
    119     mSession.mState = SessionState_Unlocked;
    120 }
    121 
    122 Machine::Data::~Data()
    123 {
    124     if (mMachineStateDepsSem != NIL_RTSEMEVENTMULTI)
    125     {
    126         RTSemEventMultiDestroy(mMachineStateDepsSem);
    127         mMachineStateDepsSem = NIL_RTSEMEVENTMULTI;
    128     }
    129     if (pMachineConfigFile)
    130     {
    131         delete pMachineConfigFile;
    132         pMachineConfigFile = NULL;
    133     }
    134 }
    135 
    136 /////////////////////////////////////////////////////////////////////////////
    137 // Machine::HWData structure
    138 /////////////////////////////////////////////////////////////////////////////
    139 
    140 Machine::HWData::HWData()
    141 {
    142     /* default values for a newly created machine */
    143     mHWVersion = "2"; /** @todo get the default from the schema if that is possible. */
    144     mMemorySize = 128;
    145     mCPUCount = 1;
    146     mCPUHotPlugEnabled = false;
    147     mMemoryBalloonSize = 0;
    148     mPageFusionEnabled = false;
    149     mVRAMSize = 8;
    150     mAccelerate3DEnabled = false;
    151     mAccelerate2DVideoEnabled = false;
    152     mMonitorCount = 1;
    153     mHWVirtExEnabled = true;
    154     mHWVirtExNestedPagingEnabled = true;
    155 #if HC_ARCH_BITS == 64
    156     /* Default value decision pending. */
    157     mHWVirtExLargePagesEnabled = false;
    158 #else
    159     /* Not supported on 32 bits hosts. */
    160     mHWVirtExLargePagesEnabled = false;
    161 #endif
    162     mHWVirtExVPIDEnabled = true;
    163     mHWVirtExForceEnabled = false;
    164 #if defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS)
    165     mHWVirtExExclusive = false;
    166 #else
    167     mHWVirtExExclusive = true;
    168 #endif
    169 #if HC_ARCH_BITS == 64 || defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
    170     mPAEEnabled = true;
    171 #else
    172     mPAEEnabled = false;
    173 #endif
    174     mSyntheticCpu = false;
    175     mHpetEnabled = false;
    176 
    177     /* default boot order: floppy - DVD - HDD */
    178     mBootOrder[0] = DeviceType_Floppy;
    179     mBootOrder[1] = DeviceType_DVD;
    180     mBootOrder[2] = DeviceType_HardDisk;
    181     for (size_t i = 3; i < RT_ELEMENTS(mBootOrder); ++i)
    182         mBootOrder[i] = DeviceType_Null;
    183 
    184     mClipboardMode = ClipboardMode_Bidirectional;
    185     mGuestPropertyNotificationPatterns = "";
    186 
    187     mFirmwareType = FirmwareType_BIOS;
    188     mKeyboardHidType = KeyboardHidType_PS2Keyboard;
    189     mPointingHidType = PointingHidType_PS2Mouse;
    190     mChipsetType = ChipsetType_PIIX3;
    191 
    192     for (size_t i = 0; i < RT_ELEMENTS(mCPUAttached); i++)
    193         mCPUAttached[i] = false;
    194 
    195     mIoCacheEnabled = true;
    196     mIoCacheSize    = 5; /* 5MB */
    197 
    198     /* Maximum CPU priority by default. */
    199     mCpuPriority = 100;
    200 }
    201 
    202 Machine::HWData::~HWData()
    203 {
    204 }
    205 
    206 /////////////////////////////////////////////////////////////////////////////
    207 // Machine::HDData structure
    208 /////////////////////////////////////////////////////////////////////////////
    209 
    210 Machine::MediaData::MediaData()
    211 {
    212 }
    213 
    214 Machine::MediaData::~MediaData()
    215 {
    216 }
    217 
    218 /////////////////////////////////////////////////////////////////////////////
    219 // Machine class
    220 /////////////////////////////////////////////////////////////////////////////
    221 
    222 // constructor / destructor
    223 /////////////////////////////////////////////////////////////////////////////
    224 
    225 Machine::Machine()
    226     : mGuestHAL(NULL),
    227       mPeer(NULL),
    228       mParent(NULL)
    229 {}
    230 
    231 Machine::~Machine()
    232 {}
    233 
    234 HRESULT Machine::FinalConstruct()
    235 {
    236     LogFlowThisFunc(("\n"));
    237     return S_OK;
    238 }
    239 
    240 void Machine::FinalRelease()
    241 {
    242     LogFlowThisFunc(("\n"));
    243     uninit();
    244 }
    245 
    246 /**
    247  *  Initializes a new machine instance; this init() variant creates a new, empty machine.
    248  *  This gets called from VirtualBox::CreateMachine() or VirtualBox::CreateLegacyMachine().
    249  *
    250  *  @param aParent      Associated parent object
    251  *  @param strConfigFile  Local file system path to the VM settings file (can
    252  *                      be relative to the VirtualBox config directory).
    253  *  @param strName      name for the machine
    254  *  @param aId          UUID for the new machine.
    255  *  @param aOsType      Optional OS Type of this machine.
    256  *  @param aOverride    |TRUE| to override VM config file existence checks.
    257  *                      |FALSE| refuses to overwrite existing VM configs.
    258  *  @param aNameSync    |TRUE| to automatically sync settings dir and file
    259  *                      name with the machine name. |FALSE| is used for legacy
    260  *                      machines where the file name is specified by the
    261  *                      user and should never change.
    262  *
    263  *  @return  Success indicator. if not S_OK, the machine object is invalid
    264  */
    265 HRESULT Machine::init(VirtualBox *aParent,
    266                       const Utf8Str &strConfigFile,
    267                       const Utf8Str &strName,
    268                       const Guid &aId,
    269                       GuestOSType *aOsType /* = NULL */,
    270                       BOOL aOverride /* = FALSE */,
    271                       BOOL aNameSync /* = TRUE */)
    272 {
    273     LogFlowThisFuncEnter();
    274     LogFlowThisFunc(("(Init_New) aConfigFile='%s'\n", strConfigFile.c_str()));
    275 
    276     /* Enclose the state transition NotReady->InInit->Ready */
    277     AutoInitSpan autoInitSpan(this);
    278     AssertReturn(autoInitSpan.isOk(), E_FAIL);
    279 
    280     HRESULT rc = initImpl(aParent, strConfigFile);
    281     if (FAILED(rc)) return rc;
    282 
    283     rc = tryCreateMachineConfigFile(aOverride);
    284     if (FAILED(rc)) return rc;
    285 
    286     if (SUCCEEDED(rc))
    287     {
    288         // create an empty machine config
    289         mData->pMachineConfigFile = new settings::MachineConfigFile(NULL);
    290 
    291         rc = initDataAndChildObjects();
    292     }
    293 
    294     if (SUCCEEDED(rc))
    295     {
    296         // set to true now to cause uninit() to call uninitDataAndChildObjects() on failure
    297         mData->mAccessible = TRUE;
    298 
    299         unconst(mData->mUuid) = aId;
    300 
    301         mUserData->s.strName = strName;
    302         mUserData->s.fNameSync = aNameSync;
    303 
    304         /* initialize the default snapshots folder
    305          * (note: depends on the name value set above!) */
    306         rc = COMSETTER(SnapshotFolder)(NULL);
    307         AssertComRC(rc);
    308 
    309         if (aOsType)
    310         {
    311             /* Store OS type */
    312             mUserData->s.strOsType = aOsType->id();
    313 
    314             /* Apply BIOS defaults */
    315             mBIOSSettings->applyDefaults(aOsType);
    316 
    317             /* Apply network adapters defaults */
    318             for (ULONG slot = 0; slot < RT_ELEMENTS(mNetworkAdapters); ++slot)
    319                 mNetworkAdapters[slot]->applyDefaults(aOsType);
    320 
    321             /* Apply serial port defaults */
    322             for (ULONG slot = 0; slot < RT_ELEMENTS(mSerialPorts); ++slot)
    323                 mSerialPorts[slot]->applyDefaults(aOsType);
    324         }
    325 
    326         /* commit all changes made during the initialization */
    327         commit();
    328     }
    329 
    330     /* Confirm a successful initialization when it's the case */
    331     if (SUCCEEDED(rc))
    332     {
    333         if (mData->mAccessible)
    334             autoInitSpan.setSucceeded();
    335         else
    336             autoInitSpan.setLimited();
    337     }
    338 
    339     LogFlowThisFunc(("mName='%s', mRegistered=%RTbool, mAccessible=%RTbool, rc=%08X\n",
    340                      !!mUserData ? mUserData->s.strName.c_str() : "NULL",
    341                      mData->mRegistered,
    342                      mData->mAccessible,
    343                      rc));
    344 
    345     LogFlowThisFuncLeave();
    346 
    347     return rc;
    348 }
    349 
    350 /**
    351  *  Initializes a new instance with data from machine XML (formerly Init_Registered).
    352  *  Gets called in two modes:
    353  *
    354  *      -- from VirtualBox::initMachines() during VirtualBox startup; in that case, the
    355  *         UUID is specified and we mark the machine as "registered";
    356  *
    357  *      -- from the public VirtualBox::OpenMachine() API, in which case the UUID is NULL
    358  *         and the machine remains unregistered until RegisterMachine() is called.
    359  *
    360  *  @param aParent      Associated parent object
    361  *  @param aConfigFile  Local file system path to the VM settings file (can
    362  *                      be relative to the VirtualBox config directory).
    363  *  @param aId          UUID of the machine or NULL (see above).
    364  *
    365  *  @return  Success indicator. if not S_OK, the machine object is invalid
    366  */
    367 HRESULT Machine::init(VirtualBox *aParent,
    368                       const Utf8Str &strConfigFile,
    369                       const Guid *aId)
    370 {
    371     LogFlowThisFuncEnter();
    372     LogFlowThisFunc(("(Init_Registered) aConfigFile='%s\n", strConfigFile.c_str()));
    373 
    374     /* Enclose the state transition NotReady->InInit->Ready */
    375     AutoInitSpan autoInitSpan(this);
    376     AssertReturn(autoInitSpan.isOk(), E_FAIL);
    377 
    378     HRESULT rc = initImpl(aParent, strConfigFile);
    379     if (FAILED(rc)) return rc;
    380 
    381     if (aId)
    382     {
    383         // loading a registered VM:
    384         unconst(mData->mUuid) = *aId;
    385         mData->mRegistered = TRUE;
    386         // now load the settings from XML:
    387         rc = registeredInit();
    388             // this calls initDataAndChildObjects() and loadSettings()
    389     }
    390     else
    391     {
    392         // opening an unregistered VM (VirtualBox::OpenMachine()):
    393         rc = initDataAndChildObjects();
    394 
    395         if (SUCCEEDED(rc))
    396         {
    397             // set to true now to cause uninit() to call uninitDataAndChildObjects() on failure
    398             mData->mAccessible = TRUE;
    399 
    400             try
    401             {
    402                 // load and parse machine XML; this will throw on XML or logic errors
    403                 mData->pMachineConfigFile = new settings::MachineConfigFile(&mData->m_strConfigFileFull);
    404 
    405                 // use UUID from machine config
    406                 unconst(mData->mUuid) = mData->pMachineConfigFile->uuid;
    407 
    408                 rc = loadMachineDataFromSettings(*mData->pMachineConfigFile);
    409                 if (FAILED(rc)) throw rc;
    410 
    411                 commit();
    412             }
    413             catch (HRESULT err)
    414             {
    415                 /* we assume that error info is set by the thrower */
    416                 rc = err;
    417             }
    418             catch (...)
    419             {
    420                 rc = VirtualBox::handleUnexpectedExceptions(RT_SRC_POS);
    421             }
    422         }
    423     }
    424 
    425     /* Confirm a successful initialization when it's the case */
    426     if (SUCCEEDED(rc))
    427     {
    428         if (mData->mAccessible)
    429             autoInitSpan.setSucceeded();
    430         else
    431         {
    432             autoInitSpan.setLimited();
    433 
    434             // uninit media from this machine's media registry, or else
    435             // reloading the settings will fail
    436             mParent->unregisterMachineMedia(getId());
    437         }
    438     }
    439 
    440     LogFlowThisFunc(("mName='%s', mRegistered=%RTbool, mAccessible=%RTbool "
    441                       "rc=%08X\n",
    442                       !!mUserData ? mUserData->s.strName.c_str() : "NULL",
    443                       mData->mRegistered, mData->mAccessible, rc));
    444 
    445     LogFlowThisFuncLeave();
    446 
    447     return rc;
    448 }
    449 
    450 /**
    451  *  Initializes a new instance from a machine config that is already in memory
    452  *  (import OVF case). Since we are importing, the UUID in the machine
    453  *  config is ignored and we always generate a fresh one.
    454  *
    455  *  @param strName  Name for the new machine; this overrides what is specified in config and is used
    456  *                  for the settings file as well.
    457  *  @param config   Machine configuration loaded and parsed from XML.
    458  *
    459  *  @return  Success indicator. if not S_OK, the machine object is invalid
    460  */
    461 HRESULT Machine::init(VirtualBox *aParent,
    462                       const Utf8Str &strName,
    463                       const settings::MachineConfigFile &config)
    464 {
    465     LogFlowThisFuncEnter();
    466 
    467     /* Enclose the state transition NotReady->InInit->Ready */
    468     AutoInitSpan autoInitSpan(this);
    469     AssertReturn(autoInitSpan.isOk(), E_FAIL);
    470 
    471     Utf8Str strConfigFile;
    472     aParent->getDefaultMachineFolder(strConfigFile);
    473     strConfigFile.append(RTPATH_DELIMITER);
    474     strConfigFile.append(strName);
    475     strConfigFile.append(RTPATH_DELIMITER);
    476     strConfigFile.append(strName);
    477     strConfigFile.append(".xml");
    478 
    479     HRESULT rc = initImpl(aParent, strConfigFile);
    480     if (FAILED(rc)) return rc;
    481 
    482     rc = tryCreateMachineConfigFile(FALSE /* aOverride */);
    483     if (FAILED(rc)) return rc;
    484 
    485     rc = initDataAndChildObjects();
    486 
    487     if (SUCCEEDED(rc))
    488     {
    489         // set to true now to cause uninit() to call uninitDataAndChildObjects() on failure
    490         mData->mAccessible = TRUE;
    491 
    492         // create empty machine config for instance data
    493         mData->pMachineConfigFile = new settings::MachineConfigFile(NULL);
    494 
    495         // generate fresh UUID, ignore machine config
    496         unconst(mData->mUuid).create();
    497 
    498         rc = loadMachineDataFromSettings(config);
    499 
    500         // override VM name as well, it may be different
    501         mUserData->s.strName = strName;
    502 
    503         /* commit all changes made during the initialization */
    504         if (SUCCEEDED(rc))
    505             commit();
    506     }
    507 
    508     /* Confirm a successful initialization when it's the case */
    509     if (SUCCEEDED(rc))
    510     {
    511         if (mData->mAccessible)
    512             autoInitSpan.setSucceeded();
    513         else
    514         {
    515             autoInitSpan.setLimited();
    516 
    517             // uninit media from this machine's media registry, or else
    518             // reloading the settings will fail
    519             mParent->unregisterMachineMedia(getId());
    520         }
    521     }
    522 
    523     LogFlowThisFunc(("mName='%s', mRegistered=%RTbool, mAccessible=%RTbool "
    524                      "rc=%08X\n",
    525                       !!mUserData ? mUserData->s.strName.c_str() : "NULL",
    526                       mData->mRegistered, mData->mAccessible, rc));
    527 
    528     LogFlowThisFuncLeave();
    529 
    530     return rc;
    531 }
    532 
    533 /**
    534  * Shared code between the various init() implementations.
    535  * @param aParent
    536  * @return
    537  */
    538 HRESULT Machine::initImpl(VirtualBox *aParent,
    539                           const Utf8Str &strConfigFile)
    540 {
    541     LogFlowThisFuncEnter();
    542 
    543     AssertReturn(aParent, E_INVALIDARG);
    544     AssertReturn(!strConfigFile.isEmpty(), E_INVALIDARG);
    545 
    546     HRESULT rc = S_OK;
    547 
    548     /* share the parent weakly */
    549     unconst(mParent) = aParent;
    550 
    551     /* allocate the essential machine data structure (the rest will be
    552      * allocated later by initDataAndChildObjects() */
    553     mData.allocate();
    554 
    555     /* memorize the config file name (as provided) */
    556     mData->m_strConfigFile = strConfigFile;
    557 
    558     /* get the full file name */
    559     int vrc1 = mParent->calculateFullPath(strConfigFile, mData->m_strConfigFileFull);
    560     if (RT_FAILURE(vrc1))
    561         return setError(VBOX_E_FILE_ERROR,
    562                         tr("Invalid machine settings file name '%s' (%Rrc)"),
    563                         strConfigFile.c_str(),
    564                         vrc1);
    565 
    566     LogFlowThisFuncLeave();
    567 
    568     return rc;
    569 }
    570 
    571 /**
    572  * Tries to create a machine settings file in the path stored in the machine
    573  * instance data. Used when a new machine is created to fail gracefully if
    574  * the settings file could not be written (e.g. because machine dir is read-only).
    575  * @return
    576  */
    577 HRESULT Machine::tryCreateMachineConfigFile(BOOL aOverride)
    578 {
    579     HRESULT rc = S_OK;
    580 
    581     // when we create a new machine, we must be able to create the settings file
    582     RTFILE f = NIL_RTFILE;
    583     int vrc = RTFileOpen(&f, mData->m_strConfigFileFull.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    584     if (    RT_SUCCESS(vrc)
    585          || vrc == VERR_SHARING_VIOLATION
    586        )
    587     {
    588         if (RT_SUCCESS(vrc))
    589             RTFileClose(f);
    590         if (!aOverride)
    591             rc = setError(VBOX_E_FILE_ERROR,
    592                           tr("Machine settings file '%s' already exists"),
    593                           mData->m_strConfigFileFull.c_str());
    594         else
    595         {
    596             /* try to delete the config file, as otherwise the creation
    597                 * of a new settings file will fail. */
    598             int vrc2 = RTFileDelete(mData->m_strConfigFileFull.c_str());
    599             if (RT_FAILURE(vrc2))
    600                 rc = setError(VBOX_E_FILE_ERROR,
    601                               tr("Could not delete the existing settings file '%s' (%Rrc)"),
    602                               mData->m_strConfigFileFull.c_str(), vrc2);
    603         }
    604     }
    605     else if (    vrc != VERR_FILE_NOT_FOUND
    606               && vrc != VERR_PATH_NOT_FOUND
    607             )
    608         rc = setError(VBOX_E_FILE_ERROR,
    609                       tr("Invalid machine settings file name '%s' (%Rrc)"),
    610                       mData->m_strConfigFileFull.c_str(),
    611                       vrc);
    612     return rc;
    613 }
    614 
    615 /**
    616  *  Initializes the registered machine by loading the settings file.
    617  *  This method is separated from #init() in order to make it possible to
    618  *  retry the operation after VirtualBox startup instead of refusing to
    619  *  startup the whole VirtualBox server in case if the settings file of some
    620  *  registered VM is invalid or inaccessible.
    621  *
    622  *  @note Must be always called from this object's write lock
    623  *        (unless called from #init() that doesn't need any locking).
    624  *  @note Locks the mUSBController method for writing.
    625  *  @note Subclasses must not call this method.
    626  */
    627 HRESULT Machine::registeredInit()
    628 {
    629     AssertReturn(!isSessionMachine(), E_FAIL);
    630     AssertReturn(!isSnapshotMachine(), E_FAIL);
    631     AssertReturn(!mData->mUuid.isEmpty(), E_FAIL);
    632     AssertReturn(!mData->mAccessible, E_FAIL);
    633 
    634     HRESULT rc = initDataAndChildObjects();
    635 
    636     if (SUCCEEDED(rc))
    637     {
    638         /* Temporarily reset the registered flag in order to let setters
    639          * potentially called from loadSettings() succeed (isMutable() used in
    640          * all setters will return FALSE for a Machine instance if mRegistered
    641          * is TRUE). */
    642         mData->mRegistered = FALSE;
    643 
    644         try
    645         {
    646             // load and parse machine XML; this will throw on XML or logic errors
    647             mData->pMachineConfigFile = new settings::MachineConfigFile(&mData->m_strConfigFileFull);
    648 
    649             if (mData->mUuid != mData->pMachineConfigFile->uuid)
    650                 throw setError(E_FAIL,
    651                                tr("Machine UUID {%RTuuid} in '%s' doesn't match its UUID {%s} in the registry file '%s'"),
    652                                mData->pMachineConfigFile->uuid.raw(),
    653                                mData->m_strConfigFileFull.c_str(),
    654                                mData->mUuid.toString().c_str(),
    655                                mParent->settingsFilePath().c_str());
    656 
    657             rc = loadMachineDataFromSettings(*mData->pMachineConfigFile);
    658             if (FAILED(rc)) throw rc;
    659         }
    660         catch (HRESULT err)
    661         {
    662             /* we assume that error info is set by the thrower */
    663             rc = err;
    664         }
    665         catch (...)
    666         {
    667             rc = VirtualBox::handleUnexpectedExceptions(RT_SRC_POS);
    668         }
    669 
    670         /* Restore the registered flag (even on failure) */
    671         mData->mRegistered = TRUE;
    672     }
    673 
    674     if (SUCCEEDED(rc))
    675     {
    676         /* Set mAccessible to TRUE only if we successfully locked and loaded
    677          * the settings file */
    678         mData->mAccessible = TRUE;
    679 
    680         /* commit all changes made during loading the settings file */
    681         commit(); // @todo r=dj why do we need a commit during init?!? this is very expensive
    682     }
    683     else
    684     {
    685         /* If the machine is registered, then, instead of returning a
    686          * failure, we mark it as inaccessible and set the result to
    687          * success to give it a try later */
    688 
    689         /* fetch the current error info */
    690         mData->mAccessError = com::ErrorInfo();
    691         LogWarning(("Machine {%RTuuid} is inaccessible! [%ls]\n",
    692                     mData->mUuid.raw(),
    693                     mData->mAccessError.getText().raw()));
    694 
    695         /* rollback all changes */
    696         rollback(false /* aNotify */);
    697 
    698         // uninit media from this machine's media registry, or else
    699         // reloading the settings will fail
    700         mParent->unregisterMachineMedia(getId());
    701 
    702         /* uninitialize the common part to make sure all data is reset to
    703          * default (null) values */
    704         uninitDataAndChildObjects();
    705 
    706         rc = S_OK;
    707     }
    708 
    709     return rc;
    710 }
    711 
    712 /**
    713  *  Uninitializes the instance.
    714  *  Called either from FinalRelease() or by the parent when it gets destroyed.
    715  *
    716  *  @note The caller of this method must make sure that this object
    717  *  a) doesn't have active callers on the current thread and b) is not locked
    718  *  by the current thread; otherwise uninit() will hang either a) due to
    719  *  AutoUninitSpan waiting for a number of calls to drop to zero or b) due to
    720  *  a dead-lock caused by this thread waiting for all callers on the other
    721  *  threads are done but preventing them from doing so by holding a lock.
    722  */
    723 void Machine::uninit()
    724 {
    725     LogFlowThisFuncEnter();
    726 
    727     Assert(!isWriteLockOnCurrentThread());
    728 
    729     /* Enclose the state transition Ready->InUninit->NotReady */
    730     AutoUninitSpan autoUninitSpan(this);
    731     if (autoUninitSpan.uninitDone())
    732         return;
    733 
    734     Assert(!isSnapshotMachine());
    735     Assert(!isSessionMachine());
    736     Assert(!!mData);
    737 
    738     LogFlowThisFunc(("initFailed()=%d\n", autoUninitSpan.initFailed()));
    739     LogFlowThisFunc(("mRegistered=%d\n", mData->mRegistered));
    740 
    741     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    742 
    743     if (!mData->mSession.mMachine.isNull())
    744     {
    745         /* Theoretically, this can only happen if the VirtualBox server has been
    746          * terminated while there were clients running that owned open direct
    747          * sessions. Since in this case we are definitely called by
    748          * VirtualBox::uninit(), we may be sure that SessionMachine::uninit()
    749          * won't happen on the client watcher thread (because it does
    750          * VirtualBox::addCaller() for the duration of the
    751          * SessionMachine::checkForDeath() call, so that VirtualBox::uninit()
    752          * cannot happen until the VirtualBox caller is released). This is
    753          * important, because SessionMachine::uninit() cannot correctly operate
    754          * after we return from this method (it expects the Machine instance is
    755          * still valid). We'll call it ourselves below.
    756          */
    757         LogWarningThisFunc(("Session machine is not NULL (%p), the direct session is still open!\n",
    758                             (SessionMachine*)mData->mSession.mMachine));
    759 
    760         if (Global::IsOnlineOrTransient(mData->mMachineState))
    761         {
    762             LogWarningThisFunc(("Setting state to Aborted!\n"));
    763             /* set machine state using SessionMachine reimplementation */
    764             static_cast<Machine*>(mData->mSession.mMachine)->setMachineState(MachineState_Aborted);
    765         }
    766 
    767         /*
    768          *  Uninitialize SessionMachine using public uninit() to indicate
    769          *  an unexpected uninitialization.
    770          */
    771         mData->mSession.mMachine->uninit();
    772         /* SessionMachine::uninit() must set mSession.mMachine to null */
    773         Assert(mData->mSession.mMachine.isNull());
    774     }
    775 
    776     // uninit media from this machine's media registry, if they're still there
    777     mParent->unregisterMachineMedia(getId());
    778 
    779     /* the lock is no more necessary (SessionMachine is uninitialized) */
    780     alock.leave();
    781 
    782     // has machine been modified?
    783     if (mData->flModifications)
    784     {
    785         LogWarningThisFunc(("Discarding unsaved settings changes!\n"));
    786         rollback(false /* aNotify */);
    787     }
    788 
    789     if (mData->mAccessible)
    790         uninitDataAndChildObjects();
    791 
    792     /* free the essential data structure last */
    793     mData.free();
    794 
    795     LogFlowThisFuncLeave();
    796 }
    797 
    798 // IMachine properties
    799 /////////////////////////////////////////////////////////////////////////////
    800 
    801 STDMETHODIMP Machine::COMGETTER(Parent)(IVirtualBox **aParent)
    802 {
    803     CheckComArgOutPointerValid(aParent);
    804 
    805     AutoLimitedCaller autoCaller(this);
    806     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    807 
    808     /* mParent is constant during life time, no need to lock */
    809     ComObjPtr<VirtualBox> pVirtualBox(mParent);
    810     pVirtualBox.queryInterfaceTo(aParent);
    811 
    812     return S_OK;
    813 }
    814 
    815 STDMETHODIMP Machine::COMGETTER(Accessible)(BOOL *aAccessible)
    816 {
    817     CheckComArgOutPointerValid(aAccessible);
    818 
    819     AutoLimitedCaller autoCaller(this);
    820     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    821 
    822     LogFlowThisFunc(("ENTER\n"));
    823 
    824     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    825 
    826     HRESULT rc = S_OK;
    827 
    828     if (!mData->mAccessible)
    829     {
    830         /* try to initialize the VM once more if not accessible */
    831 
    832         AutoReinitSpan autoReinitSpan(this);
    833         AssertReturn(autoReinitSpan.isOk(), E_FAIL);
    834 
    835 #ifdef DEBUG
    836         LogFlowThisFunc(("Dumping media backreferences\n"));
    837         mParent->dumpAllBackRefs();
    838 #endif
    839 
    840         if (mData->pMachineConfigFile)
    841         {
    842             // reset the XML file to force loadSettings() (called from registeredInit())
    843             // to parse it again; the file might have changed
    844             delete mData->pMachineConfigFile;
    845             mData->pMachineConfigFile = NULL;
    846         }
    847 
    848         rc = registeredInit();
    849 
    850         if (SUCCEEDED(rc) && mData->mAccessible)
    851         {
    852             autoReinitSpan.setSucceeded();
    853 
    854             /* make sure interesting parties will notice the accessibility
    855              * state change */
    856             mParent->onMachineStateChange(mData->mUuid, mData->mMachineState);
    857             mParent->onMachineDataChange(mData->mUuid);
    858         }
    859     }
    860 
    861     if (SUCCEEDED(rc))
    862         *aAccessible = mData->mAccessible;
    863 
    864     LogFlowThisFuncLeave();
    865 
    866     return rc;
    867 }
    868 
    869 STDMETHODIMP Machine::COMGETTER(AccessError)(IVirtualBoxErrorInfo **aAccessError)
    870 {
    871     CheckComArgOutPointerValid(aAccessError);
    872 
    873     AutoLimitedCaller autoCaller(this);
    874     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    875 
    876     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    877 
    878     if (mData->mAccessible || !mData->mAccessError.isBasicAvailable())
    879     {
    880         /* return shortly */
    881         aAccessError = NULL;
    882         return S_OK;
    883     }
    884 
    885     HRESULT rc = S_OK;
    886 
    887     ComObjPtr<VirtualBoxErrorInfo> errorInfo;
    888     rc = errorInfo.createObject();
    889     if (SUCCEEDED(rc))
    890     {
    891         errorInfo->init(mData->mAccessError.getResultCode(),
    892                         mData->mAccessError.getInterfaceID(),
    893                         Utf8Str(mData->mAccessError.getComponent()).c_str(),
    894                         Utf8Str(mData->mAccessError.getText()));
    895         rc = errorInfo.queryInterfaceTo(aAccessError);
    896     }
    897 
    898     return rc;
    899 }
    900 
    901 STDMETHODIMP Machine::COMGETTER(Name)(BSTR *aName)
    902 {
    903     CheckComArgOutPointerValid(aName);
    904 
    905     AutoCaller autoCaller(this);
    906     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    907 
    908     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    909 
    910     mUserData->s.strName.cloneTo(aName);
    911 
    912     return S_OK;
    913 }
    914 
    915 STDMETHODIMP Machine::COMSETTER(Name)(IN_BSTR aName)
    916 {
    917     CheckComArgStrNotEmptyOrNull(aName);
    918 
    919     AutoCaller autoCaller(this);
    920     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    921 
    922     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    923 
    924     HRESULT rc = checkStateDependency(MutableStateDep);
    925     if (FAILED(rc)) return rc;
    926 
    927     setModified(IsModified_MachineData);
    928     mUserData.backup();
    929     mUserData->s.strName = aName;
    930 
    931     return S_OK;
    932 }
    933 
    934 STDMETHODIMP Machine::COMGETTER(Description)(BSTR *aDescription)
    935 {
    936     CheckComArgOutPointerValid(aDescription);
    937 
    938     AutoCaller autoCaller(this);
    939     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    940 
    941     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    942 
    943     mUserData->s.strDescription.cloneTo(aDescription);
    944 
    945     return S_OK;
    946 }
    947 
    948 STDMETHODIMP Machine::COMSETTER(Description)(IN_BSTR aDescription)
    949 {
    950     AutoCaller autoCaller(this);
    951     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    952 
    953     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    954 
    955     HRESULT rc = checkStateDependency(MutableStateDep);
    956     if (FAILED(rc)) return rc;
    957 
    958     setModified(IsModified_MachineData);
    959     mUserData.backup();
    960     mUserData->s.strDescription = aDescription;
    961 
    962     return S_OK;
    963 }
    964 
    965 STDMETHODIMP Machine::COMGETTER(Id)(BSTR *aId)
    966 {
    967     CheckComArgOutPointerValid(aId);
    968 
    969     AutoLimitedCaller autoCaller(this);
    970     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    971 
    972     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    973 
    974     mData->mUuid.toUtf16().cloneTo(aId);
    975 
    976     return S_OK;
    977 }
    978 
    979 STDMETHODIMP Machine::COMGETTER(OSTypeId)(BSTR *aOSTypeId)
    980 {
    981     CheckComArgOutPointerValid(aOSTypeId);
    982 
    983     AutoCaller autoCaller(this);
    984     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    985 
    986     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    987 
    988     mUserData->s.strOsType.cloneTo(aOSTypeId);
    989 
    990     return S_OK;
    991 }
    992 
    993 STDMETHODIMP Machine::COMSETTER(OSTypeId)(IN_BSTR aOSTypeId)
    994 {
    995     CheckComArgStrNotEmptyOrNull(aOSTypeId);
    996 
    997     AutoCaller autoCaller(this);
    998     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    999 
    1000     /* look up the object by Id to check it is valid */
    1001     ComPtr<IGuestOSType> guestOSType;
    1002     HRESULT rc = mParent->GetGuestOSType(aOSTypeId, guestOSType.asOutParam());
    1003     if (FAILED(rc)) return rc;
    1004 
    1005     /* when setting, always use the "etalon" value for consistency -- lookup
    1006      * by ID is case-insensitive and the input value may have different case */
    1007     Bstr osTypeId;
    1008     rc = guestOSType->COMGETTER(Id)(osTypeId.asOutParam());
    1009     if (FAILED(rc)) return rc;
    1010 
    1011     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1012 
    1013     rc = checkStateDependency(MutableStateDep);
    1014     if (FAILED(rc)) return rc;
    1015 
    1016     setModified(IsModified_MachineData);
    1017     mUserData.backup();
    1018     mUserData->s.strOsType = osTypeId;
    1019 
    1020     return S_OK;
    1021 }
    1022 
    1023 
    1024 STDMETHODIMP Machine::COMGETTER(FirmwareType)(FirmwareType_T *aFirmwareType)
    1025 {
    1026     CheckComArgOutPointerValid(aFirmwareType);
    1027 
    1028     AutoCaller autoCaller(this);
    1029     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1030 
    1031     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1032 
    1033     *aFirmwareType = mHWData->mFirmwareType;
    1034 
    1035     return S_OK;
    1036 }
    1037 
    1038 STDMETHODIMP Machine::COMSETTER(FirmwareType)(FirmwareType_T aFirmwareType)
    1039 {
    1040     AutoCaller autoCaller(this);
    1041     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1042     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1043 
    1044     int rc = checkStateDependency(MutableStateDep);
    1045     if (FAILED(rc)) return rc;
    1046 
    1047     setModified(IsModified_MachineData);
    1048     mHWData.backup();
    1049     mHWData->mFirmwareType = aFirmwareType;
    1050 
    1051     return S_OK;
    1052 }
    1053 
    1054 STDMETHODIMP Machine::COMGETTER(KeyboardHidType)(KeyboardHidType_T *aKeyboardHidType)
    1055 {
    1056     CheckComArgOutPointerValid(aKeyboardHidType);
    1057 
    1058     AutoCaller autoCaller(this);
    1059     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1060 
    1061     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1062 
    1063     *aKeyboardHidType = mHWData->mKeyboardHidType;
    1064 
    1065     return S_OK;
    1066 }
    1067 
    1068 STDMETHODIMP Machine::COMSETTER(KeyboardHidType)(KeyboardHidType_T  aKeyboardHidType)
    1069 {
    1070     AutoCaller autoCaller(this);
    1071     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1072     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1073 
    1074     int rc = checkStateDependency(MutableStateDep);
    1075     if (FAILED(rc)) return rc;
    1076 
    1077     setModified(IsModified_MachineData);
    1078     mHWData.backup();
    1079     mHWData->mKeyboardHidType = aKeyboardHidType;
    1080 
    1081     return S_OK;
    1082 }
    1083 
    1084 STDMETHODIMP Machine::COMGETTER(PointingHidType)(PointingHidType_T *aPointingHidType)
    1085 {
    1086     CheckComArgOutPointerValid(aPointingHidType);
    1087 
    1088     AutoCaller autoCaller(this);
    1089     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1090 
    1091     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1092 
    1093     *aPointingHidType = mHWData->mPointingHidType;
    1094 
    1095     return S_OK;
    1096 }
    1097 
    1098 STDMETHODIMP Machine::COMSETTER(PointingHidType)(PointingHidType_T  aPointingHidType)
    1099 {
    1100     AutoCaller autoCaller(this);
    1101     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1102     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1103 
    1104     int rc = checkStateDependency(MutableStateDep);
    1105     if (FAILED(rc)) return rc;
    1106 
    1107     setModified(IsModified_MachineData);
    1108     mHWData.backup();
    1109     mHWData->mPointingHidType = aPointingHidType;
    1110 
    1111     return S_OK;
    1112 }
    1113 
    1114 STDMETHODIMP Machine::COMGETTER(ChipsetType)(ChipsetType_T *aChipsetType)
    1115 {
    1116     CheckComArgOutPointerValid(aChipsetType);
    1117 
    1118     AutoCaller autoCaller(this);
    1119     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1120 
    1121     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1122 
    1123     *aChipsetType = mHWData->mChipsetType;
    1124 
    1125     return S_OK;
    1126 }
    1127 
    1128 STDMETHODIMP Machine::COMSETTER(ChipsetType)(ChipsetType_T aChipsetType)
    1129 {
    1130     AutoCaller autoCaller(this);
    1131     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1132     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1133 
    1134     int rc = checkStateDependency(MutableStateDep);
    1135     if (FAILED(rc)) return rc;
    1136 
    1137     setModified(IsModified_MachineData);
    1138     mHWData.backup();
    1139     mHWData->mChipsetType = aChipsetType;
    1140 
    1141     return S_OK;
    1142 }
    1143 
    1144 STDMETHODIMP Machine::COMGETTER(HardwareVersion)(BSTR *aHWVersion)
    1145 {
    1146     if (!aHWVersion)
    1147         return E_POINTER;
    1148 
    1149     AutoCaller autoCaller(this);
    1150     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1151 
    1152     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1153 
    1154     mHWData->mHWVersion.cloneTo(aHWVersion);
    1155 
    1156     return S_OK;
    1157 }
    1158 
    1159 STDMETHODIMP Machine::COMSETTER(HardwareVersion)(IN_BSTR aHWVersion)
    1160 {
    1161     /* check known version */
    1162     Utf8Str hwVersion = aHWVersion;
    1163     if (    hwVersion.compare("1") != 0
    1164         &&  hwVersion.compare("2") != 0)
    1165         return setError(E_INVALIDARG,
    1166                         tr("Invalid hardware version: %ls\n"), aHWVersion);
    1167 
    1168     AutoCaller autoCaller(this);
    1169     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1170 
    1171     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1172 
    1173     HRESULT rc = checkStateDependency(MutableStateDep);
    1174     if (FAILED(rc)) return rc;
    1175 
    1176     setModified(IsModified_MachineData);
    1177     mHWData.backup();
    1178     mHWData->mHWVersion = hwVersion;
    1179 
    1180     return S_OK;
    1181 }
    1182 
    1183 STDMETHODIMP Machine::COMGETTER(HardwareUUID)(BSTR *aUUID)
    1184 {
    1185     CheckComArgOutPointerValid(aUUID);
    1186 
    1187     AutoCaller autoCaller(this);
    1188     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1189 
    1190     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1191 
    1192     if (!mHWData->mHardwareUUID.isEmpty())
    1193         mHWData->mHardwareUUID.toUtf16().cloneTo(aUUID);
    1194     else
    1195         mData->mUuid.toUtf16().cloneTo(aUUID);
    1196 
    1197     return S_OK;
    1198 }
    1199 
    1200 STDMETHODIMP Machine::COMSETTER(HardwareUUID)(IN_BSTR aUUID)
    1201 {
    1202     Guid hardwareUUID(aUUID);
    1203     if (hardwareUUID.isEmpty())
    1204         return E_INVALIDARG;
    1205 
    1206     AutoCaller autoCaller(this);
    1207     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1208 
    1209     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1210 
    1211     HRESULT rc = checkStateDependency(MutableStateDep);
    1212     if (FAILED(rc)) return rc;
    1213 
    1214     setModified(IsModified_MachineData);
    1215     mHWData.backup();
    1216     if (hardwareUUID == mData->mUuid)
    1217         mHWData->mHardwareUUID.clear();
    1218     else
    1219         mHWData->mHardwareUUID = hardwareUUID;
    1220 
    1221     return S_OK;
    1222 }
    1223 
    1224 STDMETHODIMP Machine::COMGETTER(MemorySize)(ULONG *memorySize)
    1225 {
    1226     if (!memorySize)
    1227         return E_POINTER;
    1228 
    1229     AutoCaller autoCaller(this);
    1230     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1231 
    1232     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1233 
    1234     *memorySize = mHWData->mMemorySize;
    1235 
    1236     return S_OK;
    1237 }
    1238 
    1239 STDMETHODIMP Machine::COMSETTER(MemorySize)(ULONG memorySize)
    1240 {
    1241     /* check RAM limits */
    1242     if (    memorySize < MM_RAM_MIN_IN_MB
    1243          || memorySize > MM_RAM_MAX_IN_MB
    1244        )
    1245         return setError(E_INVALIDARG,
    1246                         tr("Invalid RAM size: %lu MB (must be in range [%lu, %lu] MB)"),
    1247                         memorySize, MM_RAM_MIN_IN_MB, MM_RAM_MAX_IN_MB);
    1248 
    1249     AutoCaller autoCaller(this);
    1250     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1251 
    1252     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1253 
    1254     HRESULT rc = checkStateDependency(MutableStateDep);
    1255     if (FAILED(rc)) return rc;
    1256 
    1257     setModified(IsModified_MachineData);
    1258     mHWData.backup();
    1259     mHWData->mMemorySize = memorySize;
    1260 
    1261     return S_OK;
    1262 }
    1263 
    1264 STDMETHODIMP Machine::COMGETTER(CPUCount)(ULONG *CPUCount)
    1265 {
    1266     if (!CPUCount)
    1267         return E_POINTER;
    1268 
    1269     AutoCaller autoCaller(this);
    1270     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1271 
    1272     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1273 
    1274     *CPUCount = mHWData->mCPUCount;
    1275 
    1276     return S_OK;
    1277 }
    1278 
    1279 STDMETHODIMP Machine::COMSETTER(CPUCount)(ULONG CPUCount)
    1280 {
    1281     /* check CPU limits */
    1282     if (    CPUCount < SchemaDefs::MinCPUCount
    1283          || CPUCount > SchemaDefs::MaxCPUCount
    1284        )
    1285         return setError(E_INVALIDARG,
    1286                         tr("Invalid virtual CPU count: %lu (must be in range [%lu, %lu])"),
    1287                         CPUCount, SchemaDefs::MinCPUCount, SchemaDefs::MaxCPUCount);
    1288 
    1289     AutoCaller autoCaller(this);
    1290     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1291 
    1292     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1293 
    1294     /* We cant go below the current number of CPUs if hotplug is enabled*/
    1295     if (mHWData->mCPUHotPlugEnabled)
    1296     {
    1297         for (unsigned idx = CPUCount; idx < SchemaDefs::MaxCPUCount; idx++)
    1298         {
    1299             if (mHWData->mCPUAttached[idx])
    1300                 return setError(E_INVALIDARG,
    1301                                 tr(": %lu (must be higher than or equal to %lu)"),
    1302                                 CPUCount, idx+1);
    1303         }
    1304     }
    1305 
    1306     HRESULT rc = checkStateDependency(MutableStateDep);
    1307     if (FAILED(rc)) return rc;
    1308 
    1309     setModified(IsModified_MachineData);
    1310     mHWData.backup();
    1311     mHWData->mCPUCount = CPUCount;
    1312 
    1313     return S_OK;
    1314 }
    1315 
    1316 STDMETHODIMP Machine::COMGETTER(CPUPriority)(ULONG *aPriority)
    1317 {
    1318     if (!aPriority)
    1319         return E_POINTER;
    1320 
    1321     AutoCaller autoCaller(this);
    1322     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1323 
    1324     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1325 
    1326     *aPriority = mHWData->mCpuPriority;
    1327 
    1328     return S_OK;
    1329 }
    1330 
    1331 STDMETHODIMP Machine::COMSETTER(CPUPriority)(ULONG aPriority)
    1332 {
    1333     HRESULT rc = S_OK;
    1334 
    1335     /* check priority limits */
    1336     if (    aPriority < 1
    1337          || aPriority > 100
    1338        )
    1339         return setError(E_INVALIDARG,
    1340                         tr("Invalid CPU priority: %lu (must be in range [%lu, %lu])"),
    1341                         aPriority, 1, 100);
    1342 
    1343     AutoCaller autoCaller(this);
    1344     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1345 
    1346     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1347 
    1348     alock.release();
    1349     rc = onCPUPriorityChange(aPriority);
    1350     alock.acquire();
    1351     if (FAILED(rc)) return rc;
    1352 
    1353     setModified(IsModified_MachineData);
    1354     mHWData.backup();
    1355     mHWData->mCpuPriority = aPriority;
    1356 
    1357     /* Save settings if online - todo why is this required?? */
    1358     if (Global::IsOnline(mData->mMachineState))
    1359         saveSettings(NULL);
    1360 
    1361     return S_OK;
    1362 }
    1363 
    1364 
    1365 STDMETHODIMP Machine::COMGETTER(CPUHotPlugEnabled)(BOOL *enabled)
    1366 {
    1367     if (!enabled)
    1368         return E_POINTER;
    1369 
    1370     AutoCaller autoCaller(this);
    1371     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1372 
    1373     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1374 
    1375     *enabled = mHWData->mCPUHotPlugEnabled;
    1376 
    1377     return S_OK;
    1378 }
    1379 
    1380 STDMETHODIMP Machine::COMSETTER(CPUHotPlugEnabled)(BOOL enabled)
    1381 {
    1382     HRESULT rc = S_OK;
    1383 
    1384     AutoCaller autoCaller(this);
    1385     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1386 
    1387     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1388 
    1389     rc = checkStateDependency(MutableStateDep);
    1390     if (FAILED(rc)) return rc;
    1391 
    1392     if (mHWData->mCPUHotPlugEnabled != enabled)
    1393     {
    1394         if (enabled)
    1395         {
    1396             setModified(IsModified_MachineData);
    1397             mHWData.backup();
    1398 
    1399             /* Add the amount of CPUs currently attached */
    1400             for (unsigned i = 0; i < mHWData->mCPUCount; i++)
    1401             {
    1402                 mHWData->mCPUAttached[i] = true;
    1403             }
    1404         }
    1405         else
    1406         {
    1407             /*
    1408              * We can disable hotplug only if the amount of maximum CPUs is equal
    1409              * to the amount of attached CPUs
    1410              */
    1411             unsigned cCpusAttached = 0;
    1412             unsigned iHighestId = 0;
    1413 
    1414             for (unsigned i = 0; i < SchemaDefs::MaxCPUCount; i++)
    1415             {
    1416                 if (mHWData->mCPUAttached[i])
    1417                 {
    1418                     cCpusAttached++;
    1419                     iHighestId = i;
    1420                 }
    1421             }
    1422 
    1423             if (   (cCpusAttached != mHWData->mCPUCount)
    1424                 || (iHighestId >= mHWData->mCPUCount))
    1425                 return setError(E_INVALIDARG,
    1426                                 tr("CPU hotplugging can't be disabled because the maximum number of CPUs is not equal to the amount of CPUs attached\n"));
    1427 
    1428             setModified(IsModified_MachineData);
    1429             mHWData.backup();
    1430         }
    1431     }
    1432 
    1433     mHWData->mCPUHotPlugEnabled = enabled;
    1434 
    1435     return rc;
    1436 }
    1437 
    1438 STDMETHODIMP Machine::COMGETTER(HpetEnabled)(BOOL *enabled)
    1439 {
    1440     CheckComArgOutPointerValid(enabled);
    1441 
    1442     AutoCaller autoCaller(this);
    1443     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1444     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1445 
    1446     *enabled = mHWData->mHpetEnabled;
    1447 
    1448     return S_OK;
    1449 }
    1450 
    1451 STDMETHODIMP Machine::COMSETTER(HpetEnabled)(BOOL enabled)
    1452 {
    1453     HRESULT rc = S_OK;
    1454 
    1455     AutoCaller autoCaller(this);
    1456     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1457     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1458 
    1459     rc = checkStateDependency(MutableStateDep);
    1460     if (FAILED(rc)) return rc;
    1461 
    1462     setModified(IsModified_MachineData);
    1463     mHWData.backup();
    1464 
    1465     mHWData->mHpetEnabled = enabled;
    1466 
    1467     return rc;
    1468 }
    1469 
    1470 STDMETHODIMP Machine::COMGETTER(VRAMSize)(ULONG *memorySize)
    1471 {
    1472     if (!memorySize)
    1473         return E_POINTER;
    1474 
    1475     AutoCaller autoCaller(this);
    1476     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1477 
    1478     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1479 
    1480     *memorySize = mHWData->mVRAMSize;
    1481 
    1482     return S_OK;
    1483 }
    1484 
    1485 STDMETHODIMP Machine::COMSETTER(VRAMSize)(ULONG memorySize)
    1486 {
    1487     /* check VRAM limits */
    1488     if (memorySize < SchemaDefs::MinGuestVRAM ||
    1489         memorySize > SchemaDefs::MaxGuestVRAM)
    1490         return setError(E_INVALIDARG,
    1491                         tr("Invalid VRAM size: %lu MB (must be in range [%lu, %lu] MB)"),
    1492                         memorySize, SchemaDefs::MinGuestVRAM, SchemaDefs::MaxGuestVRAM);
    1493 
    1494     AutoCaller autoCaller(this);
    1495     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1496 
    1497     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1498 
    1499     HRESULT rc = checkStateDependency(MutableStateDep);
    1500     if (FAILED(rc)) return rc;
    1501 
    1502     setModified(IsModified_MachineData);
    1503     mHWData.backup();
    1504     mHWData->mVRAMSize = memorySize;
    1505 
    1506     return S_OK;
    1507 }
    1508 
    1509 /** @todo this method should not be public */
    1510 STDMETHODIMP Machine::COMGETTER(MemoryBalloonSize)(ULONG *memoryBalloonSize)
    1511 {
    1512     if (!memoryBalloonSize)
    1513         return E_POINTER;
    1514 
    1515     AutoCaller autoCaller(this);
    1516     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1517 
    1518     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1519 
    1520     *memoryBalloonSize = mHWData->mMemoryBalloonSize;
    1521 
    1522     return S_OK;
    1523 }
    1524 
    1525 /**
    1526  * Set the memory balloon size.
    1527  *
    1528  * This method is also called from IGuest::COMSETTER(MemoryBalloonSize) so
    1529  * we have to make sure that we never call IGuest from here.
    1530  */
    1531 STDMETHODIMP Machine::COMSETTER(MemoryBalloonSize)(ULONG memoryBalloonSize)
    1532 {
    1533     /* This must match GMMR0Init; currently we only support memory ballooning on all 64-bit hosts except Mac OS X */
    1534 #if HC_ARCH_BITS == 64 && (defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD))
    1535     /* check limits */
    1536     if (memoryBalloonSize >= VMMDEV_MAX_MEMORY_BALLOON(mHWData->mMemorySize))
    1537         return setError(E_INVALIDARG,
    1538                         tr("Invalid memory balloon size: %lu MB (must be in range [%lu, %lu] MB)"),
    1539                         memoryBalloonSize, 0, VMMDEV_MAX_MEMORY_BALLOON(mHWData->mMemorySize));
    1540 
    1541     AutoCaller autoCaller(this);
    1542     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1543 
    1544     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1545 
    1546     setModified(IsModified_MachineData);
    1547     mHWData.backup();
    1548     mHWData->mMemoryBalloonSize = memoryBalloonSize;
    1549 
    1550     return S_OK;
    1551 #else
    1552     NOREF(memoryBalloonSize);
    1553     return setError(E_NOTIMPL, tr("Memory ballooning is only supported on 64-bit hosts"));
    1554 #endif
    1555 }
    1556 
    1557 STDMETHODIMP Machine::COMGETTER(PageFusionEnabled) (BOOL *enabled)
    1558 {
    1559     if (!enabled)
    1560         return E_POINTER;
    1561 
    1562     AutoCaller autoCaller(this);
    1563     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1564 
    1565     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1566 
    1567     *enabled = mHWData->mPageFusionEnabled;
    1568     return S_OK;
    1569 }
    1570 
    1571 STDMETHODIMP Machine::COMSETTER(PageFusionEnabled) (BOOL enabled)
    1572 {
    1573 #ifdef VBOX_WITH_PAGE_SHARING
    1574     AutoCaller autoCaller(this);
    1575     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1576 
    1577     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1578 
    1579     /** @todo must support changes for running vms and keep this in sync with IGuest. */
    1580     setModified(IsModified_MachineData);
    1581     mHWData.backup();
    1582     mHWData->mPageFusionEnabled = enabled;
    1583     return S_OK;
    1584 #else
    1585     NOREF(enabled);
    1586     return setError(E_NOTIMPL, tr("Page fusion is only supported on 64-bit hosts"));
    1587 #endif
    1588 }
    1589 
    1590 STDMETHODIMP Machine::COMGETTER(Accelerate3DEnabled)(BOOL *enabled)
    1591 {
    1592     if (!enabled)
    1593         return E_POINTER;
    1594 
    1595     AutoCaller autoCaller(this);
    1596     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1597 
    1598     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1599 
    1600     *enabled = mHWData->mAccelerate3DEnabled;
    1601 
    1602     return S_OK;
    1603 }
    1604 
    1605 STDMETHODIMP Machine::COMSETTER(Accelerate3DEnabled)(BOOL enable)
    1606 {
    1607     AutoCaller autoCaller(this);
    1608     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1609 
    1610     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1611 
    1612     HRESULT rc = checkStateDependency(MutableStateDep);
    1613     if (FAILED(rc)) return rc;
    1614 
    1615     /** @todo check validity! */
    1616 
    1617     setModified(IsModified_MachineData);
    1618     mHWData.backup();
    1619     mHWData->mAccelerate3DEnabled = enable;
    1620 
    1621     return S_OK;
    1622 }
    1623 
    1624 
    1625 STDMETHODIMP Machine::COMGETTER(Accelerate2DVideoEnabled)(BOOL *enabled)
    1626 {
    1627     if (!enabled)
    1628         return E_POINTER;
    1629 
    1630     AutoCaller autoCaller(this);
    1631     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1632 
    1633     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1634 
    1635     *enabled = mHWData->mAccelerate2DVideoEnabled;
    1636 
    1637     return S_OK;
    1638 }
    1639 
    1640 STDMETHODIMP Machine::COMSETTER(Accelerate2DVideoEnabled)(BOOL enable)
    1641 {
    1642     AutoCaller autoCaller(this);
    1643     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1644 
    1645     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1646 
    1647     HRESULT rc = checkStateDependency(MutableStateDep);
    1648     if (FAILED(rc)) return rc;
    1649 
    1650     /** @todo check validity! */
    1651 
    1652     setModified(IsModified_MachineData);
    1653     mHWData.backup();
    1654     mHWData->mAccelerate2DVideoEnabled = enable;
    1655 
    1656     return S_OK;
    1657 }
    1658 
    1659 STDMETHODIMP Machine::COMGETTER(MonitorCount)(ULONG *monitorCount)
    1660 {
    1661     if (!monitorCount)
    1662         return E_POINTER;
    1663 
    1664     AutoCaller autoCaller(this);
    1665     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1666 
    1667     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1668 
    1669     *monitorCount = mHWData->mMonitorCount;
    1670 
    1671     return S_OK;
    1672 }
    1673 
    1674 STDMETHODIMP Machine::COMSETTER(MonitorCount)(ULONG monitorCount)
    1675 {
    1676     /* make sure monitor count is a sensible number */
    1677     if (monitorCount < 1 || monitorCount > SchemaDefs::MaxGuestMonitors)
    1678         return setError(E_INVALIDARG,
    1679                         tr("Invalid monitor count: %lu (must be in range [%lu, %lu])"),
    1680                         monitorCount, 1, SchemaDefs::MaxGuestMonitors);
    1681 
    1682     AutoCaller autoCaller(this);
    1683     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1684 
    1685     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1686 
    1687     HRESULT rc = checkStateDependency(MutableStateDep);
    1688     if (FAILED(rc)) return rc;
    1689 
    1690     setModified(IsModified_MachineData);
    1691     mHWData.backup();
    1692     mHWData->mMonitorCount = monitorCount;
    1693 
    1694     return S_OK;
    1695 }
    1696 
    1697 STDMETHODIMP Machine::COMGETTER(BIOSSettings)(IBIOSSettings **biosSettings)
    1698 {
    1699     if (!biosSettings)
    1700         return E_POINTER;
    1701 
    1702     AutoCaller autoCaller(this);
    1703     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1704 
    1705     /* mBIOSSettings is constant during life time, no need to lock */
    1706     mBIOSSettings.queryInterfaceTo(biosSettings);
    1707 
    1708     return S_OK;
    1709 }
    1710 
    1711 STDMETHODIMP Machine::GetCPUProperty(CPUPropertyType_T property, BOOL *aVal)
    1712 {
    1713     if (!aVal)
    1714         return E_POINTER;
    1715 
    1716     AutoCaller autoCaller(this);
    1717     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1718 
    1719     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1720 
    1721     switch(property)
    1722     {
    1723     case CPUPropertyType_PAE:
    1724         *aVal = mHWData->mPAEEnabled;
    1725         break;
    1726 
    1727     case CPUPropertyType_Synthetic:
    1728         *aVal = mHWData->mSyntheticCpu;
    1729         break;
    1730 
    1731     default:
    1732         return E_INVALIDARG;
    1733     }
    1734     return S_OK;
    1735 }
    1736 
    1737 STDMETHODIMP Machine::SetCPUProperty(CPUPropertyType_T property, BOOL aVal)
    1738 {
    1739     AutoCaller autoCaller(this);
    1740     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1741 
    1742     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1743 
    1744     HRESULT rc = checkStateDependency(MutableStateDep);
    1745     if (FAILED(rc)) return rc;
    1746 
    1747     switch(property)
    1748     {
    1749     case CPUPropertyType_PAE:
    1750         setModified(IsModified_MachineData);
    1751         mHWData.backup();
    1752         mHWData->mPAEEnabled = !!aVal;
    1753         break;
    1754 
    1755     case CPUPropertyType_Synthetic:
    1756         setModified(IsModified_MachineData);
    1757         mHWData.backup();
    1758         mHWData->mSyntheticCpu = !!aVal;
    1759         break;
    1760 
    1761     default:
    1762         return E_INVALIDARG;
    1763     }
    1764     return S_OK;
    1765 }
    1766 
    1767 STDMETHODIMP Machine::GetCPUIDLeaf(ULONG aId, ULONG *aValEax, ULONG *aValEbx, ULONG *aValEcx, ULONG *aValEdx)
    1768 {
    1769     CheckComArgOutPointerValid(aValEax);
    1770     CheckComArgOutPointerValid(aValEbx);
    1771     CheckComArgOutPointerValid(aValEcx);
    1772     CheckComArgOutPointerValid(aValEdx);
    1773 
    1774     AutoCaller autoCaller(this);
    1775     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1776 
    1777     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1778 
    1779     switch(aId)
    1780     {
    1781         case 0x0:
    1782         case 0x1:
    1783         case 0x2:
    1784         case 0x3:
    1785         case 0x4:
    1786         case 0x5:
    1787         case 0x6:
    1788         case 0x7:
    1789         case 0x8:
    1790         case 0x9:
    1791         case 0xA:
    1792             if (mHWData->mCpuIdStdLeafs[aId].ulId != aId)
    1793                 return setError(E_INVALIDARG, tr("CpuId override leaf %#x is not set"), aId);
    1794 
    1795             *aValEax = mHWData->mCpuIdStdLeafs[aId].ulEax;
    1796             *aValEbx = mHWData->mCpuIdStdLeafs[aId].ulEbx;
    1797             *aValEcx = mHWData->mCpuIdStdLeafs[aId].ulEcx;
    1798             *aValEdx = mHWData->mCpuIdStdLeafs[aId].ulEdx;
    1799             break;
    1800 
    1801         case 0x80000000:
    1802         case 0x80000001:
    1803         case 0x80000002:
    1804         case 0x80000003:
    1805         case 0x80000004:
    1806         case 0x80000005:
    1807         case 0x80000006:
    1808         case 0x80000007:
    1809         case 0x80000008:
    1810         case 0x80000009:
    1811         case 0x8000000A:
    1812             if (mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulId != aId)
    1813                 return setError(E_INVALIDARG, tr("CpuId override leaf %#x is not set"), aId);
    1814 
    1815             *aValEax = mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEax;
    1816             *aValEbx = mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEbx;
    1817             *aValEcx = mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEcx;
    1818             *aValEdx = mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEdx;
    1819             break;
    1820 
    1821         default:
    1822             return setError(E_INVALIDARG, tr("CpuId override leaf %#x is out of range"), aId);
    1823     }
    1824     return S_OK;
    1825 }
    1826 
    1827 STDMETHODIMP Machine::SetCPUIDLeaf(ULONG aId, ULONG aValEax, ULONG aValEbx, ULONG aValEcx, ULONG aValEdx)
    1828 {
    1829     AutoCaller autoCaller(this);
    1830     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1831 
    1832     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1833 
    1834     HRESULT rc = checkStateDependency(MutableStateDep);
    1835     if (FAILED(rc)) return rc;
    1836 
    1837     switch(aId)
    1838     {
    1839         case 0x0:
    1840         case 0x1:
    1841         case 0x2:
    1842         case 0x3:
    1843         case 0x4:
    1844         case 0x5:
    1845         case 0x6:
    1846         case 0x7:
    1847         case 0x8:
    1848         case 0x9:
    1849         case 0xA:
    1850             AssertCompile(RT_ELEMENTS(mHWData->mCpuIdStdLeafs) == 0xA);
    1851             AssertRelease(aId < RT_ELEMENTS(mHWData->mCpuIdStdLeafs));
    1852             setModified(IsModified_MachineData);
    1853             mHWData.backup();
    1854             mHWData->mCpuIdStdLeafs[aId].ulId  = aId;
    1855             mHWData->mCpuIdStdLeafs[aId].ulEax = aValEax;
    1856             mHWData->mCpuIdStdLeafs[aId].ulEbx = aValEbx;
    1857             mHWData->mCpuIdStdLeafs[aId].ulEcx = aValEcx;
    1858             mHWData->mCpuIdStdLeafs[aId].ulEdx = aValEdx;
    1859             break;
    1860 
    1861         case 0x80000000:
    1862         case 0x80000001:
    1863         case 0x80000002:
    1864         case 0x80000003:
    1865         case 0x80000004:
    1866         case 0x80000005:
    1867         case 0x80000006:
    1868         case 0x80000007:
    1869         case 0x80000008:
    1870         case 0x80000009:
    1871         case 0x8000000A:
    1872             AssertCompile(RT_ELEMENTS(mHWData->mCpuIdExtLeafs) == 0xA);
    1873             AssertRelease(aId - 0x80000000 < RT_ELEMENTS(mHWData->mCpuIdExtLeafs));
    1874             setModified(IsModified_MachineData);
    1875             mHWData.backup();
    1876             mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulId  = aId;
    1877             mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEax = aValEax;
    1878             mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEbx = aValEbx;
    1879             mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEcx = aValEcx;
    1880             mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulEdx = aValEdx;
    1881             break;
    1882 
    1883         default:
    1884             return setError(E_INVALIDARG, tr("CpuId override leaf %#x is out of range"), aId);
    1885     }
    1886     return S_OK;
    1887 }
    1888 
    1889 STDMETHODIMP Machine::RemoveCPUIDLeaf(ULONG aId)
    1890 {
    1891     AutoCaller autoCaller(this);
    1892     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1893 
    1894     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1895 
    1896     HRESULT rc = checkStateDependency(MutableStateDep);
    1897     if (FAILED(rc)) return rc;
    1898 
    1899     switch(aId)
    1900     {
    1901         case 0x0:
    1902         case 0x1:
    1903         case 0x2:
    1904         case 0x3:
    1905         case 0x4:
    1906         case 0x5:
    1907         case 0x6:
    1908         case 0x7:
    1909         case 0x8:
    1910         case 0x9:
    1911         case 0xA:
    1912             AssertCompile(RT_ELEMENTS(mHWData->mCpuIdStdLeafs) == 0xA);
    1913             AssertRelease(aId < RT_ELEMENTS(mHWData->mCpuIdStdLeafs));
    1914             setModified(IsModified_MachineData);
    1915             mHWData.backup();
    1916             /* Invalidate leaf. */
    1917             mHWData->mCpuIdStdLeafs[aId].ulId = UINT32_MAX;
    1918             break;
    1919 
    1920         case 0x80000000:
    1921         case 0x80000001:
    1922         case 0x80000002:
    1923         case 0x80000003:
    1924         case 0x80000004:
    1925         case 0x80000005:
    1926         case 0x80000006:
    1927         case 0x80000007:
    1928         case 0x80000008:
    1929         case 0x80000009:
    1930         case 0x8000000A:
    1931             AssertCompile(RT_ELEMENTS(mHWData->mCpuIdExtLeafs) == 0xA);
    1932             AssertRelease(aId - 0x80000000 < RT_ELEMENTS(mHWData->mCpuIdExtLeafs));
    1933             setModified(IsModified_MachineData);
    1934             mHWData.backup();
    1935             /* Invalidate leaf. */
    1936             mHWData->mCpuIdExtLeafs[aId - 0x80000000].ulId = UINT32_MAX;
    1937             break;
    1938 
    1939         default:
    1940             return setError(E_INVALIDARG, tr("CpuId override leaf %#x is out of range"), aId);
    1941     }
    1942     return S_OK;
    1943 }
    1944 
    1945 STDMETHODIMP Machine::RemoveAllCPUIDLeaves()
    1946 {
    1947     AutoCaller autoCaller(this);
    1948     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1949 
    1950     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1951 
    1952     HRESULT rc = checkStateDependency(MutableStateDep);
    1953     if (FAILED(rc)) return rc;
    1954 
    1955     setModified(IsModified_MachineData);
    1956     mHWData.backup();
    1957 
    1958     /* Invalidate all standard leafs. */
    1959     for (unsigned i = 0; i < RT_ELEMENTS(mHWData->mCpuIdStdLeafs); i++)
    1960         mHWData->mCpuIdStdLeafs[i].ulId = UINT32_MAX;
    1961 
    1962     /* Invalidate all extended leafs. */
    1963     for (unsigned i = 0; i < RT_ELEMENTS(mHWData->mCpuIdExtLeafs); i++)
    1964         mHWData->mCpuIdExtLeafs[i].ulId = UINT32_MAX;
    1965 
    1966     return S_OK;
    1967 }
    1968 
    1969 STDMETHODIMP Machine::GetHWVirtExProperty(HWVirtExPropertyType_T property, BOOL *aVal)
    1970 {
    1971     if (!aVal)
    1972         return E_POINTER;
    1973 
    1974     AutoCaller autoCaller(this);
    1975     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1976 
    1977     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1978 
    1979     switch(property)
    1980     {
    1981         case HWVirtExPropertyType_Enabled:
    1982             *aVal = mHWData->mHWVirtExEnabled;
    1983             break;
    1984 
    1985         case HWVirtExPropertyType_Exclusive:
    1986             *aVal = mHWData->mHWVirtExExclusive;
    1987             break;
    1988 
    1989         case HWVirtExPropertyType_VPID:
    1990             *aVal = mHWData->mHWVirtExVPIDEnabled;
    1991             break;
    1992 
    1993         case HWVirtExPropertyType_NestedPaging:
    1994             *aVal = mHWData->mHWVirtExNestedPagingEnabled;
    1995             break;
    1996 
    1997         case HWVirtExPropertyType_LargePages:
    1998             *aVal = mHWData->mHWVirtExLargePagesEnabled;
    1999             break;
    2000 
    2001         case HWVirtExPropertyType_Force:
    2002             *aVal = mHWData->mHWVirtExForceEnabled;
    2003             break;
    2004 
    2005         default:
    2006             return E_INVALIDARG;
    2007     }
    2008     return S_OK;
    2009 }
    2010 
    2011 STDMETHODIMP Machine::SetHWVirtExProperty(HWVirtExPropertyType_T property, BOOL aVal)
    2012 {
    2013     AutoCaller autoCaller(this);
    2014     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2015 
    2016     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2017 
    2018     HRESULT rc = checkStateDependency(MutableStateDep);
    2019     if (FAILED(rc)) return rc;
    2020 
    2021     switch(property)
    2022     {
    2023         case HWVirtExPropertyType_Enabled:
    2024             setModified(IsModified_MachineData);
    2025             mHWData.backup();
    2026             mHWData->mHWVirtExEnabled = !!aVal;
    2027             break;
    2028 
    2029         case HWVirtExPropertyType_Exclusive:
    2030             setModified(IsModified_MachineData);
    2031             mHWData.backup();
    2032             mHWData->mHWVirtExExclusive = !!aVal;
    2033             break;
    2034 
    2035         case HWVirtExPropertyType_VPID:
    2036             setModified(IsModified_MachineData);
    2037             mHWData.backup();
    2038             mHWData->mHWVirtExVPIDEnabled = !!aVal;
    2039             break;
    2040 
    2041         case HWVirtExPropertyType_NestedPaging:
    2042             setModified(IsModified_MachineData);
    2043             mHWData.backup();
    2044             mHWData->mHWVirtExNestedPagingEnabled = !!aVal;
    2045             break;
    2046 
    2047         case HWVirtExPropertyType_LargePages:
    2048             setModified(IsModified_MachineData);
    2049             mHWData.backup();
    2050             mHWData->mHWVirtExLargePagesEnabled = !!aVal;
    2051             break;
    2052 
    2053         case HWVirtExPropertyType_Force:
    2054             setModified(IsModified_MachineData);
    2055             mHWData.backup();
    2056             mHWData->mHWVirtExForceEnabled = !!aVal;
    2057             break;
    2058 
    2059         default:
    2060             return E_INVALIDARG;
    2061     }
    2062 
    2063     return S_OK;
    2064 }
    2065 
    2066 STDMETHODIMP Machine::COMGETTER(SnapshotFolder)(BSTR *aSnapshotFolder)
    2067 {
    2068     CheckComArgOutPointerValid(aSnapshotFolder);
    2069 
    2070     AutoCaller autoCaller(this);
    2071     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2072 
    2073     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2074 
    2075     mUserData->m_strSnapshotFolderFull.cloneTo(aSnapshotFolder);
    2076 
    2077     return S_OK;
    2078 }
    2079 
    2080 STDMETHODIMP Machine::COMSETTER(SnapshotFolder)(IN_BSTR aSnapshotFolder)
    2081 {
    2082     /* @todo (r=dmik):
    2083      *  1. Allow to change the name of the snapshot folder containing snapshots
    2084      *  2. Rename the folder on disk instead of just changing the property
    2085      *     value (to be smart and not to leave garbage). Note that it cannot be
    2086      *     done here because the change may be rolled back. Thus, the right
    2087      *     place is #saveSettings().
    2088      */
    2089 
    2090     AutoCaller autoCaller(this);
    2091     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2092 
    2093     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2094 
    2095     HRESULT rc = checkStateDependency(MutableStateDep);
    2096     if (FAILED(rc)) return rc;
    2097 
    2098     if (!mData->mCurrentSnapshot.isNull())
    2099         return setError(E_FAIL,
    2100                         tr("The snapshot folder of a machine with snapshots cannot be changed (please delete all snapshots first)"));
    2101 
    2102     Utf8Str strSnapshotFolder0(aSnapshotFolder);       // keep original
    2103     Utf8Str strSnapshotFolder(strSnapshotFolder0);
    2104 
    2105     if (strSnapshotFolder.isEmpty())
    2106     {
    2107         if (isInOwnDir())
    2108             /* the default snapshots folder is 'Snapshots' in the machine dir */
    2109             strSnapshotFolder = "Snapshots";
    2110         else
    2111             /* the default snapshots folder is {UUID}, for backwards
    2112              * compatibility and to resolve conflicts */
    2113             strSnapshotFolder = Utf8StrFmt("{%RTuuid}", mData->mUuid.raw());
    2114     }
    2115 
    2116     int vrc = calculateFullPath(strSnapshotFolder, strSnapshotFolder);
    2117     if (RT_FAILURE(vrc))
    2118         return setError(E_FAIL,
    2119                         tr("Invalid snapshot folder '%ls' (%Rrc)"),
    2120                         aSnapshotFolder, vrc);
    2121 
    2122     setModified(IsModified_MachineData);
    2123     mUserData.backup();
    2124     mUserData->s.strSnapshotFolder = strSnapshotFolder0;
    2125     mUserData->m_strSnapshotFolderFull = strSnapshotFolder;
    2126 
    2127     return S_OK;
    2128 }
    2129 
    2130 STDMETHODIMP Machine::COMGETTER(MediumAttachments)(ComSafeArrayOut(IMediumAttachment*, aAttachments))
    2131 {
    2132     if (ComSafeArrayOutIsNull(aAttachments))
    2133         return E_POINTER;
    2134 
    2135     AutoCaller autoCaller(this);
    2136     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2137 
    2138     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2139 
    2140     SafeIfaceArray<IMediumAttachment> attachments(mMediaData->mAttachments);
    2141     attachments.detachTo(ComSafeArrayOutArg(aAttachments));
    2142 
    2143     return S_OK;
    2144 }
    2145 
    2146 STDMETHODIMP Machine::COMGETTER(VRDPServer)(IVRDPServer **vrdpServer)
    2147 {
    2148 #ifdef VBOX_WITH_VRDP
    2149     if (!vrdpServer)
    2150         return E_POINTER;
    2151 
    2152     AutoCaller autoCaller(this);
    2153     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2154 
    2155     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2156 
    2157     Assert(!!mVRDPServer);
    2158     mVRDPServer.queryInterfaceTo(vrdpServer);
    2159 
    2160     return S_OK;
    2161 #else
    2162     NOREF(vrdpServer);
    2163     ReturnComNotImplemented();
    2164 #endif
    2165 }
    2166 
    2167 STDMETHODIMP Machine::COMGETTER(AudioAdapter)(IAudioAdapter **audioAdapter)
    2168 {
    2169     if (!audioAdapter)
    2170         return E_POINTER;
    2171 
    2172     AutoCaller autoCaller(this);
    2173     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2174 
    2175     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2176 
    2177     mAudioAdapter.queryInterfaceTo(audioAdapter);
    2178     return S_OK;
    2179 }
    2180 
    2181 STDMETHODIMP Machine::COMGETTER(USBController)(IUSBController **aUSBController)
    2182 {
    2183 #ifdef VBOX_WITH_VUSB
    2184     CheckComArgOutPointerValid(aUSBController);
    2185 
    2186     AutoCaller autoCaller(this);
    2187     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2188     MultiResult rc(S_OK);
    2189 
    2190 # ifdef VBOX_WITH_USB
    2191     rc = mParent->host()->checkUSBProxyService();
    2192     if (FAILED(rc)) return rc;
    2193 # endif
    2194 
    2195     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2196 
    2197     return rc = mUSBController.queryInterfaceTo(aUSBController);
    2198 #else
    2199     /* Note: The GUI depends on this method returning E_NOTIMPL with no
    2200      * extended error info to indicate that USB is simply not available
    2201      * (w/o treting it as a failure), for example, as in OSE */
    2202     NOREF(aUSBController);
    2203     ReturnComNotImplemented();
    2204 #endif /* VBOX_WITH_VUSB */
    2205 }
    2206 
    2207 STDMETHODIMP Machine::COMGETTER(SettingsFilePath)(BSTR *aFilePath)
    2208 {
    2209     CheckComArgOutPointerValid(aFilePath);
    2210 
    2211     AutoLimitedCaller autoCaller(this);
    2212     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2213 
    2214     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2215 
    2216     mData->m_strConfigFileFull.cloneTo(aFilePath);
    2217     return S_OK;
    2218 }
    2219 
    2220 STDMETHODIMP Machine::COMGETTER(SettingsModified)(BOOL *aModified)
    2221 {
    2222     CheckComArgOutPointerValid(aModified);
    2223 
    2224     AutoCaller autoCaller(this);
    2225     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2226 
    2227     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2228 
    2229     HRESULT rc = checkStateDependency(MutableStateDep);
    2230     if (FAILED(rc)) return rc;
    2231 
    2232     if (!mData->pMachineConfigFile->fileExists())
    2233         // this is a new machine, and no config file exists yet:
    2234         *aModified = TRUE;
    2235     else
    2236         *aModified = (mData->flModifications != 0);
    2237 
    2238     return S_OK;
    2239 }
    2240 
    2241 STDMETHODIMP Machine::COMGETTER(SessionState)(SessionState_T *aSessionState)
    2242 {
    2243     CheckComArgOutPointerValid(aSessionState);
    2244 
    2245     AutoCaller autoCaller(this);
    2246     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2247 
    2248     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2249 
    2250     *aSessionState = mData->mSession.mState;
    2251 
    2252     return S_OK;
    2253 }
    2254 
    2255 STDMETHODIMP Machine::COMGETTER(SessionType)(BSTR *aSessionType)
    2256 {
    2257     CheckComArgOutPointerValid(aSessionType);
    2258 
    2259     AutoCaller autoCaller(this);
    2260     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2261 
    2262     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2263 
    2264     mData->mSession.mType.cloneTo(aSessionType);
    2265 
    2266     return S_OK;
    2267 }
    2268 
    2269 STDMETHODIMP Machine::COMGETTER(SessionPid)(ULONG *aSessionPid)
    2270 {
    2271     CheckComArgOutPointerValid(aSessionPid);
    2272 
    2273     AutoCaller autoCaller(this);
    2274     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2275 
    2276     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2277 
    2278     *aSessionPid = mData->mSession.mPid;
    2279 
    2280     return S_OK;
    2281 }
    2282 
    2283 STDMETHODIMP Machine::COMGETTER(State)(MachineState_T *machineState)
    2284 {
    2285     if (!machineState)
    2286         return E_POINTER;
    2287 
    2288     AutoCaller autoCaller(this);
    2289     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2290 
    2291     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2292 
    2293     *machineState = mData->mMachineState;
    2294 
    2295     return S_OK;
    2296 }
    2297 
    2298 STDMETHODIMP Machine::COMGETTER(LastStateChange)(LONG64 *aLastStateChange)
    2299 {
    2300     CheckComArgOutPointerValid(aLastStateChange);
    2301 
    2302     AutoCaller autoCaller(this);
    2303     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2304 
    2305     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2306 
    2307     *aLastStateChange = RTTimeSpecGetMilli(&mData->mLastStateChange);
    2308 
    2309     return S_OK;
    2310 }
    2311 
    2312 STDMETHODIMP Machine::COMGETTER(StateFilePath)(BSTR *aStateFilePath)
    2313 {
    2314     CheckComArgOutPointerValid(aStateFilePath);
    2315 
    2316     AutoCaller autoCaller(this);
    2317     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2318 
    2319     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2320 
    2321     mSSData->mStateFilePath.cloneTo(aStateFilePath);
    2322 
    2323     return S_OK;
    2324 }
    2325 
    2326 STDMETHODIMP Machine::COMGETTER(LogFolder)(BSTR *aLogFolder)
    2327 {
    2328     CheckComArgOutPointerValid(aLogFolder);
    2329 
    2330     AutoCaller autoCaller(this);
    2331     AssertComRCReturnRC(autoCaller.rc());
    2332 
    2333     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2334 
    2335     Utf8Str logFolder;
    2336     getLogFolder(logFolder);
    2337 
    2338     Bstr (logFolder).cloneTo(aLogFolder);
    2339 
    2340     return S_OK;
    2341 }
    2342 
    2343 STDMETHODIMP Machine::COMGETTER(CurrentSnapshot) (ISnapshot **aCurrentSnapshot)
    2344 {
    2345     CheckComArgOutPointerValid(aCurrentSnapshot);
    2346 
    2347     AutoCaller autoCaller(this);
    2348     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2349 
    2350     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2351 
    2352     mData->mCurrentSnapshot.queryInterfaceTo(aCurrentSnapshot);
    2353 
    2354     return S_OK;
    2355 }
    2356 
    2357 STDMETHODIMP Machine::COMGETTER(SnapshotCount)(ULONG *aSnapshotCount)
    2358 {
    2359     CheckComArgOutPointerValid(aSnapshotCount);
    2360 
    2361     AutoCaller autoCaller(this);
    2362     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2363 
    2364     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2365 
    2366     *aSnapshotCount = mData->mFirstSnapshot.isNull()
    2367                           ? 0
    2368                           : mData->mFirstSnapshot->getAllChildrenCount() + 1;
    2369 
    2370     return S_OK;
    2371 }
    2372 
    2373 STDMETHODIMP Machine::COMGETTER(CurrentStateModified)(BOOL *aCurrentStateModified)
    2374 {
    2375     CheckComArgOutPointerValid(aCurrentStateModified);
    2376 
    2377     AutoCaller autoCaller(this);
    2378     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2379 
    2380     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2381 
    2382     /* Note: for machines with no snapshots, we always return FALSE
    2383      * (mData->mCurrentStateModified will be TRUE in this case, for historical
    2384      * reasons :) */
    2385 
    2386     *aCurrentStateModified = mData->mFirstSnapshot.isNull()
    2387                             ? FALSE
    2388                             : mData->mCurrentStateModified;
    2389 
    2390     return S_OK;
    2391 }
    2392 
    2393 STDMETHODIMP Machine::COMGETTER(SharedFolders)(ComSafeArrayOut(ISharedFolder *, aSharedFolders))
    2394 {
    2395     CheckComArgOutSafeArrayPointerValid(aSharedFolders);
    2396 
    2397     AutoCaller autoCaller(this);
    2398     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2399 
    2400     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2401 
    2402     SafeIfaceArray<ISharedFolder> folders(mHWData->mSharedFolders);
    2403     folders.detachTo(ComSafeArrayOutArg(aSharedFolders));
    2404 
    2405     return S_OK;
    2406 }
    2407 
    2408 STDMETHODIMP Machine::COMGETTER(ClipboardMode)(ClipboardMode_T *aClipboardMode)
    2409 {
    2410     CheckComArgOutPointerValid(aClipboardMode);
    2411 
    2412     AutoCaller autoCaller(this);
    2413     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2414 
    2415     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2416 
    2417     *aClipboardMode = mHWData->mClipboardMode;
    2418 
    2419     return S_OK;
    2420 }
    2421 
    2422 STDMETHODIMP
    2423 Machine::COMSETTER(ClipboardMode)(ClipboardMode_T aClipboardMode)
    2424 {
    2425     AutoCaller autoCaller(this);
    2426     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2427 
    2428     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2429 
    2430     HRESULT rc = checkStateDependency(MutableStateDep);
    2431     if (FAILED(rc)) return rc;
    2432 
    2433     setModified(IsModified_MachineData);
    2434     mHWData.backup();
    2435     mHWData->mClipboardMode = aClipboardMode;
    2436 
    2437     return S_OK;
    2438 }
    2439 
    2440 STDMETHODIMP
    2441 Machine::COMGETTER(GuestPropertyNotificationPatterns)(BSTR *aPatterns)
    2442 {
    2443     CheckComArgOutPointerValid(aPatterns);
    2444 
    2445     AutoCaller autoCaller(this);
    2446     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2447 
    2448     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2449 
    2450     try
    2451     {
    2452         mHWData->mGuestPropertyNotificationPatterns.cloneTo(aPatterns);
    2453     }
    2454     catch (...)
    2455     {
    2456         return VirtualBox::handleUnexpectedExceptions(RT_SRC_POS);
    2457     }
    2458 
    2459     return S_OK;
    2460 }
    2461 
    2462 STDMETHODIMP
    2463 Machine::COMSETTER(GuestPropertyNotificationPatterns)(IN_BSTR aPatterns)
    2464 {
    2465     AutoCaller autoCaller(this);
    2466     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2467 
    2468     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2469 
    2470     HRESULT rc = checkStateDependency(MutableStateDep);
    2471     if (FAILED(rc)) return rc;
    2472 
    2473     setModified(IsModified_MachineData);
    2474     mHWData.backup();
    2475     mHWData->mGuestPropertyNotificationPatterns = aPatterns;
    2476     return rc;
    2477 }
    2478 
    2479 STDMETHODIMP
    2480 Machine::COMGETTER(StorageControllers)(ComSafeArrayOut(IStorageController *, aStorageControllers))
    2481 {
    2482     CheckComArgOutSafeArrayPointerValid(aStorageControllers);
    2483 
    2484     AutoCaller autoCaller(this);
    2485     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2486 
    2487     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2488 
    2489     SafeIfaceArray<IStorageController> ctrls(*mStorageControllers.data());
    2490     ctrls.detachTo(ComSafeArrayOutArg(aStorageControllers));
    2491 
    2492     return S_OK;
    2493 }
    2494 
    2495 STDMETHODIMP
    2496 Machine::COMGETTER(TeleporterEnabled)(BOOL *aEnabled)
    2497 {
    2498     CheckComArgOutPointerValid(aEnabled);
    2499 
    2500     AutoCaller autoCaller(this);
    2501     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2502 
    2503     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2504 
    2505     *aEnabled = mUserData->s.fTeleporterEnabled;
    2506 
    2507     return S_OK;
    2508 }
    2509 
    2510 STDMETHODIMP Machine::COMSETTER(TeleporterEnabled)(BOOL aEnabled)
    2511 {
    2512     AutoCaller autoCaller(this);
    2513     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2514 
    2515     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2516 
    2517     /* Only allow it to be set to true when PoweredOff or Aborted.
    2518        (Clearing it is always permitted.) */
    2519     if (    aEnabled
    2520         &&  mData->mRegistered
    2521         &&  (   !isSessionMachine()
    2522              || (   mData->mMachineState != MachineState_PoweredOff
    2523                  && mData->mMachineState != MachineState_Teleported
    2524                  && mData->mMachineState != MachineState_Aborted
    2525                 )
    2526             )
    2527        )
    2528         return setError(VBOX_E_INVALID_VM_STATE,
    2529                         tr("The machine is not powered off (state is %s)"),
    2530                         Global::stringifyMachineState(mData->mMachineState));
    2531 
    2532     setModified(IsModified_MachineData);
    2533     mUserData.backup();
    2534     mUserData->s.fTeleporterEnabled = !!aEnabled;
    2535 
    2536     return S_OK;
    2537 }
    2538 
    2539 STDMETHODIMP Machine::COMGETTER(TeleporterPort)(ULONG *aPort)
    2540 {
    2541     CheckComArgOutPointerValid(aPort);
    2542 
    2543     AutoCaller autoCaller(this);
    2544     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2545 
    2546     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2547 
    2548     *aPort = (ULONG)mUserData->s.uTeleporterPort;
    2549 
    2550     return S_OK;
    2551 }
    2552 
    2553 STDMETHODIMP Machine::COMSETTER(TeleporterPort)(ULONG aPort)
    2554 {
    2555     if (aPort >= _64K)
    2556         return setError(E_INVALIDARG, tr("Invalid port number %d"), aPort);
    2557 
    2558     AutoCaller autoCaller(this);
    2559     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2560 
    2561     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2562 
    2563     HRESULT rc = checkStateDependency(MutableStateDep);
    2564     if (FAILED(rc)) return rc;
    2565 
    2566     setModified(IsModified_MachineData);
    2567     mUserData.backup();
    2568     mUserData->s.uTeleporterPort = (uint32_t)aPort;
    2569 
    2570     return S_OK;
    2571 }
    2572 
    2573 STDMETHODIMP Machine::COMGETTER(TeleporterAddress)(BSTR *aAddress)
    2574 {
    2575     CheckComArgOutPointerValid(aAddress);
    2576 
    2577     AutoCaller autoCaller(this);
    2578     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2579 
    2580     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2581 
    2582     mUserData->s.strTeleporterAddress.cloneTo(aAddress);
    2583 
    2584     return S_OK;
    2585 }
    2586 
    2587 STDMETHODIMP Machine::COMSETTER(TeleporterAddress)(IN_BSTR aAddress)
    2588 {
    2589     AutoCaller autoCaller(this);
    2590     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2591 
    2592     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2593 
    2594     HRESULT rc = checkStateDependency(MutableStateDep);
    2595     if (FAILED(rc)) return rc;
    2596 
    2597     setModified(IsModified_MachineData);
    2598     mUserData.backup();
    2599     mUserData->s.strTeleporterAddress = aAddress;
    2600 
    2601     return S_OK;
    2602 }
    2603 
    2604 STDMETHODIMP Machine::COMGETTER(TeleporterPassword)(BSTR *aPassword)
    2605 {
    2606     CheckComArgOutPointerValid(aPassword);
    2607 
    2608     AutoCaller autoCaller(this);
    2609     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2610 
    2611     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2612 
    2613     mUserData->s.strTeleporterPassword.cloneTo(aPassword);
    2614 
    2615     return S_OK;
    2616 }
    2617 
    2618 STDMETHODIMP Machine::COMSETTER(TeleporterPassword)(IN_BSTR aPassword)
    2619 {
    2620     AutoCaller autoCaller(this);
    2621     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2622 
    2623     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2624 
    2625     HRESULT rc = checkStateDependency(MutableStateDep);
    2626     if (FAILED(rc)) return rc;
    2627 
    2628     setModified(IsModified_MachineData);
    2629     mUserData.backup();
    2630     mUserData->s.strTeleporterPassword = aPassword;
    2631 
    2632     return S_OK;
    2633 }
    2634 
    2635 STDMETHODIMP Machine::COMGETTER(FaultToleranceState)(FaultToleranceState_T *aState)
    2636 {
    2637     CheckComArgOutPointerValid(aState);
    2638 
    2639     AutoCaller autoCaller(this);
    2640     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2641 
    2642     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2643 
    2644     *aState = mUserData->s.enmFaultToleranceState;
    2645     return S_OK;
    2646 }
    2647 
    2648 STDMETHODIMP Machine::COMSETTER(FaultToleranceState)(FaultToleranceState_T aState)
    2649 {
    2650     AutoCaller autoCaller(this);
    2651     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2652 
    2653     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2654 
    2655     /* @todo deal with running state change. */
    2656     HRESULT rc = checkStateDependency(MutableStateDep);
    2657     if (FAILED(rc)) return rc;
    2658 
    2659     setModified(IsModified_MachineData);
    2660     mUserData.backup();
    2661     mUserData->s.enmFaultToleranceState = aState;
    2662     return S_OK;
    2663 }
    2664 
    2665 STDMETHODIMP Machine::COMGETTER(FaultToleranceAddress)(BSTR *aAddress)
    2666 {
    2667     CheckComArgOutPointerValid(aAddress);
    2668 
    2669     AutoCaller autoCaller(this);
    2670     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2671 
    2672     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2673 
    2674     mUserData->s.strFaultToleranceAddress.cloneTo(aAddress);
    2675     return S_OK;
    2676 }
    2677 
    2678 STDMETHODIMP Machine::COMSETTER(FaultToleranceAddress)(IN_BSTR aAddress)
    2679 {
    2680     AutoCaller autoCaller(this);
    2681     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2682 
    2683     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2684 
    2685     /* @todo deal with running state change. */
    2686     HRESULT rc = checkStateDependency(MutableStateDep);
    2687     if (FAILED(rc)) return rc;
    2688 
    2689     setModified(IsModified_MachineData);
    2690     mUserData.backup();
    2691     mUserData->s.strFaultToleranceAddress = aAddress;
    2692     return S_OK;
    2693 }
    2694 
    2695 STDMETHODIMP Machine::COMGETTER(FaultTolerancePort)(ULONG *aPort)
    2696 {
    2697     CheckComArgOutPointerValid(aPort);
    2698 
    2699     AutoCaller autoCaller(this);
    2700     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2701 
    2702     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2703 
    2704     *aPort = mUserData->s.uFaultTolerancePort;
    2705     return S_OK;
    2706 }
    2707 
    2708 STDMETHODIMP Machine::COMSETTER(FaultTolerancePort)(ULONG aPort)
    2709 {
    2710     AutoCaller autoCaller(this);
    2711     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2712 
    2713     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2714 
    2715     /* @todo deal with running state change. */
    2716     HRESULT rc = checkStateDependency(MutableStateDep);
    2717     if (FAILED(rc)) return rc;
    2718 
    2719     setModified(IsModified_MachineData);
    2720     mUserData.backup();
    2721     mUserData->s.uFaultTolerancePort = aPort;
    2722     return S_OK;
    2723 }
    2724 
    2725 STDMETHODIMP Machine::COMGETTER(FaultTolerancePassword)(BSTR *aPassword)
    2726 {
    2727     CheckComArgOutPointerValid(aPassword);
    2728 
    2729     AutoCaller autoCaller(this);
    2730     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2731 
    2732     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2733 
    2734     mUserData->s.strFaultTolerancePassword.cloneTo(aPassword);
    2735 
    2736     return S_OK;
    2737 }
    2738 
    2739 STDMETHODIMP Machine::COMSETTER(FaultTolerancePassword)(IN_BSTR aPassword)
    2740 {
    2741     AutoCaller autoCaller(this);
    2742     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2743 
    2744     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2745 
    2746     /* @todo deal with running state change. */
    2747     HRESULT rc = checkStateDependency(MutableStateDep);
    2748     if (FAILED(rc)) return rc;
    2749 
    2750     setModified(IsModified_MachineData);
    2751     mUserData.backup();
    2752     mUserData->s.strFaultTolerancePassword = aPassword;
    2753 
    2754     return S_OK;
    2755 }
    2756 
    2757 STDMETHODIMP Machine::COMGETTER(FaultToleranceSyncInterval)(ULONG *aInterval)
    2758 {
    2759     CheckComArgOutPointerValid(aInterval);
    2760 
    2761     AutoCaller autoCaller(this);
    2762     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2763 
    2764     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2765 
    2766     *aInterval = mUserData->s.uFaultToleranceInterval;
    2767     return S_OK;
    2768 }
    2769 
    2770 STDMETHODIMP Machine::COMSETTER(FaultToleranceSyncInterval)(ULONG aInterval)
    2771 {
    2772     AutoCaller autoCaller(this);
    2773     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2774 
    2775     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2776 
    2777     /* @todo deal with running state change. */
    2778     HRESULT rc = checkStateDependency(MutableStateDep);
    2779     if (FAILED(rc)) return rc;
    2780 
    2781     setModified(IsModified_MachineData);
    2782     mUserData.backup();
    2783     mUserData->s.uFaultToleranceInterval = aInterval;
    2784     return S_OK;
    2785 }
    2786 
    2787 STDMETHODIMP Machine::COMGETTER(RTCUseUTC)(BOOL *aEnabled)
    2788 {
    2789     CheckComArgOutPointerValid(aEnabled);
    2790 
    2791     AutoCaller autoCaller(this);
    2792     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2793 
    2794     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2795 
    2796     *aEnabled = mUserData->s.fRTCUseUTC;
    2797 
    2798     return S_OK;
    2799 }
    2800 
    2801 STDMETHODIMP Machine::COMSETTER(RTCUseUTC)(BOOL aEnabled)
    2802 {
    2803     AutoCaller autoCaller(this);
    2804     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2805 
    2806     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2807 
    2808     /* Only allow it to be set to true when PoweredOff or Aborted.
    2809        (Clearing it is always permitted.) */
    2810     if (    aEnabled
    2811         &&  mData->mRegistered
    2812         &&  (   !isSessionMachine()
    2813              || (   mData->mMachineState != MachineState_PoweredOff
    2814                  && mData->mMachineState != MachineState_Teleported
    2815                  && mData->mMachineState != MachineState_Aborted
    2816                 )
    2817             )
    2818        )
    2819         return setError(VBOX_E_INVALID_VM_STATE,
    2820                         tr("The machine is not powered off (state is %s)"),
    2821                         Global::stringifyMachineState(mData->mMachineState));
    2822 
    2823     setModified(IsModified_MachineData);
    2824     mUserData.backup();
    2825     mUserData->s.fRTCUseUTC = !!aEnabled;
    2826 
    2827     return S_OK;
    2828 }
    2829 
    2830 STDMETHODIMP Machine::COMGETTER(IoCacheEnabled)(BOOL *aEnabled)
    2831 {
    2832     CheckComArgOutPointerValid(aEnabled);
    2833 
    2834     AutoCaller autoCaller(this);
    2835     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2836 
    2837     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2838 
    2839     *aEnabled = mHWData->mIoCacheEnabled;
    2840 
    2841     return S_OK;
    2842 }
    2843 
    2844 STDMETHODIMP Machine::COMSETTER(IoCacheEnabled)(BOOL aEnabled)
    2845 {
    2846     AutoCaller autoCaller(this);
    2847     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2848 
    2849     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2850 
    2851     HRESULT rc = checkStateDependency(MutableStateDep);
    2852     if (FAILED(rc)) return rc;
    2853 
    2854     setModified(IsModified_MachineData);
    2855     mHWData.backup();
    2856     mHWData->mIoCacheEnabled = aEnabled;
    2857 
    2858     return S_OK;
    2859 }
    2860 
    2861 STDMETHODIMP Machine::COMGETTER(IoCacheSize)(ULONG *aIoCacheSize)
    2862 {
    2863     CheckComArgOutPointerValid(aIoCacheSize);
    2864 
    2865     AutoCaller autoCaller(this);
    2866     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2867 
    2868     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2869 
    2870     *aIoCacheSize = mHWData->mIoCacheSize;
    2871 
    2872     return S_OK;
    2873 }
    2874 
    2875 STDMETHODIMP Machine::COMSETTER(IoCacheSize)(ULONG  aIoCacheSize)
    2876 {
    2877     AutoCaller autoCaller(this);
    2878     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2879 
    2880     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2881 
    2882     HRESULT rc = checkStateDependency(MutableStateDep);
    2883     if (FAILED(rc)) return rc;
    2884 
    2885     setModified(IsModified_MachineData);
    2886     mHWData.backup();
    2887     mHWData->mIoCacheSize = aIoCacheSize;
    2888 
    2889     return S_OK;
    2890 }
    2891 
    2892 
    2893 /**
    2894  *  @note Locks objects!
    2895  */
    2896 STDMETHODIMP Machine::LockMachine(ISession *aSession,
    2897                                   LockType_T lockType)
    2898 {
    2899     CheckComArgNotNull(aSession);
    2900 
    2901     AutoCaller autoCaller(this);
    2902     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2903 
    2904     /* check the session state */
    2905     SessionState_T state;
    2906     HRESULT rc = aSession->COMGETTER(State)(&state);
    2907     if (FAILED(rc)) return rc;
    2908 
    2909     if (state != SessionState_Unlocked)
    2910         return setError(VBOX_E_INVALID_OBJECT_STATE,
    2911                         tr("The given session is busy"));
    2912 
    2913     // get the client's IInternalSessionControl interface
    2914     ComPtr<IInternalSessionControl> pSessionControl = aSession;
    2915     ComAssertMsgRet(!!pSessionControl, ("No IInternalSessionControl interface"),
    2916                     E_INVALIDARG);
    2917 
    2918     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2919 
    2920     if (!mData->mRegistered)
    2921         return setError(E_UNEXPECTED,
    2922                         tr("The machine '%s' is not registered"),
    2923                         mUserData->s.strName.c_str());
    2924 
    2925     LogFlowThisFunc(("mSession.mState=%s\n", Global::stringifySessionState(mData->mSession.mState)));
    2926 
    2927     SessionState_T oldState = mData->mSession.mState;
    2928     /* Hack: in case the session is closing and there is a progress object
    2929      * which allows waiting for the session to be closed, take the opportunity
    2930      * and do a limited wait (max. 1 second). This helps a lot when the system
    2931      * is busy and thus session closing can take a little while. */
    2932     if (    mData->mSession.mState == SessionState_Unlocking
    2933         &&  mData->mSession.mProgress)
    2934     {
    2935         alock.release();
    2936         mData->mSession.mProgress->WaitForCompletion(1000);
    2937         alock.acquire();
    2938         LogFlowThisFunc(("after waiting: mSession.mState=%s\n", Global::stringifySessionState(mData->mSession.mState)));
    2939     }
    2940 
    2941     // try again now
    2942     if (    (mData->mSession.mState == SessionState_Locked)         // machine is write-locked already (i.e. session machine exists)
    2943          && (lockType == LockType_Shared)                           // caller wants a shared link to the existing session that holds the write lock:
    2944        )
    2945     {
    2946         // OK, share the session... we are now dealing with three processes:
    2947         // 1) VBoxSVC (where this code runs);
    2948         // 2) process C: the caller's client process (who wants a shared session);
    2949         // 3) process W: the process which already holds the write lock on the machine (write-locking session)
    2950 
    2951         // copy pointers to W (the write-locking session) before leaving lock (these must not be NULL)
    2952         ComPtr<IInternalSessionControl> pSessionW = mData->mSession.mDirectControl;
    2953         ComAssertRet(!pSessionW.isNull(), E_FAIL);
    2954         ComObjPtr<SessionMachine> pSessionMachine = mData->mSession.mMachine;
    2955         AssertReturn(!pSessionMachine.isNull(), E_FAIL);
    2956 
    2957         /*
    2958          *  Leave the lock before calling the client process. It's safe here
    2959          *  since the only thing to do after we get the lock again is to add
    2960          *  the remote control to the list (which doesn't directly influence
    2961          *  anything).
    2962          */
    2963         alock.leave();
    2964 
    2965         // get the console of the session holding the write lock (this is a remote call)
    2966         ComPtr<IConsole> pConsoleW;
    2967         LogFlowThisFunc(("Calling GetRemoteConsole()...\n"));
    2968         rc = pSessionW->GetRemoteConsole(pConsoleW.asOutParam());
    2969         LogFlowThisFunc(("GetRemoteConsole() returned %08X\n", rc));
    2970         if (FAILED(rc))
    2971             // the failure may occur w/o any error info (from RPC), so provide one
    2972             return setError(VBOX_E_VM_ERROR,
    2973                             tr("Failed to get a console object from the direct session (%Rrc)"), rc);
    2974 
    2975         ComAssertRet(!pConsoleW.isNull(), E_FAIL);
    2976 
    2977         // share the session machine and W's console with the caller's session
    2978         LogFlowThisFunc(("Calling AssignRemoteMachine()...\n"));
    2979         rc = pSessionControl->AssignRemoteMachine(pSessionMachine, pConsoleW);
    2980         LogFlowThisFunc(("AssignRemoteMachine() returned %08X\n", rc));
    2981 
    2982         if (FAILED(rc))
    2983             // the failure may occur w/o any error info (from RPC), so provide one
    2984             return setError(VBOX_E_VM_ERROR,
    2985                             tr("Failed to assign the machine to the session (%Rrc)"), rc);
    2986         alock.enter();
    2987 
    2988         // need to revalidate the state after entering the lock again
    2989         if (mData->mSession.mState != SessionState_Locked)
    2990         {
    2991             pSessionControl->Uninitialize();
    2992             return setError(VBOX_E_INVALID_SESSION_STATE,
    2993                             tr("The machine '%s' was unlocked unexpectedly while attempting to share its session"),
    2994                                mUserData->s.strName.c_str());
    2995         }
    2996 
    2997         // add the caller's session to the list
    2998         mData->mSession.mRemoteControls.push_back(pSessionControl);
    2999     }
    3000     else if (    mData->mSession.mState == SessionState_Locked
    3001               || mData->mSession.mState == SessionState_Unlocking
    3002             )
    3003     {
    3004         // sharing not permitted, or machine still unlocking:
    3005         return setError(VBOX_E_INVALID_OBJECT_STATE,
    3006                         tr("The machine '%s' is already locked for a session (or being unlocked)"),
    3007                         mUserData->s.strName.c_str());
    3008     }
    3009     else
    3010     {
    3011         // machine is not locked: then write-lock the machine (create the session machine)
    3012 
    3013         // must not be busy
    3014         AssertReturn(!Global::IsOnlineOrTransient(mData->mMachineState), E_FAIL);
    3015 
    3016         // get the caller's session PID
    3017         RTPROCESS pid = NIL_RTPROCESS;
    3018         AssertCompile(sizeof(ULONG) == sizeof(RTPROCESS));
    3019         pSessionControl->GetPID((ULONG*)&pid);
    3020         Assert(pid != NIL_RTPROCESS);
    3021 
    3022         bool fLaunchingVMProcess = (mData->mSession.mState == SessionState_Spawning);
    3023 
    3024         if (fLaunchingVMProcess)
    3025         {
    3026             // this machine is awaiting for a spawning session to be opened:
    3027             // then the calling process must be the one that got started by
    3028             // launchVMProcess()
    3029 
    3030             LogFlowThisFunc(("mSession.mPid=%d(0x%x)\n", mData->mSession.mPid, mData->mSession.mPid));
    3031             LogFlowThisFunc(("session.pid=%d(0x%x)\n", pid, pid));
    3032 
    3033             if (mData->mSession.mPid != pid)
    3034                 return setError(E_ACCESSDENIED,
    3035                                 tr("An unexpected process (PID=0x%08X) has tried to lock the "
    3036                                    "machine '%s', while only the process started by launchVMProcess (PID=0x%08X) is allowed"),
    3037                                 pid, mUserData->s.strName.c_str(), mData->mSession.mPid);
    3038         }
    3039 
    3040         // create the mutable SessionMachine from the current machine
    3041         ComObjPtr<SessionMachine> sessionMachine;
    3042         sessionMachine.createObject();
    3043         rc = sessionMachine->init(this);
    3044         AssertComRC(rc);
    3045 
    3046         /* NOTE: doing return from this function after this point but
    3047          * before the end is forbidden since it may call SessionMachine::uninit()
    3048          * (through the ComObjPtr's destructor) which requests the VirtualBox write
    3049          * lock while still holding the Machine lock in alock so that a deadlock
    3050          * is possible due to the wrong lock order. */
    3051 
    3052         if (SUCCEEDED(rc))
    3053         {
    3054             /*
    3055              *  Set the session state to Spawning to protect against subsequent
    3056              *  attempts to open a session and to unregister the machine after
    3057              *  we leave the lock.
    3058              */
    3059             SessionState_T origState = mData->mSession.mState;
    3060             mData->mSession.mState = SessionState_Spawning;
    3061 
    3062             /*
    3063              *  Leave the lock before calling the client process -- it will call
    3064              *  Machine/SessionMachine methods. Leaving the lock here is quite safe
    3065              *  because the state is Spawning, so that openRemotesession() and
    3066              *  openExistingSession() calls will fail. This method, called before we
    3067              *  enter the lock again, will fail because of the wrong PID.
    3068              *
    3069              *  Note that mData->mSession.mRemoteControls accessed outside
    3070              *  the lock may not be modified when state is Spawning, so it's safe.
    3071              */
    3072             alock.leave();
    3073 
    3074             LogFlowThisFunc(("Calling AssignMachine()...\n"));
    3075             rc = pSessionControl->AssignMachine(sessionMachine);
    3076             LogFlowThisFunc(("AssignMachine() returned %08X\n", rc));
    3077 
    3078             /* The failure may occur w/o any error info (from RPC), so provide one */
    3079             if (FAILED(rc))
    3080                 setError(VBOX_E_VM_ERROR,
    3081                          tr("Failed to assign the machine to the session (%Rrc)"), rc);
    3082 
    3083             if (    SUCCEEDED(rc)
    3084                  && fLaunchingVMProcess
    3085                )
    3086             {
    3087                 /* complete the remote session initialization */
    3088 
    3089                 /* get the console from the direct session */
    3090                 ComPtr<IConsole> console;
    3091                 rc = pSessionControl->GetRemoteConsole(console.asOutParam());
    3092                 ComAssertComRC(rc);
    3093 
    3094                 if (SUCCEEDED(rc) && !console)
    3095                 {
    3096                     ComAssert(!!console);
    3097                     rc = E_FAIL;
    3098                 }
    3099 
    3100                 /* assign machine & console to the remote session */
    3101                 if (SUCCEEDED(rc))
    3102                 {
    3103                     /*
    3104                      *  after openRemoteSession(), the first and the only
    3105                      *  entry in remoteControls is that remote session
    3106                      */
    3107                     LogFlowThisFunc(("Calling AssignRemoteMachine()...\n"));
    3108                     rc = mData->mSession.mRemoteControls.front()->AssignRemoteMachine(sessionMachine, console);
    3109                     LogFlowThisFunc(("AssignRemoteMachine() returned %08X\n", rc));
    3110 
    3111                     /* The failure may occur w/o any error info (from RPC), so provide one */
    3112                     if (FAILED(rc))
    3113                         setError(VBOX_E_VM_ERROR,
    3114                                  tr("Failed to assign the machine to the remote session (%Rrc)"), rc);
    3115                 }
    3116 
    3117                 if (FAILED(rc))
    3118                     pSessionControl->Uninitialize();
    3119             }
    3120 
    3121             /* enter the lock again */
    3122             alock.enter();
    3123 
    3124             /* Restore the session state */
    3125             mData->mSession.mState = origState;
    3126         }
    3127 
    3128         // finalize spawning anyway (this is why we don't return on errors above)
    3129         if (fLaunchingVMProcess)
    3130         {
    3131             /* Note that the progress object is finalized later */
    3132             /** @todo Consider checking mData->mSession.mProgress for cancellation
    3133              *        around here.  */
    3134 
    3135             /* We don't reset mSession.mPid here because it is necessary for
    3136              * SessionMachine::uninit() to reap the child process later. */
    3137 
    3138             if (FAILED(rc))
    3139             {
    3140                 /* Close the remote session, remove the remote control from the list
    3141                  * and reset session state to Closed (@note keep the code in sync
    3142                  * with the relevant part in openSession()). */
    3143 
    3144                 Assert(mData->mSession.mRemoteControls.size() == 1);
    3145                 if (mData->mSession.mRemoteControls.size() == 1)
    3146                 {
    3147                     ErrorInfoKeeper eik;
    3148                     mData->mSession.mRemoteControls.front()->Uninitialize();
    3149                 }
    3150 
    3151                 mData->mSession.mRemoteControls.clear();
    3152                 mData->mSession.mState = SessionState_Unlocked;
    3153             }
    3154         }
    3155         else
    3156         {
    3157             /* memorize PID of the directly opened session */
    3158             if (SUCCEEDED(rc))
    3159                 mData->mSession.mPid = pid;
    3160         }
    3161 
    3162         if (SUCCEEDED(rc))
    3163         {
    3164             /* memorize the direct session control and cache IUnknown for it */
    3165             mData->mSession.mDirectControl = pSessionControl;
    3166             mData->mSession.mState = SessionState_Locked;
    3167             /* associate the SessionMachine with this Machine */
    3168             mData->mSession.mMachine = sessionMachine;
    3169 
    3170             /* request an IUnknown pointer early from the remote party for later
    3171              * identity checks (it will be internally cached within mDirectControl
    3172              * at least on XPCOM) */
    3173             ComPtr<IUnknown> unk = mData->mSession.mDirectControl;
    3174             NOREF(unk);
    3175         }
    3176 
    3177         /* Leave the lock since SessionMachine::uninit() locks VirtualBox which
    3178          * would break the lock order */
    3179         alock.leave();
    3180 
    3181         /* uninitialize the created session machine on failure */
    3182         if (FAILED(rc))
    3183             sessionMachine->uninit();
    3184 
    3185     }
    3186 
    3187     if (SUCCEEDED(rc))
    3188     {
    3189         /*
    3190         *  tell the client watcher thread to update the set of
    3191         *  machines that have open sessions
    3192         */
    3193         mParent->updateClientWatcher();
    3194 
    3195         if (oldState != SessionState_Locked)
    3196             /* fire an event */
    3197             mParent->onSessionStateChange(getId(), SessionState_Locked);
    3198     }
    3199 
    3200     return rc;
    3201 }
    3202 
    3203 /**
    3204  *  @note Locks objects!
    3205  */
    3206 STDMETHODIMP Machine::LaunchVMProcess(ISession *aSession,
    3207                                       IN_BSTR aType,
    3208                                       IN_BSTR aEnvironment,
    3209                                       IProgress **aProgress)
    3210 {
    3211     CheckComArgNotNull(aSession);
    3212     CheckComArgStrNotEmptyOrNull(aType);
    3213     CheckComArgOutSafeArrayPointerValid(aProgress);
    3214 
    3215     AutoCaller autoCaller(this);
    3216     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3217 
    3218     /* check the session state */
    3219     SessionState_T state;
    3220     HRESULT rc = aSession->COMGETTER(State)(&state);
    3221     if (FAILED(rc)) return rc;
    3222 
    3223     if (state != SessionState_Unlocked)
    3224         return setError(VBOX_E_INVALID_OBJECT_STATE,
    3225                         tr("The given session is busy"));
    3226 
    3227     /* get the IInternalSessionControl interface */
    3228     ComPtr<IInternalSessionControl> control = aSession;
    3229     ComAssertMsgRet(!!control, ("No IInternalSessionControl interface"),
    3230                       E_INVALIDARG);
    3231 
    3232     /* get the teleporter enable state for the progress object init. */
    3233     BOOL fTeleporterEnabled;
    3234     rc = COMGETTER(TeleporterEnabled)(&fTeleporterEnabled);
    3235     if (FAILED(rc))
    3236         return rc;
    3237 
    3238     /* create a progress object */
    3239     ComObjPtr<ProgressProxy> progress;
    3240     progress.createObject();
    3241     rc = progress->init(mParent,
    3242                         static_cast<IMachine*>(this),
    3243                         Bstr(tr("Spawning session")),
    3244                         TRUE /* aCancelable */,
    3245                         fTeleporterEnabled ? 20 : 10 /* uTotalOperationsWeight */,
    3246                         Bstr(tr("Spawning session")),
    3247                         2 /* uFirstOperationWeight */,
    3248                         fTeleporterEnabled ? 3 : 1 /* cOtherProgressObjectOperations */);
    3249     if (SUCCEEDED(rc))
    3250     {
    3251         rc = openRemoteSession(control, aType, aEnvironment, progress);
    3252         if (SUCCEEDED(rc))
    3253         {
    3254             progress.queryInterfaceTo(aProgress);
    3255 
    3256             /* signal the client watcher thread */
    3257             mParent->updateClientWatcher();
    3258 
    3259             /* fire an event */
    3260             mParent->onSessionStateChange(getId(), SessionState_Spawning);
    3261         }
    3262     }
    3263 
    3264     return rc;
    3265 }
    3266 
    3267 STDMETHODIMP Machine::SetBootOrder(ULONG aPosition, DeviceType_T aDevice)
    3268 {
    3269     if (aPosition < 1 || aPosition > SchemaDefs::MaxBootPosition)
    3270         return setError(E_INVALIDARG,
    3271                         tr("Invalid boot position: %lu (must be in range [1, %lu])"),
    3272                         aPosition, SchemaDefs::MaxBootPosition);
    3273 
    3274     if (aDevice == DeviceType_USB)
    3275         return setError(E_NOTIMPL,
    3276                         tr("Booting from USB device is currently not supported"));
    3277 
    3278     AutoCaller autoCaller(this);
    3279     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3280 
    3281     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    3282 
    3283     HRESULT rc = checkStateDependency(MutableStateDep);
    3284     if (FAILED(rc)) return rc;
    3285 
    3286     setModified(IsModified_MachineData);
    3287     mHWData.backup();
    3288     mHWData->mBootOrder[aPosition - 1] = aDevice;
    3289 
    3290     return S_OK;
    3291 }
    3292 
    3293 STDMETHODIMP Machine::GetBootOrder(ULONG aPosition, DeviceType_T *aDevice)
    3294 {
    3295     if (aPosition < 1 || aPosition > SchemaDefs::MaxBootPosition)
    3296         return setError(E_INVALIDARG,
    3297                        tr("Invalid boot position: %lu (must be in range [1, %lu])"),
    3298                        aPosition, SchemaDefs::MaxBootPosition);
    3299 
    3300     AutoCaller autoCaller(this);
    3301     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3302 
    3303     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3304 
    3305     *aDevice = mHWData->mBootOrder[aPosition - 1];
    3306 
    3307     return S_OK;
    3308 }
    3309 
    3310 STDMETHODIMP Machine::AttachDevice(IN_BSTR aControllerName,
    3311                                    LONG aControllerPort,
    3312                                    LONG aDevice,
    3313                                    DeviceType_T aType,
    3314                                    IMedium *aMedium)
    3315 {
    3316     LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%d aDevice=%d aType=%d aId=\"%ls\"\n",
    3317                      aControllerName, aControllerPort, aDevice, aType, aMedium));
    3318 
    3319     CheckComArgStrNotEmptyOrNull(aControllerName);
    3320 
    3321     AutoCaller autoCaller(this);
    3322     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3323 
    3324     // if this becomes true then we need to call saveSettings in the end
    3325     // @todo r=dj there is no error handling so far...
    3326     bool fNeedsGlobalSaveSettings = false;
    3327 
    3328     // request the host lock first, since might be calling Host methods for getting host drives;
    3329     // next, protect the media tree all the while we're in here, as well as our member variables
    3330     AutoMultiWriteLock2 alock(mParent->host()->lockHandle(),
    3331                               this->lockHandle() COMMA_LOCKVAL_SRC_POS);
    3332     AutoWriteLock treeLock(&mParent->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
    3333 
    3334     HRESULT rc = checkStateDependency(MutableStateDep);
    3335     if (FAILED(rc)) return rc;
    3336 
    3337     /// @todo NEWMEDIA implicit machine registration
    3338     if (!mData->mRegistered)
    3339         return setError(VBOX_E_INVALID_OBJECT_STATE,
    3340                         tr("Cannot attach storage devices to an unregistered machine"));
    3341 
    3342     AssertReturn(mData->mMachineState != MachineState_Saved, E_FAIL);
    3343 
    3344     if (Global::IsOnlineOrTransient(mData->mMachineState))
    3345         return setError(VBOX_E_INVALID_VM_STATE,
    3346                         tr("Invalid machine state: %s"),
    3347                         Global::stringifyMachineState(mData->mMachineState));
    3348 
    3349     /* Check for an existing controller. */
    3350     ComObjPtr<StorageController> ctl;
    3351     rc = getStorageControllerByName(aControllerName, ctl, true /* aSetError */);
    3352     if (FAILED(rc)) return rc;
    3353 
    3354     // check that the port and device are not out of range
    3355     rc = ctl->checkPortAndDeviceValid(aControllerPort, aDevice);
    3356     if (FAILED(rc)) return rc;
    3357 
    3358     /* check if the device slot is already busy */
    3359     MediumAttachment *pAttachTemp;
    3360     if ((pAttachTemp = findAttachment(mMediaData->mAttachments,
    3361                                       aControllerName,
    3362                                       aControllerPort,
    3363                                       aDevice)))
    3364     {
    3365         Medium *pMedium = pAttachTemp->getMedium();
    3366         if (pMedium)
    3367         {
    3368             AutoReadLock mediumLock(pMedium COMMA_LOCKVAL_SRC_POS);
    3369             return setError(VBOX_E_OBJECT_IN_USE,
    3370                             tr("Medium '%s' is already attached to port %d, device %d of controller '%ls' of this virtual machine"),
    3371                             pMedium->getLocationFull().c_str(),
    3372                             aControllerPort,
    3373                             aDevice,
    3374                             aControllerName);
    3375         }
    3376         else
    3377             return setError(VBOX_E_OBJECT_IN_USE,
    3378                             tr("Device is already attached to port %d, device %d of controller '%ls' of this virtual machine"),
    3379                             aControllerPort, aDevice, aControllerName);
    3380     }
    3381 
    3382     ComObjPtr<Medium> medium = static_cast<Medium*>(aMedium);
    3383     if (aMedium && medium.isNull())
    3384         return setError(E_INVALIDARG, "The given medium pointer is invalid");
    3385 
    3386     AutoCaller mediumCaller(medium);
    3387     if (FAILED(mediumCaller.rc())) return mediumCaller.rc();
    3388 
    3389     AutoWriteLock mediumLock(medium COMMA_LOCKVAL_SRC_POS);
    3390 
    3391     if (    (pAttachTemp = findAttachment(mMediaData->mAttachments, medium))
    3392          && !medium.isNull()
    3393        )
    3394         return setError(VBOX_E_OBJECT_IN_USE,
    3395                         tr("Medium '%s' is already attached to this virtual machine"),
    3396                         medium->getLocationFull().c_str());
    3397 
    3398     bool fIndirect = false;
    3399     if (!medium.isNull())
    3400         fIndirect = medium->isReadOnly();
    3401     bool associate = true;
    3402 
    3403     do
    3404     {
    3405         if (    aType == DeviceType_HardDisk
    3406              && mMediaData.isBackedUp())
    3407         {
    3408             const MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments;
    3409 
    3410             /* check if the medium was attached to the VM before we started
    3411              * changing attachments in which case the attachment just needs to
    3412              * be restored */
    3413             if ((pAttachTemp = findAttachment(oldAtts, medium)))
    3414             {
    3415                 AssertReturn(!fIndirect, E_FAIL);
    3416 
    3417                 /* see if it's the same bus/channel/device */
    3418                 if (pAttachTemp->matches(aControllerName, aControllerPort, aDevice))
    3419                 {
    3420                     /* the simplest case: restore the whole attachment
    3421                      * and return, nothing else to do */
    3422                     mMediaData->mAttachments.push_back(pAttachTemp);
    3423                     return S_OK;
    3424                 }
    3425 
    3426                 /* bus/channel/device differ; we need a new attachment object,
    3427                  * but don't try to associate it again */
    3428                 associate = false;
    3429                 break;
    3430             }
    3431         }
    3432 
    3433         /* go further only if the attachment is to be indirect */
    3434         if (!fIndirect)
    3435             break;
    3436 
    3437         /* perform the so called smart attachment logic for indirect
    3438          * attachments. Note that smart attachment is only applicable to base
    3439          * hard disks. */
    3440 
    3441         if (medium->getParent().isNull())
    3442         {
    3443             /* first, investigate the backup copy of the current hard disk
    3444              * attachments to make it possible to re-attach existing diffs to
    3445              * another device slot w/o losing their contents */
    3446             if (mMediaData.isBackedUp())
    3447             {
    3448                 const MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments;
    3449 
    3450                 MediaData::AttachmentList::const_iterator foundIt = oldAtts.end();
    3451                 uint32_t foundLevel = 0;
    3452 
    3453                 for (MediaData::AttachmentList::const_iterator it = oldAtts.begin();
    3454                      it != oldAtts.end();
    3455                      ++it)
    3456                 {
    3457                     uint32_t level = 0;
    3458                     MediumAttachment *pAttach = *it;
    3459                     ComObjPtr<Medium> pMedium = pAttach->getMedium();
    3460                     Assert(!pMedium.isNull() || pAttach->getType() != DeviceType_HardDisk);
    3461                     if (pMedium.isNull())
    3462                         continue;
    3463 
    3464                     if (pMedium->getBase(&level) == medium)
    3465                     {
    3466                         /* skip the hard disk if its currently attached (we
    3467                          * cannot attach the same hard disk twice) */
    3468                         if (findAttachment(mMediaData->mAttachments,
    3469                                            pMedium))
    3470                             continue;
    3471 
    3472                         /* matched device, channel and bus (i.e. attached to the
    3473                          * same place) will win and immediately stop the search;
    3474                          * otherwise the attachment that has the youngest
    3475                          * descendant of medium will be used
    3476                          */
    3477                         if (pAttach->matches(aControllerName, aControllerPort, aDevice))
    3478                         {
    3479                             /* the simplest case: restore the whole attachment
    3480                              * and return, nothing else to do */
    3481                             mMediaData->mAttachments.push_back(*it);
    3482                             return S_OK;
    3483                         }
    3484                         else if (    foundIt == oldAtts.end()
    3485                                   || level > foundLevel /* prefer younger */
    3486                                 )
    3487                         {
    3488                             foundIt = it;
    3489                             foundLevel = level;
    3490                         }
    3491                     }
    3492                 }
    3493 
    3494                 if (foundIt != oldAtts.end())
    3495                 {
    3496                     /* use the previously attached hard disk */
    3497                     medium = (*foundIt)->getMedium();
    3498                     mediumCaller.attach(medium);
    3499                     if (FAILED(mediumCaller.rc())) return mediumCaller.rc();
    3500                     mediumLock.attach(medium);
    3501                     /* not implicit, doesn't require association with this VM */
    3502                     fIndirect = false;
    3503                     associate = false;
    3504                     /* go right to the MediumAttachment creation */
    3505                     break;
    3506                 }
    3507             }
    3508 
    3509             /* must give up the medium lock and medium tree lock as below we
    3510              * go over snapshots, which needs a lock with higher lock order. */
    3511             mediumLock.release();
    3512             treeLock.release();
    3513 
    3514             /* then, search through snapshots for the best diff in the given
    3515              * hard disk's chain to base the new diff on */
    3516 
    3517             ComObjPtr<Medium> base;
    3518             ComObjPtr<Snapshot> snap = mData->mCurrentSnapshot;
    3519             while (snap)
    3520             {
    3521                 AutoReadLock snapLock(snap COMMA_LOCKVAL_SRC_POS);
    3522 
    3523                 const MediaData::AttachmentList &snapAtts = snap->getSnapshotMachine()->mMediaData->mAttachments;
    3524 
    3525                 MediumAttachment *pAttachFound = NULL;
    3526                 uint32_t foundLevel = 0;
    3527 
    3528                 for (MediaData::AttachmentList::const_iterator it = snapAtts.begin();
    3529                      it != snapAtts.end();
    3530                      ++it)
    3531                 {
    3532                     MediumAttachment *pAttach = *it;
    3533                     ComObjPtr<Medium> pMedium = pAttach->getMedium();
    3534                     Assert(!pMedium.isNull() || pAttach->getType() != DeviceType_HardDisk);
    3535                     if (pMedium.isNull())
    3536                         continue;
    3537 
    3538                     uint32_t level = 0;
    3539                     if (pMedium->getBase(&level) == medium)
    3540                     {
    3541                         /* matched device, channel and bus (i.e. attached to the
    3542                          * same place) will win and immediately stop the search;
    3543                          * otherwise the attachment that has the youngest
    3544                          * descendant of medium will be used
    3545                          */
    3546                         if (    pAttach->getDevice() == aDevice
    3547                              && pAttach->getPort() == aControllerPort
    3548                              && pAttach->getControllerName() == aControllerName
    3549                            )
    3550                         {
    3551                             pAttachFound = pAttach;
    3552                             break;
    3553                         }
    3554                         else if (    !pAttachFound
    3555                                   || level > foundLevel /* prefer younger */
    3556                                 )
    3557                         {
    3558                             pAttachFound = pAttach;
    3559                             foundLevel = level;
    3560                         }
    3561                     }
    3562                 }
    3563 
    3564                 if (pAttachFound)
    3565                 {
    3566                     base = pAttachFound->getMedium();
    3567                     break;
    3568                 }
    3569 
    3570                 snap = snap->getParent();
    3571             }
    3572 
    3573             /* re-lock medium tree and the medium, as we need it below */
    3574             treeLock.acquire();
    3575             mediumLock.acquire();
    3576 
    3577             /* found a suitable diff, use it as a base */
    3578             if (!base.isNull())
    3579             {
    3580                 medium = base;
    3581                 mediumCaller.attach(medium);
    3582                 if (FAILED(mediumCaller.rc())) return mediumCaller.rc();
    3583                 mediumLock.attach(medium);
    3584             }
    3585         }
    3586 
    3587         ComObjPtr<Medium> diff;
    3588         diff.createObject();
    3589         rc = diff->init(mParent,
    3590                         medium->getPreferredDiffFormat(),
    3591                         Utf8Str(mUserData->m_strSnapshotFolderFull).append(RTPATH_SLASH_STR),
    3592                         medium->getRegistryMachineId(),         // store this diff in the same registry as the parent
    3593                         &fNeedsGlobalSaveSettings);
    3594         if (FAILED(rc)) return rc;
    3595 
    3596         /* Apply the normal locking logic to the entire chain. */
    3597         MediumLockList *pMediumLockList(new MediumLockList());
    3598         rc = diff->createMediumLockList(true /* fFailIfInaccessible */,
    3599                                         true /* fMediumLockWrite */,
    3600                                         medium,
    3601                                         *pMediumLockList);
    3602         if (SUCCEEDED(rc))
    3603         {
    3604             rc = pMediumLockList->Lock();
    3605             if (FAILED(rc))
    3606                 setError(rc,
    3607                          tr("Could not lock medium when creating diff '%s'"),
    3608                          diff->getLocationFull().c_str());
    3609             else
    3610             {
    3611                 /* will leave the lock before the potentially lengthy operation, so
    3612                  * protect with the special state */
    3613                 MachineState_T oldState = mData->mMachineState;
    3614                 setMachineState(MachineState_SettingUp);
    3615 
    3616                 mediumLock.leave();
    3617                 treeLock.leave();
    3618                 alock.leave();
    3619 
    3620                 rc = medium->createDiffStorage(diff,
    3621                                                MediumVariant_Standard,
    3622                                                pMediumLockList,
    3623                                                NULL /* aProgress */,
    3624                                                true /* aWait */,
    3625                                                &fNeedsGlobalSaveSettings);
    3626 
    3627                 alock.enter();
    3628                 treeLock.enter();
    3629                 mediumLock.enter();
    3630 
    3631                 setMachineState(oldState);
    3632             }
    3633         }
    3634 
    3635         /* Unlock the media and free the associated memory. */
    3636         delete pMediumLockList;
    3637 
    3638         if (FAILED(rc)) return rc;
    3639 
    3640         /* use the created diff for the actual attachment */
    3641         medium = diff;
    3642         mediumCaller.attach(medium);
    3643         if (FAILED(mediumCaller.rc())) return mediumCaller.rc();
    3644         mediumLock.attach(medium);
    3645     }
    3646     while (0);
    3647 
    3648     ComObjPtr<MediumAttachment> attachment;
    3649     attachment.createObject();
    3650     rc = attachment->init(this,
    3651                           medium,
    3652                           aControllerName,
    3653                           aControllerPort,
    3654                           aDevice,
    3655                           aType,
    3656                           fIndirect,
    3657                           0 /* No bandwidth limit */);
    3658     if (FAILED(rc)) return rc;
    3659 
    3660     if (associate && !medium.isNull())
    3661     {
    3662         // as the last step, associate the medium to the VM
    3663         rc = medium->addBackReference(mData->mUuid);
    3664         // here we can fail because of Deleting, or being in process of creating a Diff
    3665         if (FAILED(rc)) return rc;
    3666 
    3667         // and decide which medium registry to use now that the medium is attached:
    3668         if (mData->pMachineConfigFile->canHaveOwnMediaRegistry())
    3669             // machine XML is VirtualBox 4.0 or higher:
    3670             medium->setRegistryIdIfFirst(getId());        // machine UUID
    3671         else
    3672             medium->setRegistryIdIfFirst(mParent->getGlobalRegistryId()); // VirtualBox global registry UUID
    3673     }
    3674 
    3675     /* success: finally remember the attachment */
    3676     setModified(IsModified_Storage);
    3677     mMediaData.backup();
    3678     mMediaData->mAttachments.push_back(attachment);
    3679 
    3680     if (fNeedsGlobalSaveSettings)
    3681     {
    3682         // save the global settings; for that we should hold only the VirtualBox lock
    3683         mediumLock.release();
    3684         treeLock.leave();
    3685         alock.release();
    3686 
    3687         AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS);
    3688         mParent->saveSettings();
    3689     }
    3690 
    3691     return rc;
    3692 }
    3693 
    3694 STDMETHODIMP Machine::DetachDevice(IN_BSTR aControllerName, LONG aControllerPort,
    3695                                    LONG aDevice)
    3696 {
    3697     CheckComArgStrNotEmptyOrNull(aControllerName);
    3698 
    3699     LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%ld aDevice=%ld\n",
    3700                      aControllerName, aControllerPort, aDevice));
    3701 
    3702     AutoCaller autoCaller(this);
    3703     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3704 
    3705     bool fNeedsSaveSettings = false;
    3706 
    3707     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    3708 
    3709     HRESULT rc = checkStateDependency(MutableStateDep);
    3710     if (FAILED(rc)) return rc;
    3711 
    3712     AssertReturn(mData->mMachineState != MachineState_Saved, E_FAIL);
    3713 
    3714     if (Global::IsOnlineOrTransient(mData->mMachineState))
    3715         return setError(VBOX_E_INVALID_VM_STATE,
    3716                         tr("Invalid machine state: %s"),
    3717                         Global::stringifyMachineState(mData->mMachineState));
    3718 
    3719     MediumAttachment *pAttach = findAttachment(mMediaData->mAttachments,
    3720                                                aControllerName,
    3721                                                aControllerPort,
    3722                                                aDevice);
    3723     if (!pAttach)
    3724         return setError(VBOX_E_OBJECT_NOT_FOUND,
    3725                         tr("No storage device attached to device slot %d on port %d of controller '%ls'"),
    3726                         aDevice, aControllerPort, aControllerName);
    3727 
    3728     rc = detachDevice(pAttach, alock, NULL /* pSnapshot */, &fNeedsSaveSettings);
    3729 
    3730     if (fNeedsSaveSettings)
    3731     {
    3732         bool fNeedsGlobalSaveSettings = false;
    3733         saveSettings(&fNeedsGlobalSaveSettings);
    3734 
    3735         if (fNeedsGlobalSaveSettings)
    3736         {
    3737             // save the global settings; for that we should hold only the VirtualBox lock
    3738             alock.release();
    3739             AutoWriteLock vboxlock(this COMMA_LOCKVAL_SRC_POS);
    3740             mParent->saveSettings();
    3741         }
    3742     }
    3743 
    3744     return S_OK;
    3745 }
    3746 
    3747 STDMETHODIMP Machine::PassthroughDevice(IN_BSTR aControllerName, LONG aControllerPort,
    3748                                         LONG aDevice, BOOL aPassthrough)
    3749 {
    3750     CheckComArgStrNotEmptyOrNull(aControllerName);
    3751 
    3752     LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%ld aDevice=%ld aPassthrough=%d\n",
    3753                      aControllerName, aControllerPort, aDevice, aPassthrough));
    3754 
    3755     AutoCaller autoCaller(this);
    3756     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3757 
    3758     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    3759 
    3760     HRESULT rc = checkStateDependency(MutableStateDep);
    3761     if (FAILED(rc)) return rc;
    3762 
    3763     AssertReturn(mData->mMachineState != MachineState_Saved, E_FAIL);
    3764 
    3765     if (Global::IsOnlineOrTransient(mData->mMachineState))
    3766         return setError(VBOX_E_INVALID_VM_STATE,
    3767                         tr("Invalid machine state: %s"),
    3768                         Global::stringifyMachineState(mData->mMachineState));
    3769 
    3770     MediumAttachment *pAttach = findAttachment(mMediaData->mAttachments,
    3771                                                aControllerName,
    3772                                                aControllerPort,
    3773                                                aDevice);
    3774     if (!pAttach)
    3775         return setError(VBOX_E_OBJECT_NOT_FOUND,
    3776                         tr("No storage device attached to device slot %d on port %d of controller '%ls'"),
    3777                         aDevice, aControllerPort, aControllerName);
    3778 
    3779 
    3780     setModified(IsModified_Storage);
    3781     mMediaData.backup();
    3782 
    3783     AutoWriteLock attLock(pAttach COMMA_LOCKVAL_SRC_POS);
    3784 
    3785     if (pAttach->getType() != DeviceType_DVD)
    3786         return setError(E_INVALIDARG,
    3787                         tr("Setting passthrough rejected as the device attached to device slot %d on port %d of controller '%ls' is not a DVD"),
    3788                         aDevice, aControllerPort, aControllerName);
    3789     pAttach->updatePassthrough(!!aPassthrough);
    3790 
    3791     return S_OK;
    3792 }
    3793 
    3794 STDMETHODIMP Machine::MountMedium(IN_BSTR aControllerName,
    3795                                   LONG aControllerPort,
    3796                                   LONG aDevice,
    3797                                   IN_BSTR aId,
    3798                                   BOOL aForce)
    3799 {
    3800     int rc = S_OK;
    3801     LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%ld aDevice=%ld aForce=%d\n",
    3802                      aControllerName, aControllerPort, aDevice, aForce));
    3803 
    3804     CheckComArgStrNotEmptyOrNull(aControllerName);
    3805 
    3806     AutoCaller autoCaller(this);
    3807     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3808 
    3809     // we're calling host methods for getting DVD and floppy drives so lock host first
    3810     AutoMultiWriteLock2 alock(mParent->host(), this COMMA_LOCKVAL_SRC_POS);
    3811 
    3812     ComObjPtr<MediumAttachment> pAttach = findAttachment(mMediaData->mAttachments,
    3813                                                          aControllerName,
    3814                                                          aControllerPort,
    3815                                                          aDevice);
    3816     if (pAttach.isNull())
    3817         return setError(VBOX_E_OBJECT_NOT_FOUND,
    3818                         tr("No drive attached to device slot %d on port %d of controller '%ls'"),
    3819                         aDevice, aControllerPort, aControllerName);
    3820 
    3821     /* Remember previously mounted medium. The medium before taking the
    3822      * backup is not necessarily the same thing. */
    3823     ComObjPtr<Medium> oldmedium;
    3824     oldmedium = pAttach->getMedium();
    3825 
    3826     Guid uuid(aId);
    3827     ComObjPtr<Medium> medium;
    3828     DeviceType_T mediumType = pAttach->getType();
    3829     switch (mediumType)
    3830     {
    3831         case DeviceType_DVD:
    3832         case DeviceType_Floppy:
    3833             rc = mParent->findRemoveableMedium(mediumType, uuid, true /* fRefresh */, medium);
    3834             if (FAILED(rc)) return rc;
    3835         break;
    3836 
    3837         default:
    3838             return setError(VBOX_E_INVALID_OBJECT_STATE,
    3839                             tr("Cannot change medium attached to device slot %d on port %d of controller '%ls'"),
    3840                             aDevice, aControllerPort, aControllerName);
    3841     }
    3842 
    3843     if (SUCCEEDED(rc))
    3844     {
    3845         setModified(IsModified_Storage);
    3846         mMediaData.backup();
    3847 
    3848         /* The backup operation makes the pAttach reference point to the
    3849          * old settings. Re-get the correct reference. */
    3850         pAttach = findAttachment(mMediaData->mAttachments,
    3851                                  aControllerName,
    3852                                  aControllerPort,
    3853                                  aDevice);
    3854         AutoWriteLock attLock(pAttach COMMA_LOCKVAL_SRC_POS);
    3855         /* For non-hard disk media, detach straight away. */
    3856         if (mediumType != DeviceType_HardDisk && !oldmedium.isNull())
    3857             oldmedium->removeBackReference(mData->mUuid);
    3858         if (!medium.isNull())
    3859             medium->addBackReference(mData->mUuid);
    3860         pAttach->updateMedium(medium, false /* aImplicit */);
    3861         setModified(IsModified_Storage);
    3862     }
    3863 
    3864     alock.leave();
    3865     rc = onMediumChange(pAttach, aForce);
    3866     alock.enter();
    3867 
    3868     /* On error roll back this change only. */
    3869     if (FAILED(rc))
    3870     {
    3871         if (!medium.isNull())
    3872             medium->removeBackReference(mData->mUuid);
    3873         pAttach = findAttachment(mMediaData->mAttachments,
    3874                                  aControllerName,
    3875                                  aControllerPort,
    3876                                  aDevice);
    3877         /* If the attachment is gone in the mean time, bail out. */
    3878         if (pAttach.isNull())
    3879             return rc;
    3880         AutoWriteLock attLock(pAttach COMMA_LOCKVAL_SRC_POS);
    3881         /* For non-hard disk media, re-attach straight away. */
    3882         if (mediumType != DeviceType_HardDisk && !oldmedium.isNull())
    3883             oldmedium->addBackReference(mData->mUuid);
    3884         pAttach->updateMedium(oldmedium, false /* aImplicit */);
    3885     }
    3886 
    3887     return rc;
    3888 }
    3889 
    3890 STDMETHODIMP Machine::GetMedium(IN_BSTR aControllerName,
    3891                                 LONG aControllerPort,
    3892                                 LONG aDevice,
    3893                                 IMedium **aMedium)
    3894 {
    3895     LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%ld aDevice=%ld\n",
    3896                      aControllerName, aControllerPort, aDevice));
    3897 
    3898     CheckComArgStrNotEmptyOrNull(aControllerName);
    3899     CheckComArgOutPointerValid(aMedium);
    3900 
    3901     AutoCaller autoCaller(this);
    3902     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3903 
    3904     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3905 
    3906     *aMedium = NULL;
    3907 
    3908     ComObjPtr<MediumAttachment> pAttach = findAttachment(mMediaData->mAttachments,
    3909                                                          aControllerName,
    3910                                                          aControllerPort,
    3911                                                          aDevice);
    3912     if (pAttach.isNull())
    3913         return setError(VBOX_E_OBJECT_NOT_FOUND,
    3914                         tr("No storage device attached to device slot %d on port %d of controller '%ls'"),
    3915                         aDevice, aControllerPort, aControllerName);
    3916 
    3917     pAttach->getMedium().queryInterfaceTo(aMedium);
    3918 
    3919     return S_OK;
    3920 }
    3921 
    3922 STDMETHODIMP Machine::GetSerialPort(ULONG slot, ISerialPort **port)
    3923 {
    3924     CheckComArgOutPointerValid(port);
    3925     CheckComArgExpr(slot, slot < RT_ELEMENTS(mSerialPorts));
    3926 
    3927     AutoCaller autoCaller(this);
    3928     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3929 
    3930     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3931 
    3932     mSerialPorts[slot].queryInterfaceTo(port);
    3933 
    3934     return S_OK;
    3935 }
    3936 
    3937 STDMETHODIMP Machine::GetParallelPort(ULONG slot, IParallelPort **port)
    3938 {
    3939     CheckComArgOutPointerValid(port);
    3940     CheckComArgExpr(slot, slot < RT_ELEMENTS(mParallelPorts));
    3941 
    3942     AutoCaller autoCaller(this);
    3943     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3944 
    3945     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3946 
    3947     mParallelPorts[slot].queryInterfaceTo(port);
    3948 
    3949     return S_OK;
    3950 }
    3951 
    3952 STDMETHODIMP Machine::GetNetworkAdapter(ULONG slot, INetworkAdapter **adapter)
    3953 {
    3954     CheckComArgOutPointerValid(adapter);
    3955     CheckComArgExpr(slot, slot < RT_ELEMENTS(mNetworkAdapters));
    3956 
    3957     AutoCaller autoCaller(this);
    3958     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3959 
    3960     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3961 
    3962     mNetworkAdapters[slot].queryInterfaceTo(adapter);
    3963 
    3964     return S_OK;
    3965 }
    3966 
    3967 STDMETHODIMP Machine::GetExtraDataKeys(ComSafeArrayOut(BSTR, aKeys))
    3968 {
    3969     if (ComSafeArrayOutIsNull(aKeys))
    3970         return E_POINTER;
    3971 
    3972     AutoCaller autoCaller(this);
    3973     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3974 
    3975     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3976 
    3977     com::SafeArray<BSTR> saKeys(mData->pMachineConfigFile->mapExtraDataItems.size());
    3978     int i = 0;
    3979     for (settings::StringsMap::const_iterator it = mData->pMachineConfigFile->mapExtraDataItems.begin();
    3980          it != mData->pMachineConfigFile->mapExtraDataItems.end();
    3981          ++it, ++i)
    3982     {
    3983         const Utf8Str &strKey = it->first;
    3984         strKey.cloneTo(&saKeys[i]);
    3985     }
    3986     saKeys.detachTo(ComSafeArrayOutArg(aKeys));
    3987 
    3988     return S_OK;
    3989   }
    3990 
    3991   /**
    3992    *  @note Locks this object for reading.
    3993    */
    3994 STDMETHODIMP Machine::GetExtraData(IN_BSTR aKey,
    3995                                    BSTR *aValue)
    3996 {
    3997     CheckComArgStrNotEmptyOrNull(aKey);
    3998     CheckComArgOutPointerValid(aValue);
    3999 
    4000     AutoCaller autoCaller(this);
    4001     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4002 
    4003     /* start with nothing found */
    4004     Bstr bstrResult("");
    4005 
    4006     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4007 
    4008     settings::StringsMap::const_iterator it = mData->pMachineConfigFile->mapExtraDataItems.find(Utf8Str(aKey));
    4009     if (it != mData->pMachineConfigFile->mapExtraDataItems.end())
    4010         // found:
    4011         bstrResult = it->second; // source is a Utf8Str
    4012 
    4013     /* return the result to caller (may be empty) */
    4014     bstrResult.cloneTo(aValue);
    4015 
    4016     return S_OK;
    4017 }
    4018 
    4019   /**
    4020    *  @note Locks mParent for writing + this object for writing.
    4021    */
    4022 STDMETHODIMP Machine::SetExtraData(IN_BSTR aKey, IN_BSTR aValue)
    4023 {
    4024     CheckComArgStrNotEmptyOrNull(aKey);
    4025 
    4026     AutoCaller autoCaller(this);
    4027     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4028 
    4029     Utf8Str strKey(aKey);
    4030     Utf8Str strValue(aValue);
    4031     Utf8Str strOldValue;            // empty
    4032 
    4033     // locking note: we only hold the read lock briefly to look up the old value,
    4034     // then release it and call the onExtraCanChange callbacks. There is a small
    4035     // chance of a race insofar as the callback might be called twice if two callers
    4036     // change the same key at the same time, but that's a much better solution
    4037     // than the deadlock we had here before. The actual changing of the extradata
    4038     // is then performed under the write lock and race-free.
    4039 
    4040     // look up the old value first; if nothing's changed then we need not do anything
    4041     {
    4042         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); // hold read lock only while looking up
    4043         settings::StringsMap::const_iterator it = mData->pMachineConfigFile->mapExtraDataItems.find(strKey);
    4044         if (it != mData->pMachineConfigFile->mapExtraDataItems.end())
    4045             strOldValue = it->second;
    4046     }
    4047 
    4048     bool fChanged;
    4049     if ((fChanged = (strOldValue != strValue)))
    4050     {
    4051         // ask for permission from all listeners outside the locks;
    4052         // onExtraDataCanChange() only briefly requests the VirtualBox
    4053         // lock to copy the list of callbacks to invoke
    4054         Bstr error;
    4055         Bstr bstrValue(aValue);
    4056 
    4057         if (!mParent->onExtraDataCanChange(mData->mUuid, aKey, bstrValue, error))
    4058         {
    4059             const char *sep = error.isEmpty() ? "" : ": ";
    4060             CBSTR err = error.raw();
    4061             LogWarningFunc(("Someone vetoed! Change refused%s%ls\n",
    4062                             sep, err));
    4063             return setError(E_ACCESSDENIED,
    4064                             tr("Could not set extra data because someone refused the requested change of '%ls' to '%ls'%s%ls"),
    4065                             aKey,
    4066                             bstrValue.raw(),
    4067                             sep,
    4068                             err);
    4069         }
    4070 
    4071         // data is changing and change not vetoed: then write it out under the lock
    4072         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    4073 
    4074         if (isSnapshotMachine())
    4075         {
    4076             HRESULT rc = checkStateDependency(MutableStateDep);
    4077             if (FAILED(rc)) return rc;
    4078         }
    4079 
    4080         if (strValue.isEmpty())
    4081             mData->pMachineConfigFile->mapExtraDataItems.erase(strKey);
    4082         else
    4083             mData->pMachineConfigFile->mapExtraDataItems[strKey] = strValue;
    4084                 // creates a new key if needed
    4085 
    4086         bool fNeedsGlobalSaveSettings = false;
    4087         saveSettings(&fNeedsGlobalSaveSettings);
    4088 
    4089         if (fNeedsGlobalSaveSettings)
    4090         {
    4091             // save the global settings; for that we should hold only the VirtualBox lock
    4092             alock.release();
    4093             AutoWriteLock vboxlock(mParent COMMA_LOCKVAL_SRC_POS);
    4094             mParent->saveSettings();
    4095         }
    4096     }
    4097 
    4098     // fire notification outside the lock
    4099     if (fChanged)
    4100         mParent->onExtraDataChange(mData->mUuid, aKey, aValue);
    4101 
    4102     return S_OK;
    4103 }
    4104 
    4105 STDMETHODIMP Machine::SaveSettings()
    4106 {
    4107     AutoCaller autoCaller(this);
    4108     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4109 
    4110     AutoWriteLock mlock(this COMMA_LOCKVAL_SRC_POS);
    4111 
    4112     /* when there was auto-conversion, we want to save the file even if
    4113      * the VM is saved */
    4114     HRESULT rc = checkStateDependency(MutableStateDep);
    4115     if (FAILED(rc)) return rc;
    4116 
    4117     /* the settings file path may never be null */
    4118     ComAssertRet(!mData->m_strConfigFileFull.isEmpty(), E_FAIL);
    4119 
    4120     /* save all VM data excluding snapshots */
    4121     bool fNeedsGlobalSaveSettings = false;
    4122     rc = saveSettings(&fNeedsGlobalSaveSettings);
    4123     mlock.release();
    4124 
    4125     if (SUCCEEDED(rc) && fNeedsGlobalSaveSettings)
    4126     {
    4127         // save the global settings; for that we should hold only the VirtualBox lock
    4128         AutoWriteLock vlock(mParent COMMA_LOCKVAL_SRC_POS);
    4129         rc = mParent->saveSettings();
    4130     }
    4131 
    4132     return rc;
    4133 }
    4134 
    4135 STDMETHODIMP Machine::DiscardSettings()
    4136 {
    4137     AutoCaller autoCaller(this);
    4138     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4139 
    4140     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    4141 
    4142     HRESULT rc = checkStateDependency(MutableStateDep);
    4143     if (FAILED(rc)) return rc;
    4144 
    4145     /*
    4146      *  during this rollback, the session will be notified if data has
    4147      *  been actually changed
    4148      */
    4149     rollback(true /* aNotify */);
    4150 
    4151     return S_OK;
    4152 }
    4153 
    4154 /** @note Locks objects! */
    4155 STDMETHODIMP Machine::Unregister(CleanupMode_T cleanupMode,
    4156                                  ComSafeArrayOut(IMedium*, aMedia))
    4157 {
    4158     // use AutoLimitedCaller because this call is valid on inaccessible machines as well
    4159     AutoLimitedCaller autoCaller(this);
    4160     AssertComRCReturnRC(autoCaller.rc());
    4161 
    4162     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    4163 
    4164     Guid id(getId());
    4165 
    4166     if (mData->mSession.mState != SessionState_Unlocked)
    4167         return setError(VBOX_E_INVALID_OBJECT_STATE,
    4168                         tr("Cannot unregister the machine '%s' while it is locked"),
    4169                         mUserData->s.strName.c_str());
    4170 
    4171     // wait for state dependants to drop to zero
    4172     ensureNoStateDependencies();
    4173 
    4174     if (!mData->mAccessible)
    4175     {
    4176         // inaccessible maschines can only be unregistered; uninitialize ourselves
    4177         // here because currently there may be no unregistered that are inaccessible
    4178         // (this state combination is not supported). Note releasing the caller and
    4179         // leaving the lock before alling uninit()
    4180         alock.leave();
    4181         autoCaller.release();
    4182 
    4183         uninit();
    4184 
    4185         mParent->unregisterMachine(this, id);
    4186             // calls VirtualBox::saveSettings()
    4187 
    4188         return S_OK;
    4189     }
    4190 
    4191     HRESULT rc = S_OK;
    4192 
    4193     // discard saved state
    4194     if (mData->mMachineState == MachineState_Saved)
    4195     {
    4196         // add the saved state file to the list of files the caller should delete
    4197         Assert(!mSSData->mStateFilePath.isEmpty());
    4198         mData->llFilesToDelete.push_back(mSSData->mStateFilePath);
    4199 
    4200         mSSData->mStateFilePath.setNull();
    4201 
    4202         // unconditionally set the machine state to powered off, we now
    4203         // know no session has locked the machine
    4204         mData->mMachineState = MachineState_PoweredOff;
    4205     }
    4206 
    4207     size_t cSnapshots = 0;
    4208     if (mData->mFirstSnapshot)
    4209         cSnapshots = mData->mFirstSnapshot->getAllChildrenCount() + 1;
    4210     if (cSnapshots && cleanupMode == CleanupMode_UnregisterOnly)
    4211         // fail now before we start detaching media
    4212         return setError(VBOX_E_INVALID_OBJECT_STATE,
    4213                         tr("Cannot unregister the machine '%s' because it has %d snapshots"),
    4214                            mUserData->s.strName.c_str(), cSnapshots);
    4215 
    4216     // this list collects the medium objects from all medium attachments
    4217     // which got detached from the machine and its snapshots, in the following
    4218     // order:
    4219     // 1) media from machine attachments (these have the "leaf" attachments with snapshots
    4220     //    and must be closed first, or closing the parents will fail because they will
    4221     //    children);
    4222     // 2) media from the youngest snapshots followed those from the parent snapshots until
    4223     //    the root ("first") snapshot of the machine
    4224     // This order allows for closing the media on this list from the beginning to the end
    4225     // without getting "media in use" errors.
    4226     MediaList llMedia;
    4227 
    4228     if (    !mMediaData.isNull()      // can be NULL if machine is inaccessible
    4229          && mMediaData->mAttachments.size()
    4230        )
    4231     {
    4232         // we have media attachments: detach them all and add the Medium objects to our list
    4233         if (cleanupMode != CleanupMode_UnregisterOnly)
    4234             detachAllMedia(alock, NULL /* pSnapshot */, cleanupMode, llMedia);
    4235         else
    4236             return setError(VBOX_E_INVALID_OBJECT_STATE,
    4237                             tr("Cannot unregister the machine '%s' because it has %d media attachments"),
    4238                             mUserData->s.strName.c_str(), mMediaData->mAttachments.size());
    4239     }
    4240 
    4241     if (cSnapshots)
    4242     {
    4243         // autoCleanup must be true here, or we would have failed above
    4244 
    4245         // add the media from the medium attachments of the snapshots to llMedia
    4246         // as well, after the "main" machine media; Snapshot::uninitRecursively()
    4247         // calls Machine::detachAllMedia() for the snapshot machine, recursing
    4248         // into the children first
    4249 
    4250         // Snapshot::beginDeletingSnapshot() asserts if the machine state is not this
    4251         MachineState_T oldState = mData->mMachineState;
    4252         mData->mMachineState = MachineState_DeletingSnapshot;
    4253 
    4254         // make a copy of the first snapshot so the refcount does not drop to 0
    4255         // in beginDeletingSnapshot, which sets pFirstSnapshot to 0 (that hangs
    4256         // because of the AutoCaller voodoo)
    4257         ComObjPtr<Snapshot> pFirstSnapshot = mData->mFirstSnapshot;
    4258 
    4259         // GO!
    4260         pFirstSnapshot->uninitRecursively(alock, cleanupMode, llMedia, mData->llFilesToDelete);
    4261 
    4262         mData->mMachineState = oldState;
    4263     }
    4264 
    4265     if (FAILED(rc))
    4266     {
    4267         rollbackMedia();
    4268         return rc;
    4269     }
    4270 
    4271     // commit all the media changes made above
    4272     commitMedia();
    4273 
    4274     mData->mRegistered = false;
    4275 
    4276     // machine lock no longer needed
    4277     alock.release();
    4278 
    4279     // return media to caller
    4280     SafeIfaceArray<IMedium> sfaMedia(llMedia);
    4281     sfaMedia.detachTo(ComSafeArrayOutArg(aMedia));
    4282 
    4283     mParent->unregisterMachine(this, id);
    4284             // calls VirtualBox::saveSettings()
    4285 
    4286     return S_OK;
    4287 }
    4288 
    4289 struct Machine::DeleteTask
    4290 {
    4291     ComObjPtr<Machine>          pMachine;
    4292     std::list<Utf8Str>          llFilesToDelete;
    4293     ComObjPtr<Progress>         pProgress;
    4294     bool                        fNeedsGlobalSaveSettings;
    4295 };
    4296 
    4297 STDMETHODIMP Machine::Delete(ComSafeArrayIn(IMedium*, aMedia), IProgress **aProgress)
    4298 {
    4299     LogFlowFuncEnter();
    4300 
    4301     AutoCaller autoCaller(this);
    4302     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4303 
    4304     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    4305 
    4306     HRESULT rc = checkStateDependency(MutableStateDep);
    4307     if (FAILED(rc)) return rc;
    4308 
    4309     if (mData->mRegistered)
    4310         return setError(VBOX_E_INVALID_VM_STATE,
    4311                         tr("Cannot delete settings of a registered machine"));
    4312 
    4313     DeleteTask *pTask = new DeleteTask;
    4314     pTask->pMachine = this;
    4315     com::SafeIfaceArray<IMedium> sfaMedia(ComSafeArrayInArg(aMedia));
    4316 
    4317     // collect files to delete
    4318     pTask->llFilesToDelete = mData->llFilesToDelete;            // saved states pushed here by Unregister()
    4319 
    4320     pTask->fNeedsGlobalSaveSettings = false;
    4321     for (size_t i = 0; i < sfaMedia.size(); ++i)
    4322     {
    4323         IMedium *pIMedium(sfaMedia[i]);
    4324         Medium *pMedium = static_cast<Medium*>(pIMedium);
    4325         AutoCaller mediumAutoCaller(pMedium);
    4326         if (FAILED(mediumAutoCaller.rc())) return mediumAutoCaller.rc();
    4327 
    4328         Utf8Str bstrLocation = pMedium->getLocationFull();
    4329         // close the medium now; if that succeeds, then that means the medium is no longer
    4330         // in use and we can add it to the list of files to delete
    4331         rc = pMedium->close(&pTask->fNeedsGlobalSaveSettings,
    4332                             mediumAutoCaller);
    4333         if (SUCCEEDED(rc))
    4334             pTask->llFilesToDelete.push_back(bstrLocation);
    4335     }
    4336     if (mData->pMachineConfigFile->fileExists())
    4337         pTask->llFilesToDelete.push_back(mData->m_strConfigFileFull);
    4338 
    4339     pTask->pProgress.createObject();
    4340     pTask->pProgress->init(getVirtualBox(),
    4341                            static_cast<IMachine*>(this) /* aInitiator */,
    4342                            Bstr(tr("Deleting files")),
    4343                            true /* fCancellable */,
    4344                            pTask->llFilesToDelete.size() + 1,   // cOperations
    4345                            BstrFmt(tr("Deleting '%s'"), pTask->llFilesToDelete.front().c_str()));
    4346 
    4347     int vrc = RTThreadCreate(NULL,
    4348                              Machine::deleteThread,
    4349                              (void*)pTask,
    4350                              0,
    4351                              RTTHREADTYPE_MAIN_WORKER,
    4352                              0,
    4353                              "MachineDelete");
    4354 
    4355     pTask->pProgress.queryInterfaceTo(aProgress);
    4356 
    4357     if (RT_FAILURE(vrc))
    4358     {
    4359         delete pTask;
    4360         return setError(E_FAIL, "Could not create MachineDelete thread (%Rrc)", vrc);
    4361     }
    4362 
    4363     LogFlowFuncLeave();
    4364 
    4365     return S_OK;
    4366 }
    4367 
    4368 /**
    4369  * Static task wrapper passed to RTThreadCreate() in Machine::Delete() which then
    4370  * calls Machine::deleteTaskWorker() on the actual machine object.
    4371  * @param Thread
    4372  * @param pvUser
    4373  * @return
    4374  */
    4375 /*static*/
    4376 DECLCALLBACK(int) Machine::deleteThread(RTTHREAD Thread, void *pvUser)
    4377 {
    4378     LogFlowFuncEnter();
    4379 
    4380     DeleteTask *pTask = (DeleteTask*)pvUser;
    4381     Assert(pTask);
    4382     Assert(pTask->pMachine);
    4383     Assert(pTask->pProgress);
    4384 
    4385     HRESULT rc = pTask->pMachine->deleteTaskWorker(*pTask);
    4386     pTask->pProgress->notifyComplete(rc);
    4387 
    4388     delete pTask;
    4389 
    4390     LogFlowFuncLeave();
    4391 
    4392     NOREF(Thread);
    4393 
    4394     return VINF_SUCCESS;
    4395 }
    4396 
    4397 /**
    4398  * Task thread implementation for Machine::Delete(), called from Machine::deleteThread().
    4399  * @param task
    4400  * @return
    4401  */
    4402 HRESULT Machine::deleteTaskWorker(DeleteTask &task)
    4403 {
    4404     AutoCaller autoCaller(this);
    4405     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4406 
    4407     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    4408 
    4409     ULONG uLogHistoryCount = 3;
    4410     ComPtr<ISystemProperties> systemProperties;
    4411     mParent->COMGETTER(SystemProperties)(systemProperties.asOutParam());
    4412     if (!systemProperties.isNull())
    4413         systemProperties->COMGETTER(LogHistoryCount)(&uLogHistoryCount);
    4414 
    4415     // delete the files pushed on the task list by Machine::Delete()
    4416     // (this includes saved states of the machine and snapshots and
    4417     // medium storage files from the IMedium list passed in, and the
    4418     // machine XML file)
    4419     std::list<Utf8Str>::const_iterator it = task.llFilesToDelete.begin();
    4420     while (it != task.llFilesToDelete.end())
    4421     {
    4422         const Utf8Str &strFile = *it;
    4423         LogFunc(("Deleting file %s\n", strFile.c_str()));
    4424         RTFileDelete(strFile.c_str());
    4425 
    4426         ++it;
    4427         if (it == task.llFilesToDelete.end())
    4428         {
    4429             task.pProgress->SetNextOperation(Bstr(tr("Cleaning up machine directory")), 1);
    4430             break;
    4431         }
    4432 
    4433         task.pProgress->SetNextOperation(BstrFmt(tr("Deleting '%s'"), it->c_str()), 1);
    4434     }
    4435 
    4436     /* delete the settings only when the file actually exists */
    4437     if (mData->pMachineConfigFile->fileExists())
    4438     {
    4439         /* Delete any backup or uncommitted XML files. Ignore failures.
    4440            See the fSafe parameter of xml::XmlFileWriter::write for details. */
    4441         /** @todo Find a way to avoid referring directly to iprt/xml.h here. */
    4442         Utf8Str otherXml = Utf8StrFmt("%s%s", mData->m_strConfigFileFull.c_str(), xml::XmlFileWriter::s_pszTmpSuff);
    4443         RTFileDelete(otherXml.c_str());
    4444         otherXml = Utf8StrFmt("%s%s", mData->m_strConfigFileFull.c_str(), xml::XmlFileWriter::s_pszPrevSuff);
    4445         RTFileDelete(otherXml.c_str());
    4446 
    4447         /* delete the Logs folder, nothing important should be left
    4448          * there (we don't check for errors because the user might have
    4449          * some private files there that we don't want to delete) */
    4450         Utf8Str logFolder;
    4451         getLogFolder(logFolder);
    4452         Assert(logFolder.length());
    4453         if (RTDirExists(logFolder.c_str()))
    4454         {
    4455             /* Delete all VBox.log[.N] files from the Logs folder
    4456              * (this must be in sync with the rotation logic in
    4457              * Console::powerUpThread()). Also, delete the VBox.png[.N]
    4458              * files that may have been created by the GUI. */
    4459             Utf8Str log = Utf8StrFmt("%s%cVBox.log",
    4460                                      logFolder.c_str(), RTPATH_DELIMITER);
    4461             RTFileDelete(log.c_str());
    4462             log = Utf8StrFmt("%s%cVBox.png",
    4463                              logFolder.c_str(), RTPATH_DELIMITER);
    4464             RTFileDelete(log.c_str());
    4465             for (int i = uLogHistoryCount; i > 0; i--)
    4466             {
    4467                 log = Utf8StrFmt("%s%cVBox.log.%d",
    4468                                  logFolder.c_str(), RTPATH_DELIMITER, i);
    4469                 RTFileDelete(log.c_str());
    4470                 log = Utf8StrFmt("%s%cVBox.png.%d",
    4471                                  logFolder.c_str(), RTPATH_DELIMITER, i);
    4472                 RTFileDelete(log.c_str());
    4473             }
    4474 
    4475             RTDirRemove(logFolder.c_str());
    4476         }
    4477 
    4478         /* delete the Snapshots folder, nothing important should be left
    4479          * there (we don't check for errors because the user might have
    4480          * some private files there that we don't want to delete) */
    4481         Assert(mUserData->m_strSnapshotFolderFull.length());
    4482         if (RTDirExists(mUserData->m_strSnapshotFolderFull.c_str()))
    4483             RTDirRemove(mUserData->m_strSnapshotFolderFull.c_str());
    4484 
    4485         /* delete the directory that contains the settings file, but only
    4486          * if it matches the VM name (i.e. a structure created by default in
    4487          * prepareSaveSettings()) */
    4488         {
    4489             Utf8Str settingsDir;
    4490             if (isInOwnDir(&settingsDir))
    4491                 RTDirRemove(settingsDir.c_str());
    4492         }
    4493     }
    4494 
    4495     alock.release();
    4496 
    4497     if (task.fNeedsGlobalSaveSettings)
    4498     {
    4499         AutoWriteLock vboxlock(mParent COMMA_LOCKVAL_SRC_POS);
    4500         mParent->saveSettings();
    4501     }
    4502 
    4503     return S_OK;
    4504 }
    4505 
    4506 STDMETHODIMP Machine::GetSnapshot(IN_BSTR aId, ISnapshot **aSnapshot)
    4507 {
    4508     CheckComArgOutPointerValid(aSnapshot);
    4509 
    4510     AutoCaller autoCaller(this);
    4511     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4512 
    4513     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4514 
    4515     Guid uuid(aId);
    4516     /* Todo: fix this properly by perhaps introducing an isValid method for the Guid class */
    4517     if (    (aId)
    4518         &&  (*aId != '\0')      // an empty Bstr means "get root snapshot", so don't fail on that
    4519         &&  (uuid.isEmpty()))
    4520     {
    4521         RTUUID uuidTemp;
    4522         /* Either it's a null UUID or the conversion failed. (null uuid has a special meaning in findSnapshot) */
    4523         if (RT_FAILURE(RTUuidFromUtf16(&uuidTemp, aId)))
    4524             return setError(E_FAIL,
    4525                             tr("Could not find a snapshot with UUID {%ls}"),
    4526                             aId);
    4527     }
    4528 
    4529     ComObjPtr<Snapshot> snapshot;
    4530 
    4531     HRESULT rc = findSnapshot(uuid, snapshot, true /* aSetError */);
    4532     snapshot.queryInterfaceTo(aSnapshot);
    4533 
    4534     return rc;
    4535 }
    4536 
    4537 STDMETHODIMP Machine::FindSnapshot(IN_BSTR aName, ISnapshot **aSnapshot)
    4538 {
    4539     CheckComArgStrNotEmptyOrNull(aName);
    4540     CheckComArgOutPointerValid(aSnapshot);
    4541 
    4542     AutoCaller autoCaller(this);
    4543     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4544 
    4545     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4546 
    4547     ComObjPtr<Snapshot> snapshot;
    4548 
    4549     HRESULT rc = findSnapshot(aName, snapshot, true /* aSetError */);
    4550     snapshot.queryInterfaceTo(aSnapshot);
    4551 
    4552     return rc;
    4553 }
    4554 
    4555 STDMETHODIMP Machine::SetCurrentSnapshot(IN_BSTR /* aId */)
    4556 {
    4557     /// @todo (dmik) don't forget to set
    4558     //  mData->mCurrentStateModified to FALSE
    4559 
    4560     return setError(E_NOTIMPL, "Not implemented");
    4561 }
    4562 
    4563 STDMETHODIMP Machine::CreateSharedFolder(IN_BSTR aName, IN_BSTR aHostPath, BOOL aWritable, BOOL aAutoMount)
    4564 {
    4565     CheckComArgStrNotEmptyOrNull(aName);
    4566     CheckComArgStrNotEmptyOrNull(aHostPath);
    4567 
    4568     AutoCaller autoCaller(this);
    4569     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4570 
    4571     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    4572 
    4573     HRESULT rc = checkStateDependency(MutableStateDep);
    4574     if (FAILED(rc)) return rc;
    4575 
    4576     ComObjPtr<SharedFolder> sharedFolder;
    4577     rc = findSharedFolder(aName, sharedFolder, false /* aSetError */);
    4578     if (SUCCEEDED(rc))
    4579         return setError(VBOX_E_OBJECT_IN_USE,
    4580                         tr("Shared folder named '%ls' already exists"),
    4581                         aName);
    4582 
    4583     sharedFolder.createObject();
    4584     rc = sharedFolder->init(getMachine(), aName, aHostPath, aWritable, aAutoMount);
    4585     if (FAILED(rc)) return rc;
    4586 
    4587     setModified(IsModified_SharedFolders);
    4588     mHWData.backup();
    4589     mHWData->mSharedFolders.push_back(sharedFolder);
    4590 
    4591     /* inform the direct session if any */
    4592     alock.leave();
    4593     onSharedFolderChange();
    4594 
    4595     return S_OK;
    4596 }
    4597 
    4598 STDMETHODIMP Machine::RemoveSharedFolder(IN_BSTR aName)
    4599 {
    4600     CheckComArgStrNotEmptyOrNull(aName);
    4601 
    4602     AutoCaller autoCaller(this);
    4603     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4604 
    4605     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    4606 
    4607     HRESULT rc = checkStateDependency(MutableStateDep);
    4608     if (FAILED(rc)) return rc;
    4609 
    4610     ComObjPtr<SharedFolder> sharedFolder;
    4611     rc = findSharedFolder(aName, sharedFolder, true /* aSetError */);
    4612     if (FAILED(rc)) return rc;
    4613 
    4614     setModified(IsModified_SharedFolders);
    4615     mHWData.backup();
    4616     mHWData->mSharedFolders.remove(sharedFolder);
    4617 
    4618     /* inform the direct session if any */
    4619     alock.leave();
    4620     onSharedFolderChange();
    4621 
    4622     return S_OK;
    4623 }
    4624 
    4625 STDMETHODIMP Machine::CanShowConsoleWindow(BOOL *aCanShow)
    4626 {
    4627     CheckComArgOutPointerValid(aCanShow);
    4628 
    4629     /* start with No */
    4630     *aCanShow = FALSE;
    4631 
    4632     AutoCaller autoCaller(this);
    4633     AssertComRCReturnRC(autoCaller.rc());
    4634 
    4635     ComPtr<IInternalSessionControl> directControl;
    4636     {
    4637         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4638 
    4639         if (mData->mSession.mState != SessionState_Locked)
    4640             return setError(VBOX_E_INVALID_VM_STATE,
    4641                             tr("Machine is not locked for session (session state: %s)"),
    4642                             Global::stringifySessionState(mData->mSession.mState));
    4643 
    4644         directControl = mData->mSession.mDirectControl;
    4645     }
    4646 
    4647     /* ignore calls made after #OnSessionEnd() is called */
    4648     if (!directControl)
    4649         return S_OK;
    4650 
    4651     LONG64 dummy;
    4652     return directControl->OnShowWindow(TRUE /* aCheck */, aCanShow, &dummy);
    4653 }
    4654 
    4655 STDMETHODIMP Machine::ShowConsoleWindow(LONG64 *aWinId)
    4656 {
    4657     CheckComArgOutPointerValid(aWinId);
    4658 
    4659     AutoCaller autoCaller(this);
    4660     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    4661 
    4662     ComPtr<IInternalSessionControl> directControl;
    4663     {
    4664         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4665 
    4666         if (mData->mSession.mState != SessionState_Locked)
    4667             return setError(E_FAIL,
    4668                             tr("Machine is not locked for session (session state: %s)"),
    4669                             Global::stringifySessionState(mData->mSession.mState));
    4670 
    4671         directControl = mData->mSession.mDirectControl;
    4672     }
    4673 
    4674     /* ignore calls made after #OnSessionEnd() is called */
    4675     if (!directControl)
    4676         return S_OK;
    4677 
    4678     BOOL dummy;
    4679     return directControl->OnShowWindow(FALSE /* aCheck */, &dummy, aWinId);
    4680 }
    4681 
    4682 #ifdef VBOX_WITH_GUEST_PROPS
    4683 /**
    4684  * Look up a guest property in VBoxSVC's internal structures.
    4685  */
    4686 HRESULT Machine::getGuestPropertyFromService(IN_BSTR aName,
    4687                                              BSTR *aValue,
    4688                                              LONG64 *aTimestamp,
    4689                                              BSTR *aFlags) const
    4690 {
    4691     using namespace guestProp;
    4692 
    4693     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4694     Utf8Str strName(aName);
    4695     HWData::GuestPropertyList::const_iterator it;
    4696 
    4697     for (it = mHWData->mGuestProperties.begin();
    4698          it != mHWData->mGuestProperties.end(); ++it)
    4699     {
    4700         if (it->strName == strName)
    4701         {
    4702             char szFlags[MAX_FLAGS_LEN + 1];
    4703             it->strValue.cloneTo(aValue);
    4704             *aTimestamp = it->mTimestamp;
    4705             writeFlags(it->mFlags, szFlags);
    4706             Bstr(szFlags).cloneTo(aFlags);
    4707             break;
    4708         }
    4709     }
    4710     return S_OK;
    4711 }
    4712 
    4713 /**
    4714  * Query the VM that a guest property belongs to for the property.
    4715  * @returns E_ACCESSDENIED if the VM process is not available or not
    4716  *          currently handling queries and the lookup should then be done in
    4717  *          VBoxSVC.
    4718  */
    4719 HRESULT Machine::getGuestPropertyFromVM(IN_BSTR aName,
    4720                                         BSTR *aValue,
    4721                                         LONG64 *aTimestamp,
    4722                                         BSTR *aFlags) const
    4723 {
    4724     HRESULT rc;
    4725     ComPtr<IInternalSessionControl> directControl;
    4726     directControl = mData->mSession.mDirectControl;
    4727 
    4728     /* fail if we were called after #OnSessionEnd() is called.  This is a
    4729      * silly race condition. */
    4730 
    4731     if (!directControl)
    4732         rc = E_ACCESSDENIED;
    4733     else
    4734         rc = directControl->AccessGuestProperty(aName, NULL, NULL,
    4735                                                 false /* isSetter */,
    4736                                                 aValue, aTimestamp, aFlags);
    4737     return rc;
    4738 }
    4739 #endif // VBOX_WITH_GUEST_PROPS
    4740 
    4741 STDMETHODIMP Machine::GetGuestProperty(IN_BSTR aName,
    4742                                        BSTR *aValue,
    4743                                        LONG64 *aTimestamp,
    4744                                        BSTR *aFlags)
    4745 {
    4746 #ifndef VBOX_WITH_GUEST_PROPS
    4747     ReturnComNotImplemented();
    4748 #else // VBOX_WITH_GUEST_PROPS
    4749     CheckComArgStrNotEmptyOrNull(aName);
    4750     CheckComArgOutPointerValid(aValue);
    4751     CheckComArgOutPointerValid(aTimestamp);
    4752     CheckComArgOutPointerValid(aFlags);
    4753 
    4754     AutoCaller autoCaller(this);
    4755     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4756 
    4757     HRESULT rc = getGuestPropertyFromVM(aName, aValue, aTimestamp, aFlags);
    4758     if (rc == E_ACCESSDENIED)
    4759         /* The VM is not running or the service is not (yet) accessible */
    4760         rc = getGuestPropertyFromService(aName, aValue, aTimestamp, aFlags);
    4761     return rc;
    4762 #endif // VBOX_WITH_GUEST_PROPS
    4763 }
    4764 
    4765 STDMETHODIMP Machine::GetGuestPropertyValue(IN_BSTR aName, BSTR *aValue)
    4766 {
    4767     LONG64 dummyTimestamp;
    4768     Bstr dummyFlags;
    4769     return GetGuestProperty(aName, aValue, &dummyTimestamp, dummyFlags.asOutParam());
    4770 }
    4771 
    4772 STDMETHODIMP Machine::GetGuestPropertyTimestamp(IN_BSTR aName, LONG64 *aTimestamp)
    4773 {
    4774     Bstr dummyValue;
    4775     Bstr dummyFlags;
    4776     return GetGuestProperty(aName, dummyValue.asOutParam(), aTimestamp, dummyFlags.asOutParam());
    4777 }
    4778 
    4779 #ifdef VBOX_WITH_GUEST_PROPS
    4780 /**
    4781  * Set a guest property in VBoxSVC's internal structures.
    4782  */
    4783 HRESULT Machine::setGuestPropertyToService(IN_BSTR aName, IN_BSTR aValue,
    4784                                            IN_BSTR aFlags)
    4785 {
    4786     using namespace guestProp;
    4787 
    4788     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    4789     HRESULT rc = S_OK;
    4790     HWData::GuestProperty property;
    4791     property.mFlags = NILFLAG;
    4792     bool found = false;
    4793 
    4794     rc = checkStateDependency(MutableStateDep);
    4795     if (FAILED(rc)) return rc;
    4796 
    4797     try
    4798     {
    4799         Utf8Str utf8Name(aName);
    4800         Utf8Str utf8Flags(aFlags);
    4801         uint32_t fFlags = NILFLAG;
    4802         if (    (aFlags != NULL)
    4803              && RT_FAILURE(validateFlags(utf8Flags.c_str(), &fFlags))
    4804            )
    4805             return setError(E_INVALIDARG,
    4806                             tr("Invalid flag values: '%ls'"),
    4807                             aFlags);
    4808 
    4809         /** @todo r=bird: see efficiency rant in PushGuestProperty. (Yeah, I
    4810          *                know, this is simple and do an OK job atm.) */
    4811         HWData::GuestPropertyList::iterator it;
    4812         for (it = mHWData->mGuestProperties.begin();
    4813              it != mHWData->mGuestProperties.end(); ++it)
    4814             if (it->strName == utf8Name)
    4815             {
    4816                 property = *it;
    4817                 if (it->mFlags & (RDONLYHOST))
    4818                     rc = setError(E_ACCESSDENIED,
    4819                                   tr("The property '%ls' cannot be changed by the host"),
    4820                                   aName);
    4821                 else
    4822                 {
    4823                     setModified(IsModified_MachineData);
    4824                     mHWData.backup();           // @todo r=dj backup in a loop?!?
    4825 
    4826                     /* The backup() operation invalidates our iterator, so
    4827                     * get a new one. */
    4828                     for (it = mHWData->mGuestProperties.begin();
    4829                          it->strName != utf8Name;
    4830                          ++it)
    4831                         ;
    4832                     mHWData->mGuestProperties.erase(it);
    4833                 }
    4834                 found = true;
    4835                 break;
    4836             }
    4837         if (found && SUCCEEDED(rc))
    4838         {
    4839             if (*aValue)
    4840             {
    4841                 RTTIMESPEC time;
    4842                 property.strValue = aValue;
    4843                 property.mTimestamp = RTTimeSpecGetNano(RTTimeNow(&time));
    4844                 if (aFlags != NULL)
    4845                     property.mFlags = fFlags;
    4846                 mHWData->mGuestProperties.push_back(property);
    4847             }
    4848         }
    4849         else if (SUCCEEDED(rc) && *aValue)
    4850         {
    4851             RTTIMESPEC time;
    4852             setModified(IsModified_MachineData);
    4853             mHWData.backup();
    4854             property.strName = aName;
    4855             property.strValue = aValue;
    4856             property.mTimestamp = RTTimeSpecGetNano(RTTimeNow(&time));
    4857             property.mFlags = fFlags;
    4858             mHWData->mGuestProperties.push_back(property);
    4859         }
    4860         if (   SUCCEEDED(rc)
    4861             && (   mHWData->mGuestPropertyNotificationPatterns.isEmpty()
    4862                 || RTStrSimplePatternMultiMatch(mHWData->mGuestPropertyNotificationPatterns.c_str(),
    4863                                                 RTSTR_MAX,
    4864                                                 utf8Name.c_str(),
    4865                                                 RTSTR_MAX,
    4866                                                 NULL)
    4867                )
    4868            )
    4869         {
    4870             /** @todo r=bird: Why aren't we leaving the lock here?  The
    4871              *                same code in PushGuestProperty does... */
    4872             mParent->onGuestPropertyChange(mData->mUuid, aName, aValue, aFlags);
    4873         }
    4874     }
    4875     catch (std::bad_alloc &)
    4876     {
    4877         rc = E_OUTOFMEMORY;
    4878     }
    4879 
    4880     return rc;
    4881 }
    4882 
    4883 /**
    4884  * Set a property on the VM that that property belongs to.
    4885  * @returns E_ACCESSDENIED if the VM process is not available or not
    4886  *          currently handling queries and the setting should then be done in
    4887  *          VBoxSVC.
    4888  */
    4889 HRESULT Machine::setGuestPropertyToVM(IN_BSTR aName, IN_BSTR aValue,
    4890                                       IN_BSTR aFlags)
    4891 {
    4892     HRESULT rc;
    4893 
    4894     try {
    4895         ComPtr<IInternalSessionControl> directControl =
    4896             mData->mSession.mDirectControl;
    4897 
    4898         BSTR dummy = NULL; /* will not be changed (setter) */
    4899         LONG64 dummy64;
    4900         if (!directControl)
    4901             rc = E_ACCESSDENIED;
    4902         else
    4903             rc = directControl->AccessGuestProperty
    4904                      (aName,
    4905                       /** @todo Fix when adding DeleteGuestProperty(),
    4906                                    see defect. */
    4907                       *aValue ? aValue : NULL, aFlags, true /* isSetter */,
    4908                       &dummy, &dummy64, &dummy);
    4909     }
    4910     catch (std::bad_alloc &)
    4911     {
    4912         rc = E_OUTOFMEMORY;
    4913     }
    4914 
    4915     return rc;
    4916 }
    4917 #endif // VBOX_WITH_GUEST_PROPS
    4918 
    4919 STDMETHODIMP Machine::SetGuestProperty(IN_BSTR aName, IN_BSTR aValue,
    4920                                        IN_BSTR aFlags)
    4921 {
    4922 #ifndef VBOX_WITH_GUEST_PROPS
    4923     ReturnComNotImplemented();
    4924 #else // VBOX_WITH_GUEST_PROPS
    4925     CheckComArgStrNotEmptyOrNull(aName);
    4926     if ((aFlags != NULL) && !VALID_PTR(aFlags))
    4927         return E_INVALIDARG;
    4928     AutoCaller autoCaller(this);
    4929     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    4930 
    4931     HRESULT rc = setGuestPropertyToVM(aName, aValue, aFlags);
    4932     if (rc == E_ACCESSDENIED)
    4933         /* The VM is not running or the service is not (yet) accessible */
    4934         rc = setGuestPropertyToService(aName, aValue, aFlags);
    4935     return rc;
    4936 #endif // VBOX_WITH_GUEST_PROPS
    4937 }
    4938 
    4939 STDMETHODIMP Machine::SetGuestPropertyValue(IN_BSTR aName, IN_BSTR aValue)
    4940 {
    4941     return SetGuestProperty(aName, aValue, NULL);
    4942 }
    4943 
    4944 #ifdef VBOX_WITH_GUEST_PROPS
    4945 /**
    4946  * Enumerate the guest properties in VBoxSVC's internal structures.
    4947  */
    4948 HRESULT Machine::enumerateGuestPropertiesInService
    4949                 (IN_BSTR aPatterns, ComSafeArrayOut(BSTR, aNames),
    4950                  ComSafeArrayOut(BSTR, aValues),
    4951                  ComSafeArrayOut(LONG64, aTimestamps),
    4952                  ComSafeArrayOut(BSTR, aFlags))
    4953 {
    4954     using namespace guestProp;
    4955 
    4956     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    4957     Utf8Str strPatterns(aPatterns);
    4958 
    4959     /*
    4960      * Look for matching patterns and build up a list.
    4961      */
    4962     HWData::GuestPropertyList propList;
    4963     for (HWData::GuestPropertyList::iterator it = mHWData->mGuestProperties.begin();
    4964          it != mHWData->mGuestProperties.end();
    4965          ++it)
    4966         if (   strPatterns.isEmpty()
    4967             || RTStrSimplePatternMultiMatch(strPatterns.c_str(),
    4968                                             RTSTR_MAX,
    4969                                             it->strName.c_str(),
    4970                                             RTSTR_MAX,
    4971                                             NULL)
    4972            )
    4973             propList.push_back(*it);
    4974 
    4975     /*
    4976      * And build up the arrays for returning the property information.
    4977      */
    4978     size_t cEntries = propList.size();
    4979     SafeArray<BSTR> names(cEntries);
    4980     SafeArray<BSTR> values(cEntries);
    4981     SafeArray<LONG64> timestamps(cEntries);
    4982     SafeArray<BSTR> flags(cEntries);
    4983     size_t iProp = 0;
    4984     for (HWData::GuestPropertyList::iterator it = propList.begin();
    4985          it != propList.end();
    4986          ++it)
    4987     {
    4988          char szFlags[MAX_FLAGS_LEN + 1];
    4989          it->strName.cloneTo(&names[iProp]);
    4990          it->strValue.cloneTo(&values[iProp]);
    4991          timestamps[iProp] = it->mTimestamp;
    4992          writeFlags(it->mFlags, szFlags);
    4993          Bstr(szFlags).cloneTo(&flags[iProp]);
    4994          ++iProp;
    4995     }
    4996     names.detachTo(ComSafeArrayOutArg(aNames));
    4997     values.detachTo(ComSafeArrayOutArg(aValues));
    4998     timestamps.detachTo(ComSafeArrayOutArg(aTimestamps));
    4999     flags.detachTo(ComSafeArrayOutArg(aFlags));
    5000     return S_OK;
    5001 }
    5002 
    5003 /**
    5004  * Enumerate the properties managed by a VM.
    5005  * @returns E_ACCESSDENIED if the VM process is not available or not
    5006  *          currently handling queries and the setting should then be done in
    5007  *          VBoxSVC.
    5008  */
    5009 HRESULT Machine::enumerateGuestPropertiesOnVM
    5010                 (IN_BSTR aPatterns, ComSafeArrayOut(BSTR, aNames),
    5011                  ComSafeArrayOut(BSTR, aValues),
    5012                  ComSafeArrayOut(LONG64, aTimestamps),
    5013                  ComSafeArrayOut(BSTR, aFlags))
    5014 {
    5015     HRESULT rc;
    5016     ComPtr<IInternalSessionControl> directControl;
    5017     directControl = mData->mSession.mDirectControl;
    5018 
    5019     if (!directControl)
    5020         rc = E_ACCESSDENIED;
    5021     else
    5022         rc = directControl->EnumerateGuestProperties
    5023                      (aPatterns, ComSafeArrayOutArg(aNames),
    5024                       ComSafeArrayOutArg(aValues),
    5025                       ComSafeArrayOutArg(aTimestamps),
    5026                       ComSafeArrayOutArg(aFlags));
    5027     return rc;
    5028 }
    5029 #endif // VBOX_WITH_GUEST_PROPS
    5030 
    5031 STDMETHODIMP Machine::EnumerateGuestProperties(IN_BSTR aPatterns,
    5032                                                ComSafeArrayOut(BSTR, aNames),
    5033                                                ComSafeArrayOut(BSTR, aValues),
    5034                                                ComSafeArrayOut(LONG64, aTimestamps),
    5035                                                ComSafeArrayOut(BSTR, aFlags))
    5036 {
    5037 #ifndef VBOX_WITH_GUEST_PROPS
    5038     ReturnComNotImplemented();
    5039 #else // VBOX_WITH_GUEST_PROPS
    5040     if (!VALID_PTR(aPatterns) && (aPatterns != NULL))
    5041         return E_POINTER;
    5042 
    5043     CheckComArgOutSafeArrayPointerValid(aNames);
    5044     CheckComArgOutSafeArrayPointerValid(aValues);
    5045     CheckComArgOutSafeArrayPointerValid(aTimestamps);
    5046     CheckComArgOutSafeArrayPointerValid(aFlags);
    5047 
    5048     AutoCaller autoCaller(this);
    5049     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5050 
    5051     HRESULT rc = enumerateGuestPropertiesOnVM
    5052                      (aPatterns, ComSafeArrayOutArg(aNames),
    5053                       ComSafeArrayOutArg(aValues),
    5054                       ComSafeArrayOutArg(aTimestamps),
    5055                       ComSafeArrayOutArg(aFlags));
    5056     if (rc == E_ACCESSDENIED)
    5057         /* The VM is not running or the service is not (yet) accessible */
    5058         rc = enumerateGuestPropertiesInService
    5059                      (aPatterns, ComSafeArrayOutArg(aNames),
    5060                       ComSafeArrayOutArg(aValues),
    5061                       ComSafeArrayOutArg(aTimestamps),
    5062                       ComSafeArrayOutArg(aFlags));
    5063     return rc;
    5064 #endif // VBOX_WITH_GUEST_PROPS
    5065 }
    5066 
    5067 STDMETHODIMP Machine::GetMediumAttachmentsOfController(IN_BSTR aName,
    5068                                                        ComSafeArrayOut(IMediumAttachment*, aAttachments))
    5069 {
    5070     MediaData::AttachmentList atts;
    5071 
    5072     HRESULT rc = getMediumAttachmentsOfController(aName, atts);
    5073     if (FAILED(rc)) return rc;
    5074 
    5075     SafeIfaceArray<IMediumAttachment> attachments(atts);
    5076     attachments.detachTo(ComSafeArrayOutArg(aAttachments));
    5077 
    5078     return S_OK;
    5079 }
    5080 
    5081 STDMETHODIMP Machine::GetMediumAttachment(IN_BSTR aControllerName,
    5082                                           LONG aControllerPort,
    5083                                           LONG aDevice,
    5084                                           IMediumAttachment **aAttachment)
    5085 {
    5086     LogFlowThisFunc(("aControllerName=\"%ls\" aControllerPort=%d aDevice=%d\n",
    5087                      aControllerName, aControllerPort, aDevice));
    5088 
    5089     CheckComArgStrNotEmptyOrNull(aControllerName);
    5090     CheckComArgOutPointerValid(aAttachment);
    5091 
    5092     AutoCaller autoCaller(this);
    5093     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5094 
    5095     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5096 
    5097     *aAttachment = NULL;
    5098 
    5099     ComObjPtr<MediumAttachment> pAttach = findAttachment(mMediaData->mAttachments,
    5100                                                          aControllerName,
    5101                                                          aControllerPort,
    5102                                                          aDevice);
    5103     if (pAttach.isNull())
    5104         return setError(VBOX_E_OBJECT_NOT_FOUND,
    5105                         tr("No storage device attached to device slot %d on port %d of controller '%ls'"),
    5106                         aDevice, aControllerPort, aControllerName);
    5107 
    5108     pAttach.queryInterfaceTo(aAttachment);
    5109 
    5110     return S_OK;
    5111 }
    5112 
    5113 STDMETHODIMP Machine::AddStorageController(IN_BSTR aName,
    5114                                            StorageBus_T aConnectionType,
    5115                                            IStorageController **controller)
    5116 {
    5117     CheckComArgStrNotEmptyOrNull(aName);
    5118 
    5119     if (   (aConnectionType <= StorageBus_Null)
    5120         || (aConnectionType >  StorageBus_SAS))
    5121         return setError(E_INVALIDARG,
    5122                         tr("Invalid connection type: %d"),
    5123                         aConnectionType);
    5124 
    5125     AutoCaller autoCaller(this);
    5126     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5127 
    5128     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    5129 
    5130     HRESULT rc = checkStateDependency(MutableStateDep);
    5131     if (FAILED(rc)) return rc;
    5132 
    5133     /* try to find one with the name first. */
    5134     ComObjPtr<StorageController> ctrl;
    5135 
    5136     rc = getStorageControllerByName(aName, ctrl, false /* aSetError */);
    5137     if (SUCCEEDED(rc))
    5138         return setError(VBOX_E_OBJECT_IN_USE,
    5139                         tr("Storage controller named '%ls' already exists"),
    5140                         aName);
    5141 
    5142     ctrl.createObject();
    5143 
    5144     /* get a new instance number for the storage controller */
    5145     ULONG ulInstance = 0;
    5146     for (StorageControllerList::const_iterator it = mStorageControllers->begin();
    5147          it != mStorageControllers->end();
    5148          ++it)
    5149     {
    5150         if ((*it)->getStorageBus() == aConnectionType)
    5151         {
    5152             ULONG ulCurInst = (*it)->getInstance();
    5153 
    5154             if (ulCurInst >= ulInstance)
    5155                 ulInstance = ulCurInst + 1;
    5156         }
    5157     }
    5158 
    5159     rc = ctrl->init(this, aName, aConnectionType, ulInstance);
    5160     if (FAILED(rc)) return rc;
    5161 
    5162     setModified(IsModified_Storage);
    5163     mStorageControllers.backup();
    5164     mStorageControllers->push_back(ctrl);
    5165 
    5166     ctrl.queryInterfaceTo(controller);
    5167 
    5168     /* inform the direct session if any */
    5169     alock.leave();
    5170     onStorageControllerChange();
    5171 
    5172     return S_OK;
    5173 }
    5174 
    5175 STDMETHODIMP Machine::GetStorageControllerByName(IN_BSTR aName,
    5176                                                  IStorageController **aStorageController)
    5177 {
    5178     CheckComArgStrNotEmptyOrNull(aName);
    5179 
    5180     AutoCaller autoCaller(this);
    5181     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5182 
    5183     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5184 
    5185     ComObjPtr<StorageController> ctrl;
    5186 
    5187     HRESULT rc = getStorageControllerByName(aName, ctrl, true /* aSetError */);
    5188     if (SUCCEEDED(rc))
    5189         ctrl.queryInterfaceTo(aStorageController);
    5190 
    5191     return rc;
    5192 }
    5193 
    5194 STDMETHODIMP Machine::GetStorageControllerByInstance(ULONG aInstance,
    5195                                                      IStorageController **aStorageController)
    5196 {
    5197     AutoCaller autoCaller(this);
    5198     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5199 
    5200     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5201 
    5202     for (StorageControllerList::const_iterator it = mStorageControllers->begin();
    5203          it != mStorageControllers->end();
    5204          ++it)
    5205     {
    5206         if ((*it)->getInstance() == aInstance)
    5207         {
    5208             (*it).queryInterfaceTo(aStorageController);
    5209             return S_OK;
    5210         }
    5211     }
    5212 
    5213     return setError(VBOX_E_OBJECT_NOT_FOUND,
    5214                     tr("Could not find a storage controller with instance number '%lu'"),
    5215                     aInstance);
    5216 }
    5217 
    5218 STDMETHODIMP Machine::RemoveStorageController(IN_BSTR aName)
    5219 {
    5220     CheckComArgStrNotEmptyOrNull(aName);
    5221 
    5222     AutoCaller autoCaller(this);
    5223     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5224 
    5225     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    5226 
    5227     HRESULT rc = checkStateDependency(MutableStateDep);
    5228     if (FAILED(rc)) return rc;
    5229 
    5230     ComObjPtr<StorageController> ctrl;
    5231     rc = getStorageControllerByName(aName, ctrl, true /* aSetError */);
    5232     if (FAILED(rc)) return rc;
    5233 
    5234     /* We can remove the controller only if there is no device attached. */
    5235     /* check if the device slot is already busy */
    5236     for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
    5237          it != mMediaData->mAttachments.end();
    5238          ++it)
    5239     {
    5240         if ((*it)->getControllerName() == aName)
    5241             return setError(VBOX_E_OBJECT_IN_USE,
    5242                             tr("Storage controller named '%ls' has still devices attached"),
    5243                             aName);
    5244     }
    5245 
    5246     /* We can remove it now. */
    5247     setModified(IsModified_Storage);
    5248     mStorageControllers.backup();
    5249 
    5250     ctrl->unshare();
    5251 
    5252     mStorageControllers->remove(ctrl);
    5253 
    5254     /* inform the direct session if any */
    5255     alock.leave();
    5256     onStorageControllerChange();
    5257 
    5258     return S_OK;
    5259 }
    5260 
    5261 /* @todo where is the right place for this? */
    5262 #define sSSMDisplayScreenshotVer 0x00010001
    5263 
    5264 static int readSavedDisplayScreenshot(const Utf8Str &strStateFilePath, uint32_t u32Type, uint8_t **ppu8Data, uint32_t *pcbData, uint32_t *pu32Width, uint32_t *pu32Height)
     24int readSavedDisplayScreenshot(const Utf8Str &strStateFilePath, uint32_t u32Type, uint8_t **ppu8Data, uint32_t *pcbData, uint32_t *pu32Width, uint32_t *pu32Height)
    526525{
    526626    LogFlowFunc(("u32Type = %d [%s]\n", u32Type, strStateFilePath.c_str()));
     
    5375135}
    5376136
    5377 static void freeSavedDisplayScreenshot(uint8_t *pu8Data)
     137void freeSavedDisplayScreenshot(uint8_t *pu8Data)
    5378138{
    5379139    /* @todo not necessary when caching is implemented. */
     
    5381141}
    5382142
    5383 STDMETHODIMP Machine::QuerySavedThumbnailSize(ULONG aScreenId, ULONG *aSize, ULONG *aWidth, ULONG *aHeight)
     143int readSavedGuestSize(const Utf8Str &strStateFilePath, uint32_t u32ScreenId, uint32_t *pu32Width, uint32_t *pu32Height)
    5384144{
    5385     LogFlowThisFunc(("\n"));
     145    LogFlowFunc(("u32ScreenId = %d [%s]\n", u32ScreenId, strStateFilePath.c_str()));
    5386146
    5387     CheckComArgNotNull(aSize);
    5388     CheckComArgNotNull(aWidth);
    5389     CheckComArgNotNull(aHeight);
     147    /* @todo cache read data */
     148    if (strStateFilePath.isEmpty())
     149    {
     150        /* No saved state data. */
     151        return VERR_NOT_SUPPORTED;
     152    }
    5390153
    5391     if (aScreenId != 0)
    5392         return E_NOTIMPL;
    5393 
    5394     AutoCaller autoCaller(this);
    5395     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5396 
    5397     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5398 
    5399     uint8_t *pu8Data = NULL;
    5400     uint32_t cbData = 0;
    5401154    uint32_t u32Width = 0;
    5402155    uint32_t u32Height = 0;
    5403156
    5404     int vrc = readSavedDisplayScreenshot(mSSData->mStateFilePath, 0 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
    5405 
    5406     if (RT_FAILURE(vrc))
    5407         return setError(VBOX_E_IPRT_ERROR,
    5408                         tr("Saved screenshot data is not available (%Rrc)"),
    5409                         vrc);
    5410 
    5411     *aSize = cbData;
    5412     *aWidth = u32Width;
    5413     *aHeight = u32Height;
    5414 
    5415     freeSavedDisplayScreenshot(pu8Data);
    5416 
    5417     return S_OK;
    5418 }
    5419 
    5420 STDMETHODIMP Machine::ReadSavedThumbnailToArray(ULONG aScreenId, BOOL aBGR, ULONG *aWidth, ULONG *aHeight, ComSafeArrayOut(BYTE, aData))
    5421 {
    5422     LogFlowThisFunc(("\n"));
    5423 
    5424     CheckComArgNotNull(aWidth);
    5425     CheckComArgNotNull(aHeight);
    5426     CheckComArgOutSafeArrayPointerValid(aData);
    5427 
    5428     if (aScreenId != 0)
    5429         return E_NOTIMPL;
    5430 
    5431     AutoCaller autoCaller(this);
    5432     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5433 
    5434     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5435 
    5436     uint8_t *pu8Data = NULL;
    5437     uint32_t cbData = 0;
    5438     uint32_t u32Width = 0;
    5439     uint32_t u32Height = 0;
    5440 
    5441     int vrc = readSavedDisplayScreenshot(mSSData->mStateFilePath, 0 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
    5442 
    5443     if (RT_FAILURE(vrc))
    5444         return setError(VBOX_E_IPRT_ERROR,
    5445                         tr("Saved screenshot data is not available (%Rrc)"),
    5446                         vrc);
    5447 
    5448     *aWidth = u32Width;
    5449     *aHeight = u32Height;
    5450 
    5451     com::SafeArray<BYTE> bitmap(cbData);
    5452     /* Convert pixels to format expected by the API caller. */
    5453     if (aBGR)
    5454     {
    5455         /* [0] B, [1] G, [2] R, [3] A. */
    5456         for (unsigned i = 0; i < cbData; i += 4)
    5457         {
    5458             bitmap[i]     = pu8Data[i];
    5459             bitmap[i + 1] = pu8Data[i + 1];
    5460             bitmap[i + 2] = pu8Data[i + 2];
    5461             bitmap[i + 3] = 0xff;
    5462         }
    5463     }
    5464     else
    5465     {
    5466         /* [0] R, [1] G, [2] B, [3] A. */
    5467         for (unsigned i = 0; i < cbData; i += 4)
    5468         {
    5469             bitmap[i]     = pu8Data[i + 2];
    5470             bitmap[i + 1] = pu8Data[i + 1];
    5471             bitmap[i + 2] = pu8Data[i];
    5472             bitmap[i + 3] = 0xff;
    5473         }
    5474     }
    5475     bitmap.detachTo(ComSafeArrayOutArg(aData));
    5476 
    5477     freeSavedDisplayScreenshot(pu8Data);
    5478 
    5479     return S_OK;
    5480 }
    5481 
    5482 
    5483 STDMETHODIMP Machine::ReadSavedThumbnailPNGToArray(ULONG aScreenId, ULONG *aWidth, ULONG *aHeight, ComSafeArrayOut(BYTE, aData))
    5484 {
    5485     LogFlowThisFunc(("\n"));
    5486 
    5487     CheckComArgNotNull(aWidth);
    5488     CheckComArgNotNull(aHeight);
    5489     CheckComArgOutSafeArrayPointerValid(aData);
    5490 
    5491     if (aScreenId != 0)
    5492         return E_NOTIMPL;
    5493 
    5494     AutoCaller autoCaller(this);
    5495     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5496 
    5497     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5498 
    5499     uint8_t *pu8Data = NULL;
    5500     uint32_t cbData = 0;
    5501     uint32_t u32Width = 0;
    5502     uint32_t u32Height = 0;
    5503 
    5504     int vrc = readSavedDisplayScreenshot(mSSData->mStateFilePath, 0 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
    5505 
    5506     if (RT_FAILURE(vrc))
    5507         return setError(VBOX_E_IPRT_ERROR,
    5508                         tr("Saved screenshot data is not available (%Rrc)"),
    5509                         vrc);
    5510 
    5511     *aWidth = u32Width;
    5512     *aHeight = u32Height;
    5513 
    5514     uint8_t *pu8PNG = NULL;
    5515     uint32_t cbPNG = 0;
    5516     uint32_t cxPNG = 0;
    5517     uint32_t cyPNG = 0;
    5518 
    5519     DisplayMakePNG(pu8Data, u32Width, u32Height, &pu8PNG, &cbPNG, &cxPNG, &cyPNG, 0);
    5520 
    5521     com::SafeArray<BYTE> screenData(cbPNG);
    5522     screenData.initFrom(pu8PNG, cbPNG);
    5523     RTMemFree(pu8PNG);
    5524 
    5525     screenData.detachTo(ComSafeArrayOutArg(aData));
    5526 
    5527     freeSavedDisplayScreenshot(pu8Data);
    5528 
    5529     return S_OK;
    5530 }
    5531 
    5532 STDMETHODIMP Machine::QuerySavedScreenshotPNGSize(ULONG aScreenId, ULONG *aSize, ULONG *aWidth, ULONG *aHeight)
    5533 {
    5534     LogFlowThisFunc(("\n"));
    5535 
    5536     CheckComArgNotNull(aSize);
    5537     CheckComArgNotNull(aWidth);
    5538     CheckComArgNotNull(aHeight);
    5539 
    5540     if (aScreenId != 0)
    5541         return E_NOTIMPL;
    5542 
    5543     AutoCaller autoCaller(this);
    5544     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5545 
    5546     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5547 
    5548     uint8_t *pu8Data = NULL;
    5549     uint32_t cbData = 0;
    5550     uint32_t u32Width = 0;
    5551     uint32_t u32Height = 0;
    5552 
    5553     int vrc = readSavedDisplayScreenshot(mSSData->mStateFilePath, 1 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
    5554 
    5555     if (RT_FAILURE(vrc))
    5556         return setError(VBOX_E_IPRT_ERROR,
    5557                         tr("Saved screenshot data is not available (%Rrc)"),
    5558                         vrc);
    5559 
    5560     *aSize = cbData;
    5561     *aWidth = u32Width;
    5562     *aHeight = u32Height;
    5563 
    5564     freeSavedDisplayScreenshot(pu8Data);
    5565 
    5566     return S_OK;
    5567 }
    5568 
    5569 STDMETHODIMP Machine::ReadSavedScreenshotPNGToArray(ULONG aScreenId, ULONG *aWidth, ULONG *aHeight, ComSafeArrayOut(BYTE, aData))
    5570 {
    5571     LogFlowThisFunc(("\n"));
    5572 
    5573     CheckComArgNotNull(aWidth);
    5574     CheckComArgNotNull(aHeight);
    5575     CheckComArgOutSafeArrayPointerValid(aData);
    5576 
    5577     if (aScreenId != 0)
    5578         return E_NOTIMPL;
    5579 
    5580     AutoCaller autoCaller(this);
    5581     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5582 
    5583     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5584 
    5585     uint8_t *pu8Data = NULL;
    5586     uint32_t cbData = 0;
    5587     uint32_t u32Width = 0;
    5588     uint32_t u32Height = 0;
    5589 
    5590     int vrc = readSavedDisplayScreenshot(mSSData->mStateFilePath, 1 /* u32Type */, &pu8Data, &cbData, &u32Width, &u32Height);
    5591 
    5592     if (RT_FAILURE(vrc))
    5593         return setError(VBOX_E_IPRT_ERROR,
    5594                         tr("Saved screenshot thumbnail data is not available (%Rrc)"),
    5595                         vrc);
    5596 
    5597     *aWidth = u32Width;
    5598     *aHeight = u32Height;
    5599 
    5600     com::SafeArray<BYTE> png(cbData);
    5601     png.initFrom(pu8Data, cbData);
    5602     png.detachTo(ComSafeArrayOutArg(aData));
    5603 
    5604     freeSavedDisplayScreenshot(pu8Data);
    5605 
    5606     return S_OK;
    5607 }
    5608 
    5609 STDMETHODIMP Machine::HotPlugCPU(ULONG aCpu)
    5610 {
    5611     HRESULT rc = S_OK;
    5612     LogFlowThisFunc(("\n"));
    5613 
    5614     AutoCaller autoCaller(this);
    5615     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5616 
    5617     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    5618 
    5619     if (!mHWData->mCPUHotPlugEnabled)
    5620         return setError(E_INVALIDARG, tr("CPU hotplug is not enabled"));
    5621 
    5622     if (aCpu >= mHWData->mCPUCount)
    5623         return setError(E_INVALIDARG, tr("CPU id exceeds number of possible CPUs [0:%lu]"), mHWData->mCPUCount-1);
    5624 
    5625     if (mHWData->mCPUAttached[aCpu])
    5626         return setError(VBOX_E_OBJECT_IN_USE, tr("CPU %lu is already attached"), aCpu);
    5627 
    5628     alock.release();
    5629     rc = onCPUChange(aCpu, false);
    5630     alock.acquire();
    5631     if (FAILED(rc)) return rc;
    5632 
    5633     setModified(IsModified_MachineData);
    5634     mHWData.backup();
    5635     mHWData->mCPUAttached[aCpu] = true;
    5636 
    5637     /* Save settings if online */
    5638     if (Global::IsOnline(mData->mMachineState))
    5639         saveSettings(NULL);
    5640 
    5641     return S_OK;
    5642 }
    5643 
    5644 STDMETHODIMP Machine::HotUnplugCPU(ULONG aCpu)
    5645 {
    5646     HRESULT rc = S_OK;
    5647     LogFlowThisFunc(("\n"));
    5648 
    5649     AutoCaller autoCaller(this);
    5650     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5651 
    5652     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    5653 
    5654     if (!mHWData->mCPUHotPlugEnabled)
    5655         return setError(E_INVALIDARG, tr("CPU hotplug is not enabled"));
    5656 
    5657     if (aCpu >= SchemaDefs::MaxCPUCount)
    5658         return setError(E_INVALIDARG,
    5659                         tr("CPU index exceeds maximum CPU count (must be in range [0:%lu])"),
    5660                         SchemaDefs::MaxCPUCount);
    5661 
    5662     if (!mHWData->mCPUAttached[aCpu])
    5663         return setError(VBOX_E_OBJECT_NOT_FOUND, tr("CPU %lu is not attached"), aCpu);
    5664 
    5665     /* CPU 0 can't be detached */
    5666     if (aCpu == 0)
    5667         return setError(E_INVALIDARG, tr("It is not possible to detach CPU 0"));
    5668 
    5669     alock.release();
    5670     rc = onCPUChange(aCpu, true);
    5671     alock.acquire();
    5672     if (FAILED(rc)) return rc;
    5673 
    5674     setModified(IsModified_MachineData);
    5675     mHWData.backup();
    5676     mHWData->mCPUAttached[aCpu] = false;
    5677 
    5678     /* Save settings if online */
    5679     if (Global::IsOnline(mData->mMachineState))
    5680         saveSettings(NULL);
    5681 
    5682     return S_OK;
    5683 }
    5684 
    5685 STDMETHODIMP Machine::GetCPUStatus(ULONG aCpu, BOOL *aCpuAttached)
    5686 {
    5687     LogFlowThisFunc(("\n"));
    5688 
    5689     CheckComArgNotNull(aCpuAttached);
    5690 
    5691     *aCpuAttached = false;
    5692 
    5693     AutoCaller autoCaller(this);
    5694     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5695 
    5696     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5697 
    5698     /* If hotplug is enabled the CPU is always enabled. */
    5699     if (!mHWData->mCPUHotPlugEnabled)
    5700     {
    5701         if (aCpu < mHWData->mCPUCount)
    5702             *aCpuAttached = true;
    5703     }
    5704     else
    5705     {
    5706         if (aCpu < SchemaDefs::MaxCPUCount)
    5707             *aCpuAttached = mHWData->mCPUAttached[aCpu];
    5708     }
    5709 
    5710     return S_OK;
    5711 }
    5712 
    5713 STDMETHODIMP Machine::QueryLogFilename(ULONG aIdx, BSTR *aName)
    5714 {
    5715     CheckComArgOutPointerValid(aName);
    5716 
    5717     AutoCaller autoCaller(this);
    5718     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5719 
    5720     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5721 
    5722     Utf8Str log = queryLogFilename(aIdx);
    5723     if (!RTFileExists(log.c_str()))
    5724         log.setNull();
    5725     log.cloneTo(aName);
    5726 
    5727     return S_OK;
    5728 }
    5729 
    5730 STDMETHODIMP Machine::ReadLog(ULONG aIdx, LONG64 aOffset, LONG64 aSize, ComSafeArrayOut(BYTE, aData))
    5731 {
    5732     LogFlowThisFunc(("\n"));
    5733     CheckComArgOutSafeArrayPointerValid(aData);
    5734     if (aSize < 0)
    5735         return setError(E_INVALIDARG, tr("The size argument (%lld) is negative"), aSize);
    5736 
    5737     AutoCaller autoCaller(this);
    5738     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5739 
    5740     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5741 
    5742     HRESULT rc = S_OK;
    5743     Utf8Str log = queryLogFilename(aIdx);
    5744 
    5745     /* do not unnecessarily hold the lock while doing something which does
    5746      * not need the lock and potentially takes a long time. */
    5747     alock.release();
    5748 
    5749     /* Limit the chunk size to 32K for now, as that gives better performance
    5750      * over (XP)COM, and keeps the SOAP reply size under 1M for the webservice.
    5751      * One byte expands to approx. 25 bytes of breathtaking XML. */
    5752     size_t cbData = (size_t)RT_MIN(aSize, 32768);
    5753     com::SafeArray<BYTE> logData(cbData);
    5754 
    5755     RTFILE LogFile;
    5756     int vrc = RTFileOpen(&LogFile, log.c_str(),
    5757                          RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
     157    PSSMHANDLE pSSM;
     158    int vrc = SSMR3Open(strStateFilePath.c_str(), 0 /*fFlags*/, &pSSM);
    5758159    if (RT_SUCCESS(vrc))
    5759160    {
    5760         vrc = RTFileReadAt(LogFile, aOffset, logData.raw(), cbData, &cbData);
     161        uint32_t uVersion;
     162        vrc = SSMR3Seek(pSSM, "DisplayData", 0 /*iInstance*/, &uVersion);
    5761163        if (RT_SUCCESS(vrc))
    5762             logData.resize(cbData);
    5763         else
    5764             rc = setError(VBOX_E_IPRT_ERROR,
    5765                           tr("Could not read log file '%s' (%Rrc)"),
    5766                           log.c_str(), vrc);
    5767         RTFileClose(LogFile);
    5768     }
    5769     else
    5770         rc = setError(VBOX_E_IPRT_ERROR,
    5771                       tr("Could not open log file '%s' (%Rrc)"),
    5772                       log.c_str(), vrc);
    5773 
    5774     if (FAILED(rc))
    5775         logData.resize(0);
    5776     logData.detachTo(ComSafeArrayOutArg(aData));
    5777 
    5778     return rc;
    5779 }
    5780 
    5781 
    5782 // public methods for internal purposes
    5783 /////////////////////////////////////////////////////////////////////////////
    5784 
    5785 /**
    5786  * Adds the given IsModified_* flag to the dirty flags of the machine.
    5787  * This must be called either during loadSettings or under the machine write lock.
    5788  * @param fl
    5789  */
    5790 void Machine::setModified(uint32_t fl)
    5791 {
    5792     mData->flModifications |= fl;
    5793 }
    5794 
    5795 /**
    5796  *  Saves the registry entry of this machine to the given configuration node.
    5797  *
    5798  *  @param aEntryNode Node to save the registry entry to.
    5799  *
    5800  *  @note locks this object for reading.
    5801  */
    5802 HRESULT Machine::saveRegistryEntry(settings::MachineRegistryEntry &data)
    5803 {
    5804     AutoLimitedCaller autoCaller(this);
    5805     AssertComRCReturnRC(autoCaller.rc());
    5806 
    5807     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5808 
    5809     data.uuid = mData->mUuid;
    5810     data.strSettingsFile = mData->m_strConfigFile;
    5811 
    5812     return S_OK;
    5813 }
    5814 
    5815 /**
    5816  * Calculates the absolute path of the given path taking the directory of the
    5817  * machine settings file as the current directory.
    5818  *
    5819  * @param  aPath    Path to calculate the absolute path for.
    5820  * @param  aResult  Where to put the result (used only on success, can be the
    5821  *                  same Utf8Str instance as passed in @a aPath).
    5822  * @return IPRT result.
    5823  *
    5824  * @note Locks this object for reading.
    5825  */
    5826 int Machine::calculateFullPath(const Utf8Str &strPath, Utf8Str &aResult)
    5827 {
    5828     AutoCaller autoCaller(this);
    5829     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    5830 
    5831     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5832 
    5833     AssertReturn(!mData->m_strConfigFileFull.isEmpty(), VERR_GENERAL_FAILURE);
    5834 
    5835     Utf8Str strSettingsDir = mData->m_strConfigFileFull;
    5836 
    5837     strSettingsDir.stripFilename();
    5838     char folder[RTPATH_MAX];
    5839     int vrc = RTPathAbsEx(strSettingsDir.c_str(), strPath.c_str(), folder, sizeof(folder));
    5840     if (RT_SUCCESS(vrc))
    5841         aResult = folder;
    5842 
    5843     return vrc;
    5844 }
    5845 
    5846 /**
    5847  * Copies strSource to strTarget, making it relative to the machine folder
    5848  * if it is a subdirectory thereof, or simply copying it otherwise.
    5849  *
    5850  * @param strSource Path to evalue and copy.
    5851  * @param strTarget Buffer to receive target path.
    5852  *
    5853  * @note Locks this object for reading.
    5854  */
    5855 void Machine::copyPathRelativeToMachine(const Utf8Str &strSource,
    5856                                         Utf8Str &strTarget)
    5857 {
    5858     AutoCaller autoCaller(this);
    5859     AssertComRCReturn(autoCaller.rc(), (void)0);
    5860 
    5861     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5862 
    5863     AssertReturnVoid(!mData->m_strConfigFileFull.isEmpty());
    5864     // use strTarget as a temporary buffer to hold the machine settings dir
    5865     strTarget = mData->m_strConfigFileFull;
    5866     strTarget.stripFilename();
    5867     if (RTPathStartsWith(strSource.c_str(), strTarget.c_str()))
    5868         // is relative: then append what's left
    5869         strTarget.append(strSource.c_str() + strTarget.length());     // include '/'
    5870     else
    5871         // is not relative: then overwrite
    5872         strTarget = strSource;
    5873 }
    5874 
    5875 /**
    5876  *  Returns the full path to the machine's log folder in the
    5877  *  \a aLogFolder argument.
    5878  */
    5879 void Machine::getLogFolder(Utf8Str &aLogFolder)
    5880 {
    5881     AutoCaller autoCaller(this);
    5882     AssertComRCReturnVoid(autoCaller.rc());
    5883 
    5884     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    5885 
    5886     Utf8Str settingsDir;
    5887     if (isInOwnDir(&settingsDir))
    5888         /* Log folder is <Machines>/<VM_Name>/Logs */
    5889         aLogFolder = settingsDir;
    5890     else
    5891     {
    5892         /* Log folder is <Machines>/<VM_SnapshotFolder>/Logs */
    5893         Assert(!mUserData->m_strSnapshotFolderFull.isEmpty());
    5894         aLogFolder = mUserData->m_strSnapshotFolderFull;
    5895     }
    5896 
    5897     aLogFolder.append(RTPATH_DELIMITER);
    5898     aLogFolder.append("Logs");
    5899 }
    5900 
    5901 /**
    5902  *  Returns the full path to the machine's log file for an given index.
    5903  */
    5904 Utf8Str Machine::queryLogFilename(ULONG idx)
    5905 {
    5906     Utf8Str logFolder;
    5907     getLogFolder(logFolder);
    5908     Assert(logFolder.length());
    5909     Utf8Str log;
    5910     if (idx == 0)
    5911         log = Utf8StrFmt("%s%cVBox.log",
    5912                          logFolder.c_str(), RTPATH_DELIMITER);
    5913     else
    5914         log = Utf8StrFmt("%s%cVBox.log.%d",
    5915                          logFolder.c_str(), RTPATH_DELIMITER, idx);
    5916     return log;
    5917 }
    5918 
    5919 /**
    5920  *  @note Locks this object for writing, calls the client process
    5921  *        (inside the lock).
    5922  */
    5923 HRESULT Machine::openRemoteSession(IInternalSessionControl *aControl,
    5924                                    IN_BSTR aType,
    5925                                    IN_BSTR aEnvironment,
    5926                                    ProgressProxy *aProgress)
    5927 {
    5928     LogFlowThisFuncEnter();
    5929 
    5930     AssertReturn(aControl, E_FAIL);
    5931     AssertReturn(aProgress, E_FAIL);
    5932 
    5933     AutoCaller autoCaller(this);
    5934     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    5935 
    5936     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    5937 
    5938     if (!mData->mRegistered)
    5939         return setError(E_UNEXPECTED,
    5940                         tr("The machine '%s' is not registered"),
    5941                         mUserData->s.strName.c_str());
    5942 
    5943     LogFlowThisFunc(("mSession.mState=%s\n", Global::stringifySessionState(mData->mSession.mState)));
    5944 
    5945     if (    mData->mSession.mState == SessionState_Locked
    5946          || mData->mSession.mState == SessionState_Spawning
    5947          || mData->mSession.mState == SessionState_Unlocking)
    5948         return setError(VBOX_E_INVALID_OBJECT_STATE,
    5949                         tr("The machine '%s' is already locked by a session (or being locked or unlocked)"),
    5950                         mUserData->s.strName.c_str());
    5951 
    5952     /* may not be busy */
    5953     AssertReturn(!Global::IsOnlineOrTransient(mData->mMachineState), E_FAIL);
    5954 
    5955     /* get the path to the executable */
    5956     char szPath[RTPATH_MAX];
    5957     RTPathAppPrivateArch(szPath, RTPATH_MAX);
    5958     size_t sz = strlen(szPath);
    5959     szPath[sz++] = RTPATH_DELIMITER;
    5960     szPath[sz] = 0;
    5961     char *cmd = szPath + sz;
    5962     sz = RTPATH_MAX - sz;
    5963 
    5964     int vrc = VINF_SUCCESS;
    5965     RTPROCESS pid = NIL_RTPROCESS;
    5966 
    5967     RTENV env = RTENV_DEFAULT;
    5968 
    5969     if (aEnvironment != NULL && *aEnvironment)
    5970     {
    5971         char *newEnvStr = NULL;
    5972 
    5973         do
    5974164        {
    5975             /* clone the current environment */
    5976             int vrc2 = RTEnvClone(&env, RTENV_DEFAULT);
    5977             AssertRCBreakStmt(vrc2, vrc = vrc2);
    5978 
    5979             newEnvStr = RTStrDup(Utf8Str(aEnvironment).c_str());
    5980             AssertPtrBreakStmt(newEnvStr, vrc = vrc2);
    5981 
    5982             /* put new variables to the environment
    5983              * (ignore empty variable names here since RTEnv API
    5984              * intentionally doesn't do that) */
    5985             char *var = newEnvStr;
    5986             for (char *p = newEnvStr; *p; ++p)
     165            /* Only the second version is supported. */
     166            if (uVersion == sSSMDisplayVer2)
    5987167            {
    5988                 if (*p == '\n' && (p == newEnvStr || *(p - 1) != '\\'))
     168                uint32_t cMonitors;
     169                SSMR3GetU32(pSSM, &cMonitors);
     170                if (u32ScreenId > cMonitors)
     171                    vrc = -2;
     172                else
    5989173                {
    5990                     *p = '\0';
    5991                     if (*var)
    5992                     {
    5993                         char *val = strchr(var, '=');
    5994                         if (val)
    5995                         {
    5996                             *val++ = '\0';
    5997                             vrc2 = RTEnvSetEx(env, var, val);
    5998                         }
    5999                         else
    6000                             vrc2 = RTEnvUnsetEx(env, var);
    6001                         if (RT_FAILURE(vrc2))
    6002                             break;
    6003                     }
    6004                     var = p + 1;
    6005                 }
    6006             }
    6007             if (RT_SUCCESS(vrc2) && *var)
    6008                 vrc2 = RTEnvPutEx(env, var);
    6009 
    6010             AssertRCBreakStmt(vrc2, vrc = vrc2);
    6011         }
    6012         while (0);
    6013 
    6014         if (newEnvStr != NULL)
    6015             RTStrFree(newEnvStr);
    6016     }
    6017 
    6018     Utf8Str strType(aType);
    6019 
    6020     /* Qt is default */
    6021 #ifdef VBOX_WITH_QTGUI
    6022     if (strType == "gui" || strType == "GUI/Qt")
    6023     {
    6024 # ifdef RT_OS_DARWIN /* Avoid Launch Services confusing this with the selector by using a helper app. */
    6025         const char VirtualBox_exe[] = "../Resources/VirtualBoxVM.app/Contents/MacOS/VirtualBoxVM";
    6026 # else
    6027         const char VirtualBox_exe[] = "VirtualBox" HOSTSUFF_EXE;
    6028 # endif
    6029         Assert(sz >= sizeof(VirtualBox_exe));
    6030         strcpy(cmd, VirtualBox_exe);
    6031 
    6032         Utf8Str idStr = mData->mUuid.toString();
    6033         const char * args[] = {szPath, "--comment", mUserData->s.strName.c_str(), "--startvm", idStr.c_str(), "--no-startvm-errormsgbox", 0 };
    6034         vrc = RTProcCreate(szPath, args, env, 0, &pid);
    6035     }
    6036 #else /* !VBOX_WITH_QTGUI */
    6037     if (0)
    6038         ;
    6039 #endif /* VBOX_WITH_QTGUI */
    6040 
    6041     else
    6042 
    6043 #ifdef VBOX_WITH_VBOXSDL
    6044     if (strType == "sdl" || strType == "GUI/SDL")
    6045     {
    6046         const char VBoxSDL_exe[] = "VBoxSDL" HOSTSUFF_EXE;
    6047         Assert(sz >= sizeof(VBoxSDL_exe));
    6048         strcpy(cmd, VBoxSDL_exe);
    6049 
    6050         Utf8Str idStr = mData->mUuid.toString();
    6051         const char * args[] = {szPath, "--comment", mUserData->s.strName.c_str(), "--startvm", idStr.c_str(), 0 };
    6052         vrc = RTProcCreate(szPath, args, env, 0, &pid);
    6053     }
    6054 #else /* !VBOX_WITH_VBOXSDL */
    6055     if (0)
    6056         ;
    6057 #endif /* !VBOX_WITH_VBOXSDL */
    6058 
    6059     else
    6060 
    6061 #ifdef VBOX_WITH_HEADLESS
    6062     if (   strType == "headless"
    6063         || strType == "capture"
    6064 #ifdef VBOX_WITH_VRDP
    6065         || strType == "vrdp"
    6066 #endif
    6067        )
    6068     {
    6069         const char VBoxHeadless_exe[] = "VBoxHeadless" HOSTSUFF_EXE;
    6070         Assert(sz >= sizeof(VBoxHeadless_exe));
    6071         strcpy(cmd, VBoxHeadless_exe);
    6072 
    6073         Utf8Str idStr = mData->mUuid.toString();
    6074         /* Leave space for 2 args, as "headless" needs --vrdp off on non-OSE. */
    6075         const char * args[] = {szPath, "--comment", mUserData->s.strName.c_str(), "--startvm", idStr.c_str(), 0, 0, 0 };
    6076 #ifdef VBOX_WITH_VRDP
    6077         if (strType == "headless")
    6078         {
    6079             unsigned pos = RT_ELEMENTS(args) - 3;
    6080             args[pos++] = "--vrdp";
    6081             args[pos] = "off";
    6082         }
    6083 #endif
    6084         if (strType == "capture")
    6085         {
    6086             unsigned pos = RT_ELEMENTS(args) - 3;
    6087             args[pos] = "--capture";
    6088         }
    6089         vrc = RTProcCreate(szPath, args, env, 0, &pid);
    6090     }
    6091 #else /* !VBOX_WITH_HEADLESS */
    6092     if (0)
    6093         ;
    6094 #endif /* !VBOX_WITH_HEADLESS */
    6095     else
    6096     {
    6097         RTEnvDestroy(env);
    6098         return setError(E_INVALIDARG,
    6099                         tr("Invalid session type: '%s'"),
    6100                         strType.c_str());
    6101     }
    6102 
    6103     RTEnvDestroy(env);
    6104 
    6105     if (RT_FAILURE(vrc))
    6106         return setError(VBOX_E_IPRT_ERROR,
    6107                         tr("Could not launch a process for the machine '%s' (%Rrc)"),
    6108                         mUserData->s.strName.c_str(), vrc);
    6109 
    6110     LogFlowThisFunc(("launched.pid=%d(0x%x)\n", pid, pid));
    6111 
    6112     /*
    6113      *  Note that we don't leave the lock here before calling the client,
    6114      *  because it doesn't need to call us back if called with a NULL argument.
    6115      *  Leaving the lock herer is dangerous because we didn't prepare the
    6116      *  launch data yet, but the client we've just started may happen to be
    6117      *  too fast and call openSession() that will fail (because of PID, etc.),
    6118      *  so that the Machine will never get out of the Spawning session state.
    6119      */
    6120 
    6121     /* inform the session that it will be a remote one */
    6122     LogFlowThisFunc(("Calling AssignMachine (NULL)...\n"));
    6123     HRESULT rc = aControl->AssignMachine(NULL);
    6124     LogFlowThisFunc(("AssignMachine (NULL) returned %08X\n", rc));
    6125 
    6126     if (FAILED(rc))
    6127     {
    6128         /* restore the session state */
    6129         mData->mSession.mState = SessionState_Unlocked;
    6130         /* The failure may occur w/o any error info (from RPC), so provide one */
    6131         return setError(VBOX_E_VM_ERROR,
    6132                         tr("Failed to assign the machine to the session (%Rrc)"), rc);
    6133     }
    6134 
    6135     /* attach launch data to the machine */
    6136     Assert(mData->mSession.mPid == NIL_RTPROCESS);
    6137     mData->mSession.mRemoteControls.push_back (aControl);
    6138     mData->mSession.mProgress = aProgress;
    6139     mData->mSession.mPid = pid;
    6140     mData->mSession.mState = SessionState_Spawning;
    6141     mData->mSession.mType = strType;
    6142 
    6143     LogFlowThisFuncLeave();
    6144     return S_OK;
    6145 }
    6146 
    6147 /**
    6148  * Returns @c true if the given machine has an open direct session and returns
    6149  * the session machine instance and additional session data (on some platforms)
    6150  * if so.
    6151  *
    6152  * Note that when the method returns @c false, the arguments remain unchanged.
    6153  *
    6154  * @param aMachine  Session machine object.
    6155  * @param aControl  Direct session control object (optional).
    6156  * @param aIPCSem   Mutex IPC semaphore handle for this machine (optional).
    6157  *
    6158  * @note locks this object for reading.
    6159  */
    6160 #if defined(RT_OS_WINDOWS)
    6161 bool Machine::isSessionOpen(ComObjPtr<SessionMachine> &aMachine,
    6162                             ComPtr<IInternalSessionControl> *aControl /*= NULL*/,
    6163                             HANDLE *aIPCSem /*= NULL*/,
    6164                             bool aAllowClosing /*= false*/)
    6165 #elif defined(RT_OS_OS2)
    6166 bool Machine::isSessionOpen(ComObjPtr<SessionMachine> &aMachine,
    6167                             ComPtr<IInternalSessionControl> *aControl /*= NULL*/,
    6168                             HMTX *aIPCSem /*= NULL*/,
    6169                             bool aAllowClosing /*= false*/)
    6170 #else
    6171 bool Machine::isSessionOpen(ComObjPtr<SessionMachine> &aMachine,
    6172                             ComPtr<IInternalSessionControl> *aControl /*= NULL*/,
    6173                             bool aAllowClosing /*= false*/)
    6174 #endif
    6175 {
    6176     AutoLimitedCaller autoCaller(this);
    6177     AssertComRCReturn(autoCaller.rc(), false);
    6178 
    6179     /* just return false for inaccessible machines */
    6180     if (autoCaller.state() != Ready)
    6181         return false;
    6182 
    6183     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    6184 
    6185     if (    mData->mSession.mState == SessionState_Locked
    6186          || (aAllowClosing && mData->mSession.mState == SessionState_Unlocking)
    6187        )
    6188     {
    6189         AssertReturn(!mData->mSession.mMachine.isNull(), false);
    6190 
    6191         aMachine = mData->mSession.mMachine;
    6192 
    6193         if (aControl != NULL)
    6194             *aControl = mData->mSession.mDirectControl;
    6195 
    6196 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    6197         /* Additional session data */
    6198         if (aIPCSem != NULL)
    6199             *aIPCSem = aMachine->mIPCSem;
    6200 #endif
    6201         return true;
    6202     }
    6203 
    6204     return false;
    6205 }
    6206 
    6207 /**
    6208  * Returns @c true if the given machine has an spawning direct session and
    6209  * returns and additional session data (on some platforms) if so.
    6210  *
    6211  * Note that when the method returns @c false, the arguments remain unchanged.
    6212  *
    6213  * @param aPID  PID of the spawned direct session process.
    6214  *
    6215  * @note locks this object for reading.
    6216  */
    6217 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    6218 bool Machine::isSessionSpawning(RTPROCESS *aPID /*= NULL*/)
    6219 #else
    6220 bool Machine::isSessionSpawning()
    6221 #endif
    6222 {
    6223     AutoLimitedCaller autoCaller(this);
    6224     AssertComRCReturn(autoCaller.rc(), false);
    6225 
    6226     /* just return false for inaccessible machines */
    6227     if (autoCaller.state() != Ready)
    6228         return false;
    6229 
    6230     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    6231 
    6232     if (mData->mSession.mState == SessionState_Spawning)
    6233     {
    6234 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    6235         /* Additional session data */
    6236         if (aPID != NULL)
    6237         {
    6238             AssertReturn(mData->mSession.mPid != NIL_RTPROCESS, false);
    6239             *aPID = mData->mSession.mPid;
    6240         }
    6241 #endif
    6242         return true;
    6243     }
    6244 
    6245     return false;
    6246 }
    6247 
    6248 /**
    6249  * Called from the client watcher thread to check for unexpected client process
    6250  * death during Session_Spawning state (e.g. before it successfully opened a
    6251  * direct session).
    6252  *
    6253  * On Win32 and on OS/2, this method is called only when we've got the
    6254  * direct client's process termination notification, so it always returns @c
    6255  * true.
    6256  *
    6257  * On other platforms, this method returns @c true if the client process is
    6258  * terminated and @c false if it's still alive.
    6259  *
    6260  * @note Locks this object for writing.
    6261  */
    6262 bool Machine::checkForSpawnFailure()
    6263 {
    6264     AutoCaller autoCaller(this);
    6265     if (!autoCaller.isOk())
    6266     {
    6267         /* nothing to do */
    6268         LogFlowThisFunc(("Already uninitialized!\n"));
    6269         return true;
    6270     }
    6271 
    6272     /* VirtualBox::addProcessToReap() needs a write lock */
    6273     AutoMultiWriteLock2 alock(mParent, this COMMA_LOCKVAL_SRC_POS);
    6274 
    6275     if (mData->mSession.mState != SessionState_Spawning)
    6276     {
    6277         /* nothing to do */
    6278         LogFlowThisFunc(("Not spawning any more!\n"));
    6279         return true;
    6280     }
    6281 
    6282     HRESULT rc = S_OK;
    6283 
    6284 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    6285 
    6286     /* the process was already unexpectedly terminated, we just need to set an
    6287      * error and finalize session spawning */
    6288     rc = setError(E_FAIL,
    6289                   tr("The virtual machine '%ls' has terminated unexpectedly during startup"),
    6290                   getName().c_str());
    6291 #else
    6292 
    6293     /* PID not yet initialized, skip check. */
    6294     if (mData->mSession.mPid == NIL_RTPROCESS)
    6295         return false;
    6296 
    6297     RTPROCSTATUS status;
    6298     int vrc = ::RTProcWait(mData->mSession.mPid, RTPROCWAIT_FLAGS_NOBLOCK,
    6299                            &status);
    6300 
    6301     if (vrc != VERR_PROCESS_RUNNING)
    6302     {
    6303         if (RT_SUCCESS(vrc) && status.enmReason == RTPROCEXITREASON_NORMAL)
    6304             rc = setError(E_FAIL,
    6305                           tr("The virtual machine '%s' has terminated unexpectedly during startup with exit code %d"),
    6306                           getName().c_str(), status.iStatus);
    6307         else if (RT_SUCCESS(vrc) && status.enmReason == RTPROCEXITREASON_SIGNAL)
    6308             rc = setError(E_FAIL,
    6309                           tr("The virtual machine '%s' has terminated unexpectedly during startup because of signal %d"),
    6310                           getName().c_str(), status.iStatus);
    6311         else if (RT_SUCCESS(vrc) && status.enmReason == RTPROCEXITREASON_ABEND)
    6312             rc = setError(E_FAIL,
    6313                           tr("The virtual machine '%s' has terminated abnormally"),
    6314                           getName().c_str(), status.iStatus);
    6315         else
    6316             rc = setError(E_FAIL,
    6317                           tr("The virtual machine '%s' has terminated unexpectedly during startup (%Rrc)"),
    6318                           getName().c_str(), rc);
    6319     }
    6320 
    6321 #endif
    6322 
    6323     if (FAILED(rc))
    6324     {
    6325         /* Close the remote session, remove the remote control from the list
    6326          * and reset session state to Closed (@note keep the code in sync with
    6327          * the relevant part in checkForSpawnFailure()). */
    6328 
    6329         Assert(mData->mSession.mRemoteControls.size() == 1);
    6330         if (mData->mSession.mRemoteControls.size() == 1)
    6331         {
    6332             ErrorInfoKeeper eik;
    6333             mData->mSession.mRemoteControls.front()->Uninitialize();
    6334         }
    6335 
    6336         mData->mSession.mRemoteControls.clear();
    6337         mData->mSession.mState = SessionState_Unlocked;
    6338 
    6339         /* finalize the progress after setting the state */
    6340         if (!mData->mSession.mProgress.isNull())
    6341         {
    6342             mData->mSession.mProgress->notifyComplete(rc);
    6343             mData->mSession.mProgress.setNull();
    6344         }
    6345 
    6346         mParent->addProcessToReap(mData->mSession.mPid);
    6347         mData->mSession.mPid = NIL_RTPROCESS;
    6348 
    6349         mParent->onSessionStateChange(mData->mUuid, SessionState_Unlocked);
    6350         return true;
    6351     }
    6352 
    6353     return false;
    6354 }
    6355 
    6356 /**
    6357  *  Checks whether the machine can be registered. If so, commits and saves
    6358  *  all settings.
    6359  *
    6360  *  @note Must be called from mParent's write lock. Locks this object and
    6361  *  children for writing.
    6362  */
    6363 HRESULT Machine::prepareRegister()
    6364 {
    6365     AssertReturn(mParent->isWriteLockOnCurrentThread(), E_FAIL);
    6366 
    6367     AutoLimitedCaller autoCaller(this);
    6368     AssertComRCReturnRC(autoCaller.rc());
    6369 
    6370     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    6371 
    6372     /* wait for state dependants to drop to zero */
    6373     ensureNoStateDependencies();
    6374 
    6375     if (!mData->mAccessible)
    6376         return setError(VBOX_E_INVALID_OBJECT_STATE,
    6377                         tr("The machine '%s' with UUID {%s} is inaccessible and cannot be registered"),
    6378                         mUserData->s.strName.c_str(),
    6379                         mData->mUuid.toString().c_str());
    6380 
    6381     AssertReturn(autoCaller.state() == Ready, E_FAIL);
    6382 
    6383     if (mData->mRegistered)
    6384         return setError(VBOX_E_INVALID_OBJECT_STATE,
    6385                         tr("The machine '%s' with UUID {%s} is already registered"),
    6386                         mUserData->s.strName.c_str(),
    6387                         mData->mUuid.toString().c_str());
    6388 
    6389     HRESULT rc = S_OK;
    6390 
    6391     // Ensure the settings are saved. If we are going to be registered and
    6392     // no config file exists yet, create it by calling saveSettings() too.
    6393     if (    (mData->flModifications)
    6394          || (!mData->pMachineConfigFile->fileExists())
    6395        )
    6396     {
    6397         rc = saveSettings(NULL);
    6398                 // no need to check whether VirtualBox.xml needs saving too since
    6399                 // we can't have a machine XML file rename pending
    6400         if (FAILED(rc)) return rc;
    6401     }
    6402 
    6403     /* more config checking goes here */
    6404 
    6405     if (SUCCEEDED(rc))
    6406     {
    6407         /* we may have had implicit modifications we want to fix on success */
    6408         commit();
    6409 
    6410         mData->mRegistered = true;
    6411     }
    6412     else
    6413     {
    6414         /* we may have had implicit modifications we want to cancel on failure*/
    6415         rollback(false /* aNotify */);
    6416     }
    6417 
    6418     return rc;
    6419 }
    6420 
    6421 /**
    6422  * Increases the number of objects dependent on the machine state or on the
    6423  * registered state. Guarantees that these two states will not change at least
    6424  * until #releaseStateDependency() is called.
    6425  *
    6426  * Depending on the @a aDepType value, additional state checks may be made.
    6427  * These checks will set extended error info on failure. See
    6428  * #checkStateDependency() for more info.
    6429  *
    6430  * If this method returns a failure, the dependency is not added and the caller
    6431  * is not allowed to rely on any particular machine state or registration state
    6432  * value and may return the failed result code to the upper level.
    6433  *
    6434  * @param aDepType      Dependency type to add.
    6435  * @param aState        Current machine state (NULL if not interested).
    6436  * @param aRegistered   Current registered state (NULL if not interested).
    6437  *
    6438  * @note Locks this object for writing.
    6439  */
    6440 HRESULT Machine::addStateDependency(StateDependency aDepType /* = AnyStateDep */,
    6441                                     MachineState_T *aState /* = NULL */,
    6442                                     BOOL *aRegistered /* = NULL */)
    6443 {
    6444     AutoCaller autoCaller(this);
    6445     AssertComRCReturnRC(autoCaller.rc());
    6446 
    6447     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    6448 
    6449     HRESULT rc = checkStateDependency(aDepType);
    6450     if (FAILED(rc)) return rc;
    6451 
    6452     {
    6453         if (mData->mMachineStateChangePending != 0)
    6454         {
    6455             /* ensureNoStateDependencies() is waiting for state dependencies to
    6456              * drop to zero so don't add more. It may make sense to wait a bit
    6457              * and retry before reporting an error (since the pending state
    6458              * transition should be really quick) but let's just assert for
    6459              * now to see if it ever happens on practice. */
    6460 
    6461             AssertFailed();
    6462 
    6463             return setError(E_ACCESSDENIED,
    6464                             tr("Machine state change is in progress. Please retry the operation later."));
    6465         }
    6466 
    6467         ++mData->mMachineStateDeps;
    6468         Assert(mData->mMachineStateDeps != 0 /* overflow */);
    6469     }
    6470 
    6471     if (aState)
    6472         *aState = mData->mMachineState;
    6473     if (aRegistered)
    6474         *aRegistered = mData->mRegistered;
    6475 
    6476     return S_OK;
    6477 }
    6478 
    6479 /**
    6480  * Decreases the number of objects dependent on the machine state.
    6481  * Must always complete the #addStateDependency() call after the state
    6482  * dependency is no more necessary.
    6483  */
    6484 void Machine::releaseStateDependency()
    6485 {
    6486     AutoCaller autoCaller(this);
    6487     AssertComRCReturnVoid(autoCaller.rc());
    6488 
    6489     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    6490 
    6491     /* releaseStateDependency() w/o addStateDependency()? */
    6492     AssertReturnVoid(mData->mMachineStateDeps != 0);
    6493     -- mData->mMachineStateDeps;
    6494 
    6495     if (mData->mMachineStateDeps == 0)
    6496     {
    6497         /* inform ensureNoStateDependencies() that there are no more deps */
    6498         if (mData->mMachineStateChangePending != 0)
    6499         {
    6500             Assert(mData->mMachineStateDepsSem != NIL_RTSEMEVENTMULTI);
    6501             RTSemEventMultiSignal (mData->mMachineStateDepsSem);
    6502         }
    6503     }
    6504 }
    6505 
    6506 // protected methods
    6507 /////////////////////////////////////////////////////////////////////////////
    6508 
    6509 /**
    6510  *  Performs machine state checks based on the @a aDepType value. If a check
    6511  *  fails, this method will set extended error info, otherwise it will return
    6512  *  S_OK. It is supposed, that on failure, the caller will immedieately return
    6513  *  the return value of this method to the upper level.
    6514  *
    6515  *  When @a aDepType is AnyStateDep, this method always returns S_OK.
    6516  *
    6517  *  When @a aDepType is MutableStateDep, this method returns S_OK only if the
    6518  *  current state of this machine object allows to change settings of the
    6519  *  machine (i.e. the machine is not registered, or registered but not running
    6520  *  and not saved). It is useful to call this method from Machine setters
    6521  *  before performing any change.
    6522  *
    6523  *  When @a aDepType is MutableOrSavedStateDep, this method behaves the same
    6524  *  as for MutableStateDep except that if the machine is saved, S_OK is also
    6525  *  returned. This is useful in setters which allow changing machine
    6526  *  properties when it is in the saved state.
    6527  *
    6528  *  @param aDepType     Dependency type to check.
    6529  *
    6530  *  @note Non Machine based classes should use #addStateDependency() and
    6531  *  #releaseStateDependency() methods or the smart AutoStateDependency
    6532  *  template.
    6533  *
    6534  *  @note This method must be called from under this object's read or write
    6535  *        lock.
    6536  */
    6537 HRESULT Machine::checkStateDependency(StateDependency aDepType)
    6538 {
    6539     switch (aDepType)
    6540     {
    6541         case AnyStateDep:
    6542         {
    6543             break;
    6544         }
    6545         case MutableStateDep:
    6546         {
    6547             if (   mData->mRegistered
    6548                 && (   !isSessionMachine()  /** @todo This was just convered raw; Check if Running and Paused should actually be included here... (Live Migration) */
    6549                     || (   mData->mMachineState != MachineState_Paused
    6550                         && mData->mMachineState != MachineState_Running
    6551                         && mData->mMachineState != MachineState_Aborted
    6552                         && mData->mMachineState != MachineState_Teleported
    6553                         && mData->mMachineState != MachineState_PoweredOff
    6554                        )
    6555                    )
    6556                )
    6557                 return setError(VBOX_E_INVALID_VM_STATE,
    6558                                 tr("The machine is not mutable (state is %s)"),
    6559                                 Global::stringifyMachineState(mData->mMachineState));
    6560             break;
    6561         }
    6562         case MutableOrSavedStateDep:
    6563         {
    6564             if (   mData->mRegistered
    6565                 && (   !isSessionMachine() /** @todo This was just convered raw; Check if Running and Paused should actually be included here... (Live Migration) */
    6566                     || (   mData->mMachineState != MachineState_Paused
    6567                         && mData->mMachineState != MachineState_Running
    6568                         && mData->mMachineState != MachineState_Aborted
    6569                         && mData->mMachineState != MachineState_Teleported
    6570                         && mData->mMachineState != MachineState_Saved
    6571                         && mData->mMachineState != MachineState_PoweredOff
    6572                        )
    6573                    )
    6574                )
    6575                 return setError(VBOX_E_INVALID_VM_STATE,
    6576                                 tr("The machine is not mutable (state is %s)"),
    6577                                 Global::stringifyMachineState(mData->mMachineState));
    6578             break;
    6579         }
    6580     }
    6581 
    6582     return S_OK;
    6583 }
    6584 
    6585 /**
    6586  * Helper to initialize all associated child objects and allocate data
    6587  * structures.
    6588  *
    6589  * This method must be called as a part of the object's initialization procedure
    6590  * (usually done in the #init() method).
    6591  *
    6592  * @note Must be called only from #init() or from #registeredInit().
    6593  */
    6594 HRESULT Machine::initDataAndChildObjects()
    6595 {
    6596     AutoCaller autoCaller(this);
    6597     AssertComRCReturnRC(autoCaller.rc());
    6598     AssertComRCReturn(autoCaller.state() == InInit ||
    6599                       autoCaller.state() == Limited, E_FAIL);
    6600 
    6601     AssertReturn(!mData->mAccessible, E_FAIL);
    6602 
    6603     /* allocate data structures */
    6604     mSSData.allocate();
    6605     mUserData.allocate();
    6606     mHWData.allocate();
    6607     mMediaData.allocate();
    6608     mStorageControllers.allocate();
    6609 
    6610     /* initialize mOSTypeId */
    6611     mUserData->s.strOsType = mParent->getUnknownOSType()->id();
    6612 
    6613     /* create associated BIOS settings object */
    6614     unconst(mBIOSSettings).createObject();
    6615     mBIOSSettings->init(this);
    6616 
    6617 #ifdef VBOX_WITH_VRDP
    6618     /* create an associated VRDPServer object (default is disabled) */
    6619     unconst(mVRDPServer).createObject();
    6620     mVRDPServer->init(this);
    6621 #endif
    6622 
    6623     /* create associated serial port objects */
    6624     for (ULONG slot = 0; slot < RT_ELEMENTS(mSerialPorts); slot++)
    6625     {
    6626         unconst(mSerialPorts[slot]).createObject();
    6627         mSerialPorts[slot]->init(this, slot);
    6628     }
    6629 
    6630     /* create associated parallel port objects */
    6631     for (ULONG slot = 0; slot < RT_ELEMENTS(mParallelPorts); slot++)
    6632     {
    6633         unconst(mParallelPorts[slot]).createObject();
    6634         mParallelPorts[slot]->init(this, slot);
    6635     }
    6636 
    6637     /* create the audio adapter object (always present, default is disabled) */
    6638     unconst(mAudioAdapter).createObject();
    6639     mAudioAdapter->init(this);
    6640 
    6641     /* create the USB controller object (always present, default is disabled) */
    6642     unconst(mUSBController).createObject();
    6643     mUSBController->init(this);
    6644 
    6645     /* create associated network adapter objects */
    6646     for (ULONG slot = 0; slot < RT_ELEMENTS(mNetworkAdapters); slot ++)
    6647     {
    6648         unconst(mNetworkAdapters[slot]).createObject();
    6649         mNetworkAdapters[slot]->init(this, slot);
    6650     }
    6651 
    6652     return S_OK;
    6653 }
    6654 
    6655 /**
    6656  * Helper to uninitialize all associated child objects and to free all data
    6657  * structures.
    6658  *
    6659  * This method must be called as a part of the object's uninitialization
    6660  * procedure (usually done in the #uninit() method).
    6661  *
    6662  * @note Must be called only from #uninit() or from #registeredInit().
    6663  */
    6664 void Machine::uninitDataAndChildObjects()
    6665 {
    6666     AutoCaller autoCaller(this);
    6667     AssertComRCReturnVoid(autoCaller.rc());
    6668     AssertComRCReturnVoid(    autoCaller.state() == InUninit
    6669                            || autoCaller.state() == Limited);
    6670 
    6671     /* uninit all children using addDependentChild()/removeDependentChild()
    6672      * in their init()/uninit() methods */
    6673     uninitDependentChildren();
    6674 
    6675     /* tell all our other child objects we've been uninitialized */
    6676 
    6677     for (ULONG slot = 0; slot < RT_ELEMENTS(mNetworkAdapters); slot++)
    6678     {
    6679         if (mNetworkAdapters[slot])
    6680         {
    6681             mNetworkAdapters[slot]->uninit();
    6682             unconst(mNetworkAdapters[slot]).setNull();
    6683         }
    6684     }
    6685 
    6686     if (mUSBController)
    6687     {
    6688         mUSBController->uninit();
    6689         unconst(mUSBController).setNull();
    6690     }
    6691 
    6692     if (mAudioAdapter)
    6693     {
    6694         mAudioAdapter->uninit();
    6695         unconst(mAudioAdapter).setNull();
    6696     }
    6697 
    6698     for (ULONG slot = 0; slot < RT_ELEMENTS(mParallelPorts); slot++)
    6699     {
    6700         if (mParallelPorts[slot])
    6701         {
    6702             mParallelPorts[slot]->uninit();
    6703             unconst(mParallelPorts[slot]).setNull();
    6704         }
    6705     }
    6706 
    6707     for (ULONG slot = 0; slot < RT_ELEMENTS(mSerialPorts); slot++)
    6708     {
    6709         if (mSerialPorts[slot])
    6710         {
    6711             mSerialPorts[slot]->uninit();
    6712             unconst(mSerialPorts[slot]).setNull();
    6713         }
    6714     }
    6715 
    6716 #ifdef VBOX_WITH_VRDP
    6717     if (mVRDPServer)
    6718     {
    6719         mVRDPServer->uninit();
    6720         unconst(mVRDPServer).setNull();
    6721     }
    6722 #endif
    6723 
    6724     if (mBIOSSettings)
    6725     {
    6726         mBIOSSettings->uninit();
    6727         unconst(mBIOSSettings).setNull();
    6728     }
    6729 
    6730     /* Deassociate hard disks (only when a real Machine or a SnapshotMachine
    6731      * instance is uninitialized; SessionMachine instances refer to real
    6732      * Machine hard disks). This is necessary for a clean re-initialization of
    6733      * the VM after successfully re-checking the accessibility state. Note
    6734      * that in case of normal Machine or SnapshotMachine uninitialization (as
    6735      * a result of unregistering or deleting the snapshot), outdated hard
    6736      * disk attachments will already be uninitialized and deleted, so this
    6737      * code will not affect them. */
    6738     if (    !!mMediaData
    6739          && (!isSessionMachine())
    6740        )
    6741     {
    6742         for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
    6743              it != mMediaData->mAttachments.end();
    6744              ++it)
    6745         {
    6746             ComObjPtr<Medium> hd = (*it)->getMedium();
    6747             if (hd.isNull())
    6748                 continue;
    6749             HRESULT rc = hd->removeBackReference(mData->mUuid, getSnapshotId());
    6750             AssertComRC(rc);
    6751         }
    6752     }
    6753 
    6754     if (!isSessionMachine() && !isSnapshotMachine())
    6755     {
    6756         // clean up the snapshots list (Snapshot::uninit() will handle the snapshot's children recursively)
    6757         if (mData->mFirstSnapshot)
    6758         {
    6759             // snapshots tree is protected by media write lock; strictly
    6760             // this isn't necessary here since we're deleting the entire
    6761             // machine, but otherwise we assert in Snapshot::uninit()
    6762             AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    6763             mData->mFirstSnapshot->uninit();
    6764             mData->mFirstSnapshot.setNull();
    6765         }
    6766 
    6767         mData->mCurrentSnapshot.setNull();
    6768     }
    6769 
    6770     /* free data structures (the essential mData structure is not freed here
    6771      * since it may be still in use) */
    6772     mMediaData.free();
    6773     mStorageControllers.free();
    6774     mHWData.free();
    6775     mUserData.free();
    6776     mSSData.free();
    6777 }
    6778 
    6779 /**
    6780  *  Returns a pointer to the Machine object for this machine that acts like a
    6781  *  parent for complex machine data objects such as shared folders, etc.
    6782  *
    6783  *  For primary Machine objects and for SnapshotMachine objects, returns this
    6784  *  object's pointer itself. For SessoinMachine objects, returns the peer
    6785  *  (primary) machine pointer.
    6786  */
    6787 Machine* Machine::getMachine()
    6788 {
    6789     if (isSessionMachine())
    6790         return (Machine*)mPeer;
    6791     return this;
    6792 }
    6793 
    6794 /**
    6795  * Makes sure that there are no machine state dependants. If necessary, waits
    6796  * for the number of dependants to drop to zero.
    6797  *
    6798  * Make sure this method is called from under this object's write lock to
    6799  * guarantee that no new dependants may be added when this method returns
    6800  * control to the caller.
    6801  *
    6802  * @note Locks this object for writing. The lock will be released while waiting
    6803  *       (if necessary).
    6804  *
    6805  * @warning To be used only in methods that change the machine state!
    6806  */
    6807 void Machine::ensureNoStateDependencies()
    6808 {
    6809     AssertReturnVoid(isWriteLockOnCurrentThread());
    6810 
    6811     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    6812 
    6813     /* Wait for all state dependants if necessary */
    6814     if (mData->mMachineStateDeps != 0)
    6815     {
    6816         /* lazy semaphore creation */
    6817         if (mData->mMachineStateDepsSem == NIL_RTSEMEVENTMULTI)
    6818             RTSemEventMultiCreate(&mData->mMachineStateDepsSem);
    6819 
    6820         LogFlowThisFunc(("Waiting for state deps (%d) to drop to zero...\n",
    6821                           mData->mMachineStateDeps));
    6822 
    6823         ++mData->mMachineStateChangePending;
    6824 
    6825         /* reset the semaphore before waiting, the last dependant will signal
    6826          * it */
    6827         RTSemEventMultiReset(mData->mMachineStateDepsSem);
    6828 
    6829         alock.leave();
    6830 
    6831         RTSemEventMultiWait(mData->mMachineStateDepsSem, RT_INDEFINITE_WAIT);
    6832 
    6833         alock.enter();
    6834 
    6835         -- mData->mMachineStateChangePending;
    6836     }
    6837 }
    6838 
    6839 /**
    6840  * Changes the machine state and informs callbacks.
    6841  *
    6842  * This method is not intended to fail so it either returns S_OK or asserts (and
    6843  * returns a failure).
    6844  *
    6845  * @note Locks this object for writing.
    6846  */
    6847 HRESULT Machine::setMachineState(MachineState_T aMachineState)
    6848 {
    6849     LogFlowThisFuncEnter();
    6850     LogFlowThisFunc(("aMachineState=%s\n", Global::stringifyMachineState(aMachineState) ));
    6851 
    6852     AutoCaller autoCaller(this);
    6853     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    6854 
    6855     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    6856 
    6857     /* wait for state dependants to drop to zero */
    6858     ensureNoStateDependencies();
    6859 
    6860     if (mData->mMachineState != aMachineState)
    6861     {
    6862         mData->mMachineState = aMachineState;
    6863 
    6864         RTTimeNow(&mData->mLastStateChange);
    6865 
    6866         mParent->onMachineStateChange(mData->mUuid, aMachineState);
    6867     }
    6868 
    6869     LogFlowThisFuncLeave();
    6870     return S_OK;
    6871 }
    6872 
    6873 /**
    6874  *  Searches for a shared folder with the given logical name
    6875  *  in the collection of shared folders.
    6876  *
    6877  *  @param aName            logical name of the shared folder
    6878  *  @param aSharedFolder    where to return the found object
    6879  *  @param aSetError        whether to set the error info if the folder is
    6880  *                          not found
    6881  *  @return
    6882  *      S_OK when found or VBOX_E_OBJECT_NOT_FOUND when not found
    6883  *
    6884  *  @note
    6885  *      must be called from under the object's lock!
    6886  */
    6887 HRESULT Machine::findSharedFolder(CBSTR aName,
    6888                                   ComObjPtr<SharedFolder> &aSharedFolder,
    6889                                   bool aSetError /* = false */)
    6890 {
    6891     bool found = false;
    6892     for (HWData::SharedFolderList::const_iterator it = mHWData->mSharedFolders.begin();
    6893         !found && it != mHWData->mSharedFolders.end();
    6894         ++it)
    6895     {
    6896         AutoWriteLock alock(*it COMMA_LOCKVAL_SRC_POS);
    6897         found = (*it)->getName() == aName;
    6898         if (found)
    6899             aSharedFolder = *it;
    6900     }
    6901 
    6902     HRESULT rc = found ? S_OK : VBOX_E_OBJECT_NOT_FOUND;
    6903 
    6904     if (aSetError && !found)
    6905         setError(rc, tr("Could not find a shared folder named '%ls'"), aName);
    6906 
    6907     return rc;
    6908 }
    6909 
    6910 /**
    6911  * Initializes all machine instance data from the given settings structures
    6912  * from XML. The exception is the machine UUID which needs special handling
    6913  * depending on the caller's use case, so the caller needs to set that herself.
    6914  *
    6915  * @param config
    6916  * @param fAllowStorage
    6917  */
    6918 HRESULT Machine::loadMachineDataFromSettings(const settings::MachineConfigFile &config)
    6919 {
    6920     // copy name, description, OS type, teleporter, UTC etc.
    6921     mUserData->s = config.machineUserData;
    6922 
    6923     // look up the object by Id to check it is valid
    6924     ComPtr<IGuestOSType> guestOSType;
    6925     HRESULT rc = mParent->GetGuestOSType(Bstr(mUserData->s.strOsType),
    6926                                          guestOSType.asOutParam());
    6927     if (FAILED(rc)) return rc;
    6928 
    6929     // stateFile (optional)
    6930     if (config.strStateFile.isEmpty())
    6931         mSSData->mStateFilePath.setNull();
    6932     else
    6933     {
    6934         Utf8Str stateFilePathFull(config.strStateFile);
    6935         int vrc = calculateFullPath(stateFilePathFull, stateFilePathFull);
    6936         if (RT_FAILURE(vrc))
    6937             return setError(E_FAIL,
    6938                             tr("Invalid saved state file path '%s' (%Rrc)"),
    6939                             config.strStateFile.c_str(),
    6940                             vrc);
    6941         mSSData->mStateFilePath = stateFilePathFull;
    6942     }
    6943 
    6944     // snapshot folder needs special processing so set it again
    6945     rc = COMSETTER(SnapshotFolder)(Bstr(config.machineUserData.strSnapshotFolder));
    6946     if (FAILED(rc)) return rc;
    6947 
    6948     /* currentStateModified (optional, default is true) */
    6949     mData->mCurrentStateModified = config.fCurrentStateModified;
    6950 
    6951     mData->mLastStateChange = config.timeLastStateChange;
    6952 
    6953     /*
    6954      *  note: all mUserData members must be assigned prior this point because
    6955      *  we need to commit changes in order to let mUserData be shared by all
    6956      *  snapshot machine instances.
    6957      */
    6958     mUserData.commitCopy();
    6959 
    6960     // machine registry, if present (must be loaded before snapshots)
    6961     if (config.canHaveOwnMediaRegistry())
    6962     {
    6963         rc = mParent->initMedia(getId(),         // media registry ID == machine UUID
    6964                                 config.mediaRegistry);
    6965         if (FAILED(rc)) return rc;
    6966     }
    6967 
    6968     /* Snapshot node (optional) */
    6969     size_t cRootSnapshots;
    6970     if ((cRootSnapshots = config.llFirstSnapshot.size()))
    6971     {
    6972         // there must be only one root snapshot
    6973         Assert(cRootSnapshots == 1);
    6974 
    6975         const settings::Snapshot &snap = config.llFirstSnapshot.front();
    6976 
    6977         rc = loadSnapshot(snap,
    6978                           config.uuidCurrentSnapshot,
    6979                           NULL);        // no parent == first snapshot
    6980         if (FAILED(rc)) return rc;
    6981     }
    6982 
    6983     // hardware data
    6984     rc = loadHardware(config.hardwareMachine);
    6985     if (FAILED(rc)) return rc;
    6986 
    6987     // load storage controllers
    6988     rc = loadStorageControllers(config.storageMachine);
    6989     if (FAILED(rc)) return rc;
    6990 
    6991     /*
    6992         *  NOTE: the assignment below must be the last thing to do,
    6993         *  otherwise it will be not possible to change the settings
    6994         *  somewehere in the code above because all setters will be
    6995         *  blocked by checkStateDependency(MutableStateDep).
    6996         */
    6997 
    6998     /* set the machine state to Aborted or Saved when appropriate */
    6999     if (config.fAborted)
    7000     {
    7001         Assert(!mSSData->mStateFilePath.isEmpty());
    7002         mSSData->mStateFilePath.setNull();
    7003 
    7004         /* no need to use setMachineState() during init() */
    7005         mData->mMachineState = MachineState_Aborted;
    7006     }
    7007     else if (!mSSData->mStateFilePath.isEmpty())
    7008     {
    7009         /* no need to use setMachineState() during init() */
    7010         mData->mMachineState = MachineState_Saved;
    7011     }
    7012 
    7013     // after loading settings, we are no longer different from the XML on disk
    7014     mData->flModifications = 0;
    7015 
    7016     return S_OK;
    7017 }
    7018 
    7019 /**
    7020  *  Recursively loads all snapshots starting from the given.
    7021  *
    7022  *  @param aNode            <Snapshot> node.
    7023  *  @param aCurSnapshotId   Current snapshot ID from the settings file.
    7024  *  @param aParentSnapshot  Parent snapshot.
    7025  */
    7026 HRESULT Machine::loadSnapshot(const settings::Snapshot &data,
    7027                               const Guid &aCurSnapshotId,
    7028                               Snapshot *aParentSnapshot)
    7029 {
    7030     AssertReturn(!isSnapshotMachine(), E_FAIL);
    7031     AssertReturn(!isSessionMachine(), E_FAIL);
    7032 
    7033     HRESULT rc = S_OK;
    7034 
    7035     Utf8Str strStateFile;
    7036     if (!data.strStateFile.isEmpty())
    7037     {
    7038         /* optional */
    7039         strStateFile = data.strStateFile;
    7040         int vrc = calculateFullPath(strStateFile, strStateFile);
    7041         if (RT_FAILURE(vrc))
    7042             return setError(E_FAIL,
    7043                             tr("Invalid saved state file path '%s' (%Rrc)"),
    7044                             strStateFile.c_str(),
    7045                             vrc);
    7046     }
    7047 
    7048     /* create a snapshot machine object */
    7049     ComObjPtr<SnapshotMachine> pSnapshotMachine;
    7050     pSnapshotMachine.createObject();
    7051     rc = pSnapshotMachine->init(this,
    7052                                 data.hardware,
    7053                                 data.storage,
    7054                                 data.uuid,
    7055                                 strStateFile);
    7056     if (FAILED(rc)) return rc;
    7057 
    7058     /* create a snapshot object */
    7059     ComObjPtr<Snapshot> pSnapshot;
    7060     pSnapshot.createObject();
    7061     /* initialize the snapshot */
    7062     rc = pSnapshot->init(mParent, // VirtualBox object
    7063                          data.uuid,
    7064                          data.strName,
    7065                          data.strDescription,
    7066                          data.timestamp,
    7067                          pSnapshotMachine,
    7068                          aParentSnapshot);
    7069     if (FAILED(rc)) return rc;
    7070 
    7071     /* memorize the first snapshot if necessary */
    7072     if (!mData->mFirstSnapshot)
    7073         mData->mFirstSnapshot = pSnapshot;
    7074 
    7075     /* memorize the current snapshot when appropriate */
    7076     if (    !mData->mCurrentSnapshot
    7077          && pSnapshot->getId() == aCurSnapshotId
    7078        )
    7079         mData->mCurrentSnapshot = pSnapshot;
    7080 
    7081     // now create the children
    7082     for (settings::SnapshotsList::const_iterator it = data.llChildSnapshots.begin();
    7083          it != data.llChildSnapshots.end();
    7084          ++it)
    7085     {
    7086         const settings::Snapshot &childData = *it;
    7087         // recurse
    7088         rc = loadSnapshot(childData,
    7089                           aCurSnapshotId,
    7090                           pSnapshot);       // parent = the one we created above
    7091         if (FAILED(rc)) return rc;
    7092     }
    7093 
    7094     return rc;
    7095 }
    7096 
    7097 /**
    7098  *  @param aNode    <Hardware> node.
    7099  */
    7100 HRESULT Machine::loadHardware(const settings::Hardware &data)
    7101 {
    7102     AssertReturn(!isSessionMachine(), E_FAIL);
    7103 
    7104     HRESULT rc = S_OK;
    7105 
    7106     try
    7107     {
    7108         /* The hardware version attribute (optional). */
    7109         mHWData->mHWVersion = data.strVersion;
    7110         mHWData->mHardwareUUID = data.uuid;
    7111 
    7112         mHWData->mHWVirtExEnabled             = data.fHardwareVirt;
    7113         mHWData->mHWVirtExExclusive           = data.fHardwareVirtExclusive;
    7114         mHWData->mHWVirtExNestedPagingEnabled = data.fNestedPaging;
    7115         mHWData->mHWVirtExLargePagesEnabled   = data.fLargePages;
    7116         mHWData->mHWVirtExVPIDEnabled         = data.fVPID;
    7117         mHWData->mHWVirtExForceEnabled        = data.fHardwareVirtForce;
    7118         mHWData->mPAEEnabled                  = data.fPAE;
    7119         mHWData->mSyntheticCpu                = data.fSyntheticCpu;
    7120 
    7121         mHWData->mCPUCount                    = data.cCPUs;
    7122         mHWData->mCPUHotPlugEnabled           = data.fCpuHotPlug;
    7123         mHWData->mCpuPriority                 = data.ulCpuPriority;
    7124 
    7125         // cpu
    7126         if (mHWData->mCPUHotPlugEnabled)
    7127         {
    7128             for (settings::CpuList::const_iterator it = data.llCpus.begin();
    7129                 it != data.llCpus.end();
    7130                 ++it)
    7131             {
    7132                 const settings::Cpu &cpu = *it;
    7133 
    7134                 mHWData->mCPUAttached[cpu.ulId] = true;
    7135             }
    7136         }
    7137 
    7138         // cpuid leafs
    7139         for (settings::CpuIdLeafsList::const_iterator it = data.llCpuIdLeafs.begin();
    7140             it != data.llCpuIdLeafs.end();
    7141             ++it)
    7142         {
    7143             const settings::CpuIdLeaf &leaf = *it;
    7144 
    7145             switch (leaf.ulId)
    7146             {
    7147             case 0x0:
    7148             case 0x1:
    7149             case 0x2:
    7150             case 0x3:
    7151             case 0x4:
    7152             case 0x5:
    7153             case 0x6:
    7154             case 0x7:
    7155             case 0x8:
    7156             case 0x9:
    7157             case 0xA:
    7158                 mHWData->mCpuIdStdLeafs[leaf.ulId] = leaf;
    7159                 break;
    7160 
    7161             case 0x80000000:
    7162             case 0x80000001:
    7163             case 0x80000002:
    7164             case 0x80000003:
    7165             case 0x80000004:
    7166             case 0x80000005:
    7167             case 0x80000006:
    7168             case 0x80000007:
    7169             case 0x80000008:
    7170             case 0x80000009:
    7171             case 0x8000000A:
    7172                 mHWData->mCpuIdExtLeafs[leaf.ulId - 0x80000000] = leaf;
    7173                 break;
    7174 
    7175             default:
    7176                 /* just ignore */
    7177                 break;
    7178             }
    7179         }
    7180 
    7181         mHWData->mMemorySize = data.ulMemorySizeMB;
    7182         mHWData->mPageFusionEnabled = data.fPageFusionEnabled;
    7183 
    7184         // boot order
    7185         for (size_t i = 0;
    7186              i < RT_ELEMENTS(mHWData->mBootOrder);
    7187              i++)
    7188         {
    7189             settings::BootOrderMap::const_iterator it = data.mapBootOrder.find(i);
    7190             if (it == data.mapBootOrder.end())
    7191                 mHWData->mBootOrder[i] = DeviceType_Null;
    7192             else
    7193                 mHWData->mBootOrder[i] = it->second;
    7194         }
    7195 
    7196         mHWData->mVRAMSize      = data.ulVRAMSizeMB;
    7197         mHWData->mMonitorCount  = data.cMonitors;
    7198         mHWData->mAccelerate3DEnabled = data.fAccelerate3D;
    7199         mHWData->mAccelerate2DVideoEnabled = data.fAccelerate2DVideo;
    7200         mHWData->mFirmwareType = data.firmwareType;
    7201         mHWData->mPointingHidType = data.pointingHidType;
    7202         mHWData->mKeyboardHidType = data.keyboardHidType;
    7203         mHWData->mChipsetType = data.chipsetType;
    7204         mHWData->mHpetEnabled = data.fHpetEnabled;
    7205 
    7206 #ifdef VBOX_WITH_VRDP
    7207         /* RemoteDisplay */
    7208         rc = mVRDPServer->loadSettings(data.vrdpSettings);
    7209         if (FAILED(rc)) return rc;
    7210 #endif
    7211 
    7212         /* BIOS */
    7213         rc = mBIOSSettings->loadSettings(data.biosSettings);
    7214         if (FAILED(rc)) return rc;
    7215 
    7216         /* USB Controller */
    7217         rc = mUSBController->loadSettings(data.usbController);
    7218         if (FAILED(rc)) return rc;
    7219 
    7220         // network adapters
    7221         for (settings::NetworkAdaptersList::const_iterator it = data.llNetworkAdapters.begin();
    7222             it != data.llNetworkAdapters.end();
    7223             ++it)
    7224         {
    7225             const settings::NetworkAdapter &nic = *it;
    7226 
    7227             /* slot unicity is guaranteed by XML Schema */
    7228             AssertBreak(nic.ulSlot < RT_ELEMENTS(mNetworkAdapters));
    7229             rc = mNetworkAdapters[nic.ulSlot]->loadSettings(nic);
    7230             if (FAILED(rc)) return rc;
    7231         }
    7232 
    7233         // serial ports
    7234         for (settings::SerialPortsList::const_iterator it = data.llSerialPorts.begin();
    7235             it != data.llSerialPorts.end();
    7236             ++it)
    7237         {
    7238             const settings::SerialPort &s = *it;
    7239 
    7240             AssertBreak(s.ulSlot < RT_ELEMENTS(mSerialPorts));
    7241             rc = mSerialPorts[s.ulSlot]->loadSettings(s);
    7242             if (FAILED(rc)) return rc;
    7243         }
    7244 
    7245         // parallel ports (optional)
    7246         for (settings::ParallelPortsList::const_iterator it = data.llParallelPorts.begin();
    7247             it != data.llParallelPorts.end();
    7248             ++it)
    7249         {
    7250             const settings::ParallelPort &p = *it;
    7251 
    7252             AssertBreak(p.ulSlot < RT_ELEMENTS(mParallelPorts));
    7253             rc = mParallelPorts[p.ulSlot]->loadSettings(p);
    7254             if (FAILED(rc)) return rc;
    7255         }
    7256 
    7257         /* AudioAdapter */
    7258         rc = mAudioAdapter->loadSettings(data.audioAdapter);
    7259         if (FAILED(rc)) return rc;
    7260 
    7261         for (settings::SharedFoldersList::const_iterator it = data.llSharedFolders.begin();
    7262              it != data.llSharedFolders.end();
    7263              ++it)
    7264         {
    7265             const settings::SharedFolder &sf = *it;
    7266             rc = CreateSharedFolder(Bstr(sf.strName), Bstr(sf.strHostPath), sf.fWritable, sf.fAutoMount);
    7267             if (FAILED(rc)) return rc;
    7268         }
    7269 
    7270         // Clipboard
    7271         mHWData->mClipboardMode = data.clipboardMode;
    7272 
    7273         // guest settings
    7274         mHWData->mMemoryBalloonSize = data.ulMemoryBalloonSize;
    7275 
    7276         // IO settings
    7277         mHWData->mIoCacheEnabled = data.ioSettings.fIoCacheEnabled;
    7278         mHWData->mIoCacheSize = data.ioSettings.ulIoCacheSize;
    7279 
    7280 #ifdef VBOX_WITH_GUEST_PROPS
    7281         /* Guest properties (optional) */
    7282         for (settings::GuestPropertiesList::const_iterator it = data.llGuestProperties.begin();
    7283             it != data.llGuestProperties.end();
    7284             ++it)
    7285         {
    7286             const settings::GuestProperty &prop = *it;
    7287             uint32_t fFlags = guestProp::NILFLAG;
    7288             guestProp::validateFlags(prop.strFlags.c_str(), &fFlags);
    7289             HWData::GuestProperty property = { prop.strName, prop.strValue, prop.timestamp, fFlags };
    7290             mHWData->mGuestProperties.push_back(property);
    7291         }
    7292 
    7293         mHWData->mGuestPropertyNotificationPatterns = data.strNotificationPatterns;
    7294 #endif /* VBOX_WITH_GUEST_PROPS defined */
    7295     }
    7296     catch(std::bad_alloc &)
    7297     {
    7298         return E_OUTOFMEMORY;
    7299     }
    7300 
    7301     AssertComRC(rc);
    7302     return rc;
    7303 }
    7304 
    7305   /**
    7306    *  @param aNode    <StorageControllers> node.
    7307    */
    7308 HRESULT Machine::loadStorageControllers(const settings::Storage &data,
    7309                                         const Guid *aSnapshotId /* = NULL */)
    7310 {
    7311     AssertReturn(!isSessionMachine(), E_FAIL);
    7312 
    7313     HRESULT rc = S_OK;
    7314 
    7315     for (settings::StorageControllersList::const_iterator it = data.llStorageControllers.begin();
    7316          it != data.llStorageControllers.end();
    7317          ++it)
    7318     {
    7319         const settings::StorageController &ctlData = *it;
    7320 
    7321         ComObjPtr<StorageController> pCtl;
    7322         /* Try to find one with the name first. */
    7323         rc = getStorageControllerByName(ctlData.strName, pCtl, false /* aSetError */);
    7324         if (SUCCEEDED(rc))
    7325             return setError(VBOX_E_OBJECT_IN_USE,
    7326                             tr("Storage controller named '%s' already exists"),
    7327                             ctlData.strName.c_str());
    7328 
    7329         pCtl.createObject();
    7330         rc = pCtl->init(this,
    7331                         ctlData.strName,
    7332                         ctlData.storageBus,
    7333                         ctlData.ulInstance);
    7334         if (FAILED(rc)) return rc;
    7335 
    7336         mStorageControllers->push_back(pCtl);
    7337 
    7338         rc = pCtl->COMSETTER(ControllerType)(ctlData.controllerType);
    7339         if (FAILED(rc)) return rc;
    7340 
    7341         rc = pCtl->COMSETTER(PortCount)(ctlData.ulPortCount);
    7342         if (FAILED(rc)) return rc;
    7343 
    7344         rc = pCtl->COMSETTER(UseHostIOCache)(ctlData.fUseHostIOCache);
    7345         if (FAILED(rc)) return rc;
    7346 
    7347         /* Set IDE emulation settings (only for AHCI controller). */
    7348         if (ctlData.controllerType == StorageControllerType_IntelAhci)
    7349         {
    7350             if (    (FAILED(rc = pCtl->SetIDEEmulationPort(0, ctlData.lIDE0MasterEmulationPort)))
    7351                  || (FAILED(rc = pCtl->SetIDEEmulationPort(1, ctlData.lIDE0SlaveEmulationPort)))
    7352                  || (FAILED(rc = pCtl->SetIDEEmulationPort(2, ctlData.lIDE1MasterEmulationPort)))
    7353                  || (FAILED(rc = pCtl->SetIDEEmulationPort(3, ctlData.lIDE1SlaveEmulationPort)))
    7354                )
    7355                 return rc;
    7356         }
    7357 
    7358         /* Load the attached devices now. */
    7359         rc = loadStorageDevices(pCtl,
    7360                                 ctlData,
    7361                                 aSnapshotId);
    7362         if (FAILED(rc)) return rc;
    7363     }
    7364 
    7365     return S_OK;
    7366 }
    7367 
    7368 /**
    7369  * @param aNode        <HardDiskAttachments> node.
    7370  * @param fAllowStorage if false, we produce an error if the config requests media attachments
    7371  *                      (used with importing unregistered machines which cannot have media attachments)
    7372  * @param aSnapshotId  pointer to the snapshot ID if this is a snapshot machine
    7373  *
    7374  * @note Lock mParent  for reading and hard disks for writing before calling.
    7375  */
    7376 HRESULT Machine::loadStorageDevices(StorageController *aStorageController,
    7377                                     const settings::StorageController &data,
    7378                                     const Guid *aSnapshotId /*= NULL*/)
    7379 {
    7380     HRESULT rc = S_OK;
    7381 
    7382     /* paranoia: detect duplicate attachments */
    7383     for (settings::AttachedDevicesList::const_iterator it = data.llAttachedDevices.begin();
    7384          it != data.llAttachedDevices.end();
    7385          ++it)
    7386     {
    7387         const settings::AttachedDevice &ad = *it;
    7388 
    7389         for (settings::AttachedDevicesList::const_iterator it2 = it;
    7390              it2 != data.llAttachedDevices.end();
    7391              ++it2)
    7392         {
    7393             if (it == it2)
    7394                 continue;
    7395 
    7396             const settings::AttachedDevice &ad2 = *it2;
    7397 
    7398             if (   ad.lPort == ad2.lPort
    7399                 && ad.lDevice == ad2.lDevice)
    7400             {
    7401                 return setError(E_FAIL,
    7402                                 tr("Duplicate attachments for storage controller '%s', port %d, device %d of the virtual machine '%s'"),
    7403                                 aStorageController->getName().c_str(),
    7404                                 ad.lPort,
    7405                                 ad.lDevice,
    7406                                 mUserData->s.strName.c_str());
    7407             }
    7408         }
    7409     }
    7410 
    7411     for (settings::AttachedDevicesList::const_iterator it = data.llAttachedDevices.begin();
    7412          it != data.llAttachedDevices.end();
    7413          ++it)
    7414     {
    7415         const settings::AttachedDevice &dev = *it;
    7416         ComObjPtr<Medium> medium;
    7417 
    7418         switch (dev.deviceType)
    7419         {
    7420             case DeviceType_Floppy:
    7421             case DeviceType_DVD:
    7422                 rc = mParent->findRemoveableMedium(dev.deviceType, dev.uuid, false /* fRefresh */, medium);
    7423                 if (FAILED(rc))
    7424                     return rc;
    7425             break;
    7426 
    7427             case DeviceType_HardDisk:
    7428             {
    7429                 /* find a hard disk by UUID */
    7430                 rc = mParent->findHardDisk(&dev.uuid, Utf8Str::Empty, true /* aDoSetError */, &medium);
    7431                 if (FAILED(rc))
    7432                 {
    7433                     if (isSnapshotMachine())
    7434                     {
    7435                         // wrap another error message around the "cannot find hard disk" set by findHardDisk
    7436                         // so the user knows that the bad disk is in a snapshot somewhere
    7437                         com::ErrorInfo info;
    7438                         return setError(E_FAIL,
    7439                                         tr("A differencing image of snapshot {%RTuuid} could not be found. %ls"),
    7440                                         aSnapshotId->raw(),
    7441                                         info.getText().raw());
    7442                     }
    7443                     else
    7444                         return rc;
    7445                 }
    7446 
    7447                 AutoWriteLock hdLock(medium COMMA_LOCKVAL_SRC_POS);
    7448 
    7449                 if (medium->getType() == MediumType_Immutable)
    7450                 {
    7451                     if (isSnapshotMachine())
    7452                         return setError(E_FAIL,
    7453                                         tr("Immutable hard disk '%s' with UUID {%RTuuid} cannot be directly attached to snapshot with UUID {%RTuuid} "
    7454                                            "of the virtual machine '%s' ('%s')"),
    7455                                         medium->getLocationFull().c_str(),
    7456                                         dev.uuid.raw(),
    7457                                         aSnapshotId->raw(),
    7458                                         mUserData->s.strName.c_str(),
    7459                                         mData->m_strConfigFileFull.c_str());
    7460 
    7461                     return setError(E_FAIL,
    7462                                     tr("Immutable hard disk '%s' with UUID {%RTuuid} cannot be directly attached to the virtual machine '%s' ('%s')"),
    7463                                     medium->getLocationFull().c_str(),
    7464                                     dev.uuid.raw(),
    7465                                     mUserData->s.strName.c_str(),
    7466                                     mData->m_strConfigFileFull.c_str());
    7467                 }
    7468 
    7469                 if (    !isSnapshotMachine()
    7470                      && medium->getChildren().size() != 0
    7471                    )
    7472                     return setError(E_FAIL,
    7473                                     tr("Hard disk '%s' with UUID {%RTuuid} cannot be directly attached to the virtual machine '%s' ('%s') "
    7474                                        "because it has %d differencing child hard disks"),
    7475                                     medium->getLocationFull().c_str(),
    7476                                     dev.uuid.raw(),
    7477                                     mUserData->s.strName.c_str(),
    7478                                     mData->m_strConfigFileFull.c_str(),
    7479                                     medium->getChildren().size());
    7480 
    7481                 if (findAttachment(mMediaData->mAttachments,
    7482                                    medium))
    7483                     return setError(E_FAIL,
    7484                                     tr("Hard disk '%s' with UUID {%RTuuid} is already attached to the virtual machine '%s' ('%s')"),
    7485                                     medium->getLocationFull().c_str(),
    7486                                     dev.uuid.raw(),
    7487                                     mUserData->s.strName.c_str(),
    7488                                     mData->m_strConfigFileFull.c_str());
    7489 
    7490                 break;
    7491             }
    7492 
    7493             default:
    7494                 return setError(E_FAIL,
    7495                                 tr("Device '%s' with unknown type is attached to the virtual machine '%s' ('%s')"),
    7496                                 medium->getLocationFull().c_str(),
    7497                                 mUserData->s.strName.c_str(),
    7498                                 mData->m_strConfigFileFull.c_str());
    7499         }
    7500 
    7501         if (FAILED(rc))
    7502             break;
    7503 
    7504         const Bstr controllerName = aStorageController->getName();
    7505         ComObjPtr<MediumAttachment> pAttachment;
    7506         pAttachment.createObject();
    7507         rc = pAttachment->init(this,
    7508                                medium,
    7509                                controllerName,
    7510                                dev.lPort,
    7511                                dev.lDevice,
    7512                                dev.deviceType,
    7513                                dev.fPassThrough,
    7514                                dev.ulBandwidthLimit);
    7515         if (FAILED(rc)) break;
    7516 
    7517         /* associate the medium with this machine and snapshot */
    7518         if (!medium.isNull())
    7519         {
    7520             if (isSnapshotMachine())
    7521                 rc = medium->addBackReference(mData->mUuid, *aSnapshotId);
    7522             else
    7523                 rc = medium->addBackReference(mData->mUuid);
    7524         }
    7525 
    7526         if (FAILED(rc))
    7527             break;
    7528 
    7529         /* back up mMediaData to let registeredInit() properly rollback on failure
    7530          * (= limited accessibility) */
    7531         setModified(IsModified_Storage);
    7532         mMediaData.backup();
    7533         mMediaData->mAttachments.push_back(pAttachment);
    7534     }
    7535 
    7536     return rc;
    7537 }
    7538 
    7539 /**
    7540  *  Returns the snapshot with the given UUID or fails of no such snapshot exists.
    7541  *
    7542  *  @param aId          snapshot UUID to find (empty UUID refers the first snapshot)
    7543  *  @param aSnapshot    where to return the found snapshot
    7544  *  @param aSetError    true to set extended error info on failure
    7545  */
    7546 HRESULT Machine::findSnapshot(const Guid &aId,
    7547                               ComObjPtr<Snapshot> &aSnapshot,
    7548                               bool aSetError /* = false */)
    7549 {
    7550     AutoReadLock chlock(this COMMA_LOCKVAL_SRC_POS);
    7551 
    7552     if (!mData->mFirstSnapshot)
    7553     {
    7554         if (aSetError)
    7555             return setError(E_FAIL,
    7556                             tr("This machine does not have any snapshots"));
    7557         return E_FAIL;
    7558     }
    7559 
    7560     if (aId.isEmpty())
    7561         aSnapshot = mData->mFirstSnapshot;
    7562     else
    7563         aSnapshot = mData->mFirstSnapshot->findChildOrSelf(aId);
    7564 
    7565     if (!aSnapshot)
    7566     {
    7567         if (aSetError)
    7568             return setError(E_FAIL,
    7569                             tr("Could not find a snapshot with UUID {%s}"),
    7570                             aId.toString().c_str());
    7571         return E_FAIL;
    7572     }
    7573 
    7574     return S_OK;
    7575 }
    7576 
    7577 /**
    7578  *  Returns the snapshot with the given name or fails of no such snapshot.
    7579  *
    7580  *  @param aName        snapshot name to find
    7581  *  @param aSnapshot    where to return the found snapshot
    7582  *  @param aSetError    true to set extended error info on failure
    7583  */
    7584 HRESULT Machine::findSnapshot(IN_BSTR aName,
    7585                               ComObjPtr<Snapshot> &aSnapshot,
    7586                               bool aSetError /* = false */)
    7587 {
    7588     AssertReturn(aName, E_INVALIDARG);
    7589 
    7590     AutoReadLock chlock(this COMMA_LOCKVAL_SRC_POS);
    7591 
    7592     if (!mData->mFirstSnapshot)
    7593     {
    7594         if (aSetError)
    7595             return setError(VBOX_E_OBJECT_NOT_FOUND,
    7596                             tr("This machine does not have any snapshots"));
    7597         return VBOX_E_OBJECT_NOT_FOUND;
    7598     }
    7599 
    7600     aSnapshot = mData->mFirstSnapshot->findChildOrSelf(aName);
    7601 
    7602     if (!aSnapshot)
    7603     {
    7604         if (aSetError)
    7605             return setError(VBOX_E_OBJECT_NOT_FOUND,
    7606                             tr("Could not find a snapshot named '%ls'"), aName);
    7607         return VBOX_E_OBJECT_NOT_FOUND;
    7608     }
    7609 
    7610     return S_OK;
    7611 }
    7612 
    7613 /**
    7614  * Returns a storage controller object with the given name.
    7615  *
    7616  *  @param aName                 storage controller name to find
    7617  *  @param aStorageController    where to return the found storage controller
    7618  *  @param aSetError             true to set extended error info on failure
    7619  */
    7620 HRESULT Machine::getStorageControllerByName(const Utf8Str &aName,
    7621                                             ComObjPtr<StorageController> &aStorageController,
    7622                                             bool aSetError /* = false */)
    7623 {
    7624     AssertReturn(!aName.isEmpty(), E_INVALIDARG);
    7625 
    7626     for (StorageControllerList::const_iterator it = mStorageControllers->begin();
    7627          it != mStorageControllers->end();
    7628          ++it)
    7629     {
    7630         if ((*it)->getName() == aName)
    7631         {
    7632             aStorageController = (*it);
    7633             return S_OK;
    7634         }
    7635     }
    7636 
    7637     if (aSetError)
    7638         return setError(VBOX_E_OBJECT_NOT_FOUND,
    7639                         tr("Could not find a storage controller named '%s'"),
    7640                         aName.c_str());
    7641     return VBOX_E_OBJECT_NOT_FOUND;
    7642 }
    7643 
    7644 HRESULT Machine::getMediumAttachmentsOfController(CBSTR aName,
    7645                                                   MediaData::AttachmentList &atts)
    7646 {
    7647     AutoCaller autoCaller(this);
    7648     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    7649 
    7650     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    7651 
    7652     for (MediaData::AttachmentList::iterator it = mMediaData->mAttachments.begin();
    7653          it != mMediaData->mAttachments.end();
    7654          ++it)
    7655     {
    7656         const ComObjPtr<MediumAttachment> &pAtt = *it;
    7657 
    7658         // should never happen, but deal with NULL pointers in the list.
    7659         AssertStmt(!pAtt.isNull(), continue);
    7660 
    7661         // getControllerName() needs caller+read lock
    7662         AutoCaller autoAttCaller(pAtt);
    7663         if (FAILED(autoAttCaller.rc()))
    7664         {
    7665             atts.clear();
    7666             return autoAttCaller.rc();
    7667         }
    7668         AutoReadLock attLock(pAtt COMMA_LOCKVAL_SRC_POS);
    7669 
    7670         if (pAtt->getControllerName() == aName)
    7671             atts.push_back(pAtt);
    7672     }
    7673 
    7674     return S_OK;
    7675 }
    7676 
    7677 /**
    7678  *  Helper for #saveSettings. Cares about renaming the settings directory and
    7679  *  file if the machine name was changed and about creating a new settings file
    7680  *  if this is a new machine.
    7681  *
    7682  *  @note Must be never called directly but only from #saveSettings().
    7683  */
    7684 HRESULT Machine::prepareSaveSettings(bool *pfNeedsGlobalSaveSettings)
    7685 {
    7686     AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
    7687 
    7688     HRESULT rc = S_OK;
    7689 
    7690     bool fSettingsFileIsNew = !mData->pMachineConfigFile->fileExists();
    7691 
    7692     /* attempt to rename the settings file if machine name is changed */
    7693     if (    mUserData->s.fNameSync
    7694          && mUserData.isBackedUp()
    7695          && mUserData.backedUpData()->s.strName != mUserData->s.strName
    7696        )
    7697     {
    7698         bool dirRenamed = false;
    7699         bool fileRenamed = false;
    7700 
    7701         Utf8Str configFile, newConfigFile;
    7702         Utf8Str configDir, newConfigDir;
    7703 
    7704         do
    7705         {
    7706             int vrc = VINF_SUCCESS;
    7707 
    7708             Utf8Str name = mUserData.backedUpData()->s.strName;
    7709             Utf8Str newName = mUserData->s.strName;
    7710 
    7711             configFile = mData->m_strConfigFileFull;
    7712 
    7713             /* first, rename the directory if it matches the machine name */
    7714             configDir = configFile;
    7715             configDir.stripFilename();
    7716             newConfigDir = configDir;
    7717             if (!strcmp(RTPathFilename(configDir.c_str()), name.c_str()))
    7718             {
    7719                 newConfigDir.stripFilename();
    7720                 newConfigDir.append(RTPATH_DELIMITER);
    7721                 newConfigDir.append(newName);
    7722                 /* new dir and old dir cannot be equal here because of 'if'
    7723                  * above and because name != newName */
    7724                 Assert(configDir != newConfigDir);
    7725                 if (!fSettingsFileIsNew)
    7726                 {
    7727                     /* perform real rename only if the machine is not new */
    7728                     vrc = RTPathRename(configDir.c_str(), newConfigDir.c_str(), 0);
    7729                     if (RT_FAILURE(vrc))
    7730                     {
    7731                         rc = setError(E_FAIL,
    7732                                       tr("Could not rename the directory '%s' to '%s' to save the settings file (%Rrc)"),
    7733                                       configDir.c_str(),
    7734                                       newConfigDir.c_str(),
    7735                                       vrc);
    7736                         break;
    7737                     }
    7738                     dirRenamed = true;
    7739                 }
    7740             }
    7741 
    7742             newConfigFile = Utf8StrFmt("%s%c%s.xml",
    7743                 newConfigDir.c_str(), RTPATH_DELIMITER, newName.c_str());
    7744 
    7745             /* then try to rename the settings file itself */
    7746             if (newConfigFile != configFile)
    7747             {
    7748                 /* get the path to old settings file in renamed directory */
    7749                 configFile = Utf8StrFmt("%s%c%s",
    7750                                         newConfigDir.c_str(),
    7751                                         RTPATH_DELIMITER,
    7752                                         RTPathFilename(configFile.c_str()));
    7753                 if (!fSettingsFileIsNew)
    7754                 {
    7755                     /* perform real rename only if the machine is not new */
    7756                     vrc = RTFileRename(configFile.c_str(), newConfigFile.c_str(), 0);
    7757                     if (RT_FAILURE(vrc))
    7758                     {
    7759                         rc = setError(E_FAIL,
    7760                                       tr("Could not rename the settings file '%s' to '%s' (%Rrc)"),
    7761                                       configFile.c_str(),
    7762                                       newConfigFile.c_str(),
    7763                                       vrc);
    7764                         break;
    7765                     }
    7766                     fileRenamed = true;
    7767                 }
    7768             }
    7769 
    7770             /* update m_strConfigFileFull amd mConfigFile */
    7771             mData->m_strConfigFileFull = newConfigFile;
    7772             // compute the relative path too
    7773             mParent->copyPathRelativeToConfig(newConfigFile, mData->m_strConfigFile);
    7774 
    7775             // store the old and new so that VirtualBox::saveSettings() can update
    7776             // the media registry
    7777             if (    mData->mRegistered
    7778                  && configDir != newConfigDir)
    7779             {
    7780                 mParent->rememberMachineNameChangeForMedia(configDir, newConfigDir);
    7781 
    7782                 if (pfNeedsGlobalSaveSettings)
    7783                     *pfNeedsGlobalSaveSettings = true;
    7784             }
    7785 
    7786             /* update the snapshot folder */
    7787             if (RTPathStartsWith(mUserData->m_strSnapshotFolderFull.c_str(),
    7788                                  configDir.c_str()))
    7789             {
    7790                 mUserData->m_strSnapshotFolderFull = Utf8StrFmt("%s%s",
    7791                                                                 newConfigDir.c_str(),
    7792                                                                 mUserData->m_strSnapshotFolderFull.c_str() + configDir.length());
    7793                 copyPathRelativeToMachine(mUserData->m_strSnapshotFolderFull,
    7794                                           mUserData->s.strSnapshotFolder);
    7795             }
    7796 
    7797             /* update the saved state file path */
    7798             Utf8Str path = mSSData->mStateFilePath;
    7799             if (RTPathStartsWith(path.c_str(), configDir.c_str()))
    7800                 mSSData->mStateFilePath = Utf8StrFmt("%s%s",
    7801                                                      newConfigDir.c_str(),
    7802                                                      path.c_str() + configDir.length());
    7803 
    7804             /* Update saved state file paths of all online snapshots.
    7805              * Note that saveSettings() will recognize name change
    7806              * and will save all snapshots in this case. */
    7807             if (mData->mFirstSnapshot)
    7808                 mData->mFirstSnapshot->updateSavedStatePaths(configDir.c_str(),
    7809                                                              newConfigDir.c_str());
    7810         }
    7811         while (0);
    7812 
    7813         if (FAILED(rc))
    7814         {
    7815             /* silently try to rename everything back */
    7816             if (fileRenamed)
    7817                 RTFileRename(newConfigFile.c_str(), configFile.c_str(), 0);
    7818             if (dirRenamed)
    7819                 RTPathRename(newConfigDir.c_str(), configDir.c_str(), 0);
    7820         }
    7821 
    7822         if (FAILED(rc)) return rc;
    7823     }
    7824 
    7825     if (fSettingsFileIsNew)
    7826     {
    7827         /* create a virgin config file */
    7828         int vrc = VINF_SUCCESS;
    7829 
    7830         /* ensure the settings directory exists */
    7831         Utf8Str path(mData->m_strConfigFileFull);
    7832         path.stripFilename();
    7833         if (!RTDirExists(path.c_str()))
    7834         {
    7835             vrc = RTDirCreateFullPath(path.c_str(), 0777);
    7836             if (RT_FAILURE(vrc))
    7837             {
    7838                 return setError(E_FAIL,
    7839                                 tr("Could not create a directory '%s' to save the settings file (%Rrc)"),
    7840                                 path.c_str(),
    7841                                 vrc);
    7842             }
    7843         }
    7844 
    7845         /* Note: open flags must correlate with RTFileOpen() in lockConfig() */
    7846         path = Utf8Str(mData->m_strConfigFileFull);
    7847         RTFILE f = NIL_RTFILE;
    7848         vrc = RTFileOpen(&f, path.c_str(),
    7849                          RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
    7850         if (RT_FAILURE(vrc))
    7851             return setError(E_FAIL,
    7852                             tr("Could not create the settings file '%s' (%Rrc)"),
    7853                             path.c_str(),
    7854                             vrc);
    7855         RTFileClose(f);
    7856     }
    7857 
    7858     return rc;
    7859 }
    7860 
    7861 /**
    7862  * Saves and commits machine data, user data and hardware data.
    7863  *
    7864  * Note that on failure, the data remains uncommitted.
    7865  *
    7866  * @a aFlags may combine the following flags:
    7867  *
    7868  *  - SaveS_ResetCurStateModified: Resets mData->mCurrentStateModified to FALSE.
    7869  *    Used when saving settings after an operation that makes them 100%
    7870  *    correspond to the settings from the current snapshot.
    7871  *  - SaveS_InformCallbacksAnyway: Callbacks will be informed even if
    7872  *    #isReallyModified() returns false. This is necessary for cases when we
    7873  *    change machine data directly, not through the backup()/commit() mechanism.
    7874  *  - SaveS_Force: settings will be saved without doing a deep compare of the
    7875  *    settings structures. This is used when this is called because snapshots
    7876  *    have changed to avoid the overhead of the deep compare.
    7877  *
    7878  * @note Must be called from under this object's write lock. Locks children for
    7879  * writing.
    7880  *
    7881  * @param pfNeedsGlobalSaveSettings Optional pointer to a bool that must have been
    7882  *          initialized to false and that will be set to true by this function if
    7883  *          the caller must invoke VirtualBox::saveSettings() because the global
    7884  *          settings have changed. This will happen if a machine rename has been
    7885  *          saved and the global machine and media registries will therefore need
    7886  *          updating.
    7887  */
    7888 HRESULT Machine::saveSettings(bool *pfNeedsGlobalSaveSettings,
    7889                               int aFlags /*= 0*/)
    7890 {
    7891     LogFlowThisFuncEnter();
    7892 
    7893     AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
    7894 
    7895     /* make sure child objects are unable to modify the settings while we are
    7896      * saving them */
    7897     ensureNoStateDependencies();
    7898 
    7899     AssertReturn(!isSnapshotMachine(),
    7900                  E_FAIL);
    7901 
    7902     HRESULT rc = S_OK;
    7903     bool fNeedsWrite = false;
    7904 
    7905     /* First, prepare to save settings. It will care about renaming the
    7906      * settings directory and file if the machine name was changed and about
    7907      * creating a new settings file if this is a new machine. */
    7908     rc = prepareSaveSettings(pfNeedsGlobalSaveSettings);
    7909     if (FAILED(rc)) return rc;
    7910 
    7911     // keep a pointer to the current settings structures
    7912     settings::MachineConfigFile *pOldConfig = mData->pMachineConfigFile;
    7913     settings::MachineConfigFile *pNewConfig = NULL;
    7914 
    7915     try
    7916     {
    7917         // make a fresh one to have everyone write stuff into
    7918         pNewConfig = new settings::MachineConfigFile(NULL);
    7919         pNewConfig->copyBaseFrom(*mData->pMachineConfigFile);
    7920 
    7921         // now go and copy all the settings data from COM to the settings structures
    7922         // (this calles saveSettings() on all the COM objects in the machine)
    7923         copyMachineDataToSettings(*pNewConfig);
    7924 
    7925         if (aFlags & SaveS_ResetCurStateModified)
    7926         {
    7927             // this gets set by takeSnapshot() (if offline snapshot) and restoreSnapshot()
    7928             mData->mCurrentStateModified = FALSE;
    7929             fNeedsWrite = true;     // always, no need to compare
    7930         }
    7931         else if (aFlags & SaveS_Force)
    7932         {
    7933             fNeedsWrite = true;     // always, no need to compare
    7934         }
    7935         else
    7936         {
    7937             if (!mData->mCurrentStateModified)
    7938             {
    7939                 // do a deep compare of the settings that we just saved with the settings
    7940                 // previously stored in the config file; this invokes MachineConfigFile::operator==
    7941                 // which does a deep compare of all the settings, which is expensive but less expensive
    7942                 // than writing out XML in vain
    7943                 bool fAnySettingsChanged = (*pNewConfig == *pOldConfig);
    7944 
    7945                 // could still be modified if any settings changed
    7946                 mData->mCurrentStateModified = fAnySettingsChanged;
    7947 
    7948                 fNeedsWrite = fAnySettingsChanged;
    7949             }
    7950             else
    7951                 fNeedsWrite = true;
    7952         }
    7953 
    7954         pNewConfig->fCurrentStateModified = !!mData->mCurrentStateModified;
    7955 
    7956         if (fNeedsWrite)
    7957             // now spit it all out!
    7958             pNewConfig->write(mData->m_strConfigFileFull);
    7959 
    7960         mData->pMachineConfigFile = pNewConfig;
    7961         delete pOldConfig;
    7962         commit();
    7963 
    7964         // after saving settings, we are no longer different from the XML on disk
    7965         mData->flModifications = 0;
    7966     }
    7967     catch (HRESULT err)
    7968     {
    7969         // we assume that error info is set by the thrower
    7970         rc = err;
    7971 
    7972         // restore old config
    7973         delete pNewConfig;
    7974         mData->pMachineConfigFile = pOldConfig;
    7975     }
    7976     catch (...)
    7977     {
    7978         rc = VirtualBox::handleUnexpectedExceptions(RT_SRC_POS);
    7979     }
    7980 
    7981     if (fNeedsWrite || (aFlags & SaveS_InformCallbacksAnyway))
    7982     {
    7983         /* Fire the data change event, even on failure (since we've already
    7984          * committed all data). This is done only for SessionMachines because
    7985          * mutable Machine instances are always not registered (i.e. private
    7986          * to the client process that creates them) and thus don't need to
    7987          * inform callbacks. */
    7988         if (isSessionMachine())
    7989             mParent->onMachineDataChange(mData->mUuid);
    7990     }
    7991 
    7992     LogFlowThisFunc(("rc=%08X\n", rc));
    7993     LogFlowThisFuncLeave();
    7994     return rc;
    7995 }
    7996 
    7997 /**
    7998  * Implementation for saving the machine settings into the given
    7999  * settings::MachineConfigFile instance. This copies machine extradata
    8000  * from the previous machine config file in the instance data, if any.
    8001  *
    8002  * This gets called from two locations:
    8003  *
    8004  *  --  Machine::saveSettings(), during the regular XML writing;
    8005  *
    8006  *  --  Appliance::buildXMLForOneVirtualSystem(), when a machine gets
    8007  *      exported to OVF and we write the VirtualBox proprietary XML
    8008  *      into a <vbox:Machine> tag.
    8009  *
    8010  * This routine fills all the fields in there, including snapshots, *except*
    8011  * for the following:
    8012  *
    8013  * -- fCurrentStateModified. There is some special logic associated with that.
    8014  *
    8015  * The caller can then call MachineConfigFile::write() or do something else
    8016  * with it.
    8017  *
    8018  * Caller must hold the machine lock!
    8019  *
    8020  * This throws XML errors and HRESULT, so the caller must have a catch block!
    8021  */
    8022 void Machine::copyMachineDataToSettings(settings::MachineConfigFile &config)
    8023 {
    8024     // deep copy extradata
    8025     config.mapExtraDataItems = mData->pMachineConfigFile->mapExtraDataItems;
    8026 
    8027     config.uuid = mData->mUuid;
    8028 
    8029     // copy name, description, OS type, teleport, UTC etc.
    8030     config.machineUserData = mUserData->s;
    8031 
    8032     if (    mData->mMachineState == MachineState_Saved
    8033          || mData->mMachineState == MachineState_Restoring
    8034             // when deleting a snapshot we may or may not have a saved state in the current state,
    8035             // so let's not assert here please
    8036          || (    (   mData->mMachineState == MachineState_DeletingSnapshot
    8037                   || mData->mMachineState == MachineState_DeletingSnapshotOnline
    8038                   || mData->mMachineState == MachineState_DeletingSnapshotPaused)
    8039               && (!mSSData->mStateFilePath.isEmpty())
    8040             )
    8041         )
    8042     {
    8043         Assert(!mSSData->mStateFilePath.isEmpty());
    8044         /* try to make the file name relative to the settings file dir */
    8045         copyPathRelativeToMachine(mSSData->mStateFilePath, config.strStateFile);
    8046     }
    8047     else
    8048     {
    8049         Assert(mSSData->mStateFilePath.isEmpty());
    8050         config.strStateFile.setNull();
    8051     }
    8052 
    8053     if (mData->mCurrentSnapshot)
    8054         config.uuidCurrentSnapshot = mData->mCurrentSnapshot->getId();
    8055     else
    8056         config.uuidCurrentSnapshot.clear();
    8057 
    8058     config.timeLastStateChange = mData->mLastStateChange;
    8059     config.fAborted = (mData->mMachineState == MachineState_Aborted);
    8060     /// @todo Live Migration:        config.fTeleported = (mData->mMachineState == MachineState_Teleported);
    8061 
    8062     HRESULT rc = saveHardware(config.hardwareMachine);
    8063     if (FAILED(rc)) throw rc;
    8064 
    8065     rc = saveStorageControllers(config.storageMachine);
    8066     if (FAILED(rc)) throw rc;
    8067 
    8068     // save machine's media registry if this is VirtualBox 4.0 or later
    8069     if (config.canHaveOwnMediaRegistry())
    8070         mParent->saveMediaRegistry(config.mediaRegistry,
    8071                                    getId());            // only media with registry ID == machine UUID
    8072             // this throws HRESULT
    8073 
    8074     // save snapshots
    8075     rc = saveAllSnapshots(config);
    8076     if (FAILED(rc)) throw rc;
    8077 }
    8078 
    8079 /**
    8080  * Saves all snapshots of the machine into the given machine config file. Called
    8081  * from Machine::buildMachineXML() and SessionMachine::deleteSnapshotHandler().
    8082  * @param config
    8083  * @return
    8084  */
    8085 HRESULT Machine::saveAllSnapshots(settings::MachineConfigFile &config)
    8086 {
    8087     AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
    8088 
    8089     HRESULT rc = S_OK;
    8090 
    8091     try
    8092     {
    8093         config.llFirstSnapshot.clear();
    8094 
    8095         if (mData->mFirstSnapshot)
    8096         {
    8097             settings::Snapshot snapNew;
    8098             config.llFirstSnapshot.push_back(snapNew);
    8099 
    8100             // get reference to the fresh copy of the snapshot on the list and
    8101             // work on that copy directly to avoid excessive copying later
    8102             settings::Snapshot &snap = config.llFirstSnapshot.front();
    8103 
    8104             rc = mData->mFirstSnapshot->saveSnapshot(snap, false /*aAttrsOnly*/);
    8105             if (FAILED(rc)) throw rc;
    8106         }
    8107 
    8108 //         if (mType == IsSessionMachine)
    8109 //             mParent->onMachineDataChange(mData->mUuid);          @todo is this necessary?
    8110 
    8111     }
    8112     catch (HRESULT err)
    8113     {
    8114         /* we assume that error info is set by the thrower */
    8115         rc = err;
    8116     }
    8117     catch (...)
    8118     {
    8119         rc = VirtualBox::handleUnexpectedExceptions(RT_SRC_POS);
    8120     }
    8121 
    8122     return rc;
    8123 }
    8124 
    8125 /**
    8126  *  Saves the VM hardware configuration. It is assumed that the
    8127  *  given node is empty.
    8128  *
    8129  *  @param aNode    <Hardware> node to save the VM hardware confguration to.
    8130  */
    8131 HRESULT Machine::saveHardware(settings::Hardware &data)
    8132 {
    8133     HRESULT rc = S_OK;
    8134 
    8135     try
    8136     {
    8137         /* The hardware version attribute (optional).
    8138             Automatically upgrade from 1 to 2 when there is no saved state. (ugly!) */
    8139         if (    mHWData->mHWVersion == "1"
    8140              && mSSData->mStateFilePath.isEmpty()
    8141            )
    8142             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. */
    8143 
    8144         data.strVersion = mHWData->mHWVersion;
    8145         data.uuid = mHWData->mHardwareUUID;
    8146 
    8147         // CPU
    8148         data.fHardwareVirt          = !!mHWData->mHWVirtExEnabled;
    8149         data.fHardwareVirtExclusive = !!mHWData->mHWVirtExExclusive;
    8150         data.fNestedPaging          = !!mHWData->mHWVirtExNestedPagingEnabled;
    8151         data.fLargePages            = !!mHWData->mHWVirtExLargePagesEnabled;
    8152         data.fVPID                  = !!mHWData->mHWVirtExVPIDEnabled;
    8153         data.fHardwareVirtForce     = !!mHWData->mHWVirtExForceEnabled;
    8154         data.fPAE                   = !!mHWData->mPAEEnabled;
    8155         data.fSyntheticCpu          = !!mHWData->mSyntheticCpu;
    8156 
    8157         /* Standard and Extended CPUID leafs. */
    8158         data.llCpuIdLeafs.clear();
    8159         for (unsigned idx = 0; idx < RT_ELEMENTS(mHWData->mCpuIdStdLeafs); idx++)
    8160         {
    8161             if (mHWData->mCpuIdStdLeafs[idx].ulId != UINT32_MAX)
    8162                 data.llCpuIdLeafs.push_back(mHWData->mCpuIdStdLeafs[idx]);
    8163         }
    8164         for (unsigned idx = 0; idx < RT_ELEMENTS(mHWData->mCpuIdExtLeafs); idx++)
    8165         {
    8166             if (mHWData->mCpuIdExtLeafs[idx].ulId != UINT32_MAX)
    8167                 data.llCpuIdLeafs.push_back(mHWData->mCpuIdExtLeafs[idx]);
    8168         }
    8169 
    8170         data.cCPUs         = mHWData->mCPUCount;
    8171         data.fCpuHotPlug   = !!mHWData->mCPUHotPlugEnabled;
    8172         data.ulCpuPriority = mHWData->mCpuPriority;
    8173 
    8174         data.llCpus.clear();
    8175         if (data.fCpuHotPlug)
    8176         {
    8177             for (unsigned idx = 0; idx < data.cCPUs; idx++)
    8178             {
    8179                 if (mHWData->mCPUAttached[idx])
    8180                 {
    8181                     settings::Cpu cpu;
    8182                     cpu.ulId = idx;
    8183                     data.llCpus.push_back(cpu);
     174                    /* Skip all previous monitors and the first 3 entries. */
     175                    SSMR3Skip(pSSM, u32ScreenId * 5 * sizeof(uint32_t) + 3 * sizeof(uint32_t));
     176                    SSMR3GetU32(pSSM, &u32Width);
     177                    SSMR3GetU32(pSSM, &u32Height);
    8184178                }
    8185179            }
    8186180        }
    8187181
    8188         // memory
    8189         data.ulMemorySizeMB = mHWData->mMemorySize;
    8190         data.fPageFusionEnabled = mHWData->mPageFusionEnabled;
    8191 
    8192         // firmware
    8193         data.firmwareType = mHWData->mFirmwareType;
    8194 
    8195         // HID
    8196         data.pointingHidType = mHWData->mPointingHidType;
    8197         data.keyboardHidType = mHWData->mKeyboardHidType;
    8198 
    8199         // chipset
    8200         data.chipsetType = mHWData->mChipsetType;
    8201 
    8202         // HPET
    8203         data.fHpetEnabled = !!mHWData->mHpetEnabled;
    8204 
    8205         // boot order
    8206         data.mapBootOrder.clear();
    8207         for (size_t i = 0;
    8208              i < RT_ELEMENTS(mHWData->mBootOrder);
    8209              ++i)
    8210             data.mapBootOrder[i] = mHWData->mBootOrder[i];
    8211 
    8212         // display
    8213         data.ulVRAMSizeMB = mHWData->mVRAMSize;
    8214         data.cMonitors = mHWData->mMonitorCount;
    8215         data.fAccelerate3D = !!mHWData->mAccelerate3DEnabled;
    8216         data.fAccelerate2DVideo = !!mHWData->mAccelerate2DVideoEnabled;
    8217 
    8218 #ifdef VBOX_WITH_VRDP
    8219         /* VRDP settings (optional) */
    8220         rc = mVRDPServer->saveSettings(data.vrdpSettings);
    8221         if (FAILED(rc)) throw rc;
    8222 #endif
    8223 
    8224         /* BIOS (required) */
    8225         rc = mBIOSSettings->saveSettings(data.biosSettings);
    8226         if (FAILED(rc)) throw rc;
    8227 
    8228         /* USB Controller (required) */
    8229         rc = mUSBController->saveSettings(data.usbController);
    8230         if (FAILED(rc)) throw rc;
    8231 
    8232         /* Network adapters (required) */
    8233         data.llNetworkAdapters.clear();
    8234         for (ULONG slot = 0;
    8235              slot < RT_ELEMENTS(mNetworkAdapters);
    8236              ++slot)
    8237         {
    8238             settings::NetworkAdapter nic;
    8239             nic.ulSlot = slot;
    8240             rc = mNetworkAdapters[slot]->saveSettings(nic);
    8241             if (FAILED(rc)) throw rc;
    8242 
    8243             data.llNetworkAdapters.push_back(nic);
    8244         }
    8245 
    8246         /* Serial ports */
    8247         data.llSerialPorts.clear();
    8248         for (ULONG slot = 0;
    8249              slot < RT_ELEMENTS(mSerialPorts);
    8250              ++slot)
    8251         {
    8252             settings::SerialPort s;
    8253             s.ulSlot = slot;
    8254             rc = mSerialPorts[slot]->saveSettings(s);
    8255             if (FAILED(rc)) return rc;
    8256 
    8257             data.llSerialPorts.push_back(s);
    8258         }
    8259 
    8260         /* Parallel ports */
    8261         data.llParallelPorts.clear();
    8262         for (ULONG slot = 0;
    8263              slot < RT_ELEMENTS(mParallelPorts);
    8264              ++slot)
    8265         {
    8266             settings::ParallelPort p;
    8267             p.ulSlot = slot;
    8268             rc = mParallelPorts[slot]->saveSettings(p);
    8269             if (FAILED(rc)) return rc;
    8270 
    8271             data.llParallelPorts.push_back(p);
    8272         }
    8273 
    8274         /* Audio adapter */
    8275         rc = mAudioAdapter->saveSettings(data.audioAdapter);
    8276         if (FAILED(rc)) return rc;
    8277 
    8278         /* Shared folders */
    8279         data.llSharedFolders.clear();
    8280         for (HWData::SharedFolderList::const_iterator it = mHWData->mSharedFolders.begin();
    8281             it != mHWData->mSharedFolders.end();
    8282             ++it)
    8283         {
    8284             ComObjPtr<SharedFolder> pFolder = *it;
    8285             settings::SharedFolder sf;
    8286             sf.strName = pFolder->getName();
    8287             sf.strHostPath = pFolder->getHostPath();
    8288             sf.fWritable = !!pFolder->isWritable();
    8289             sf.fAutoMount = !!pFolder->isAutoMounted();
    8290 
    8291             data.llSharedFolders.push_back(sf);
    8292         }
    8293 
    8294         // clipboard
    8295         data.clipboardMode = mHWData->mClipboardMode;
    8296 
    8297         /* Guest */
    8298         data.ulMemoryBalloonSize = mHWData->mMemoryBalloonSize;
    8299 
    8300         // IO settings
    8301         data.ioSettings.fIoCacheEnabled = !!mHWData->mIoCacheEnabled;
    8302         data.ioSettings.ulIoCacheSize = mHWData->mIoCacheSize;
    8303 
    8304         // guest properties
    8305         data.llGuestProperties.clear();
    8306 #ifdef VBOX_WITH_GUEST_PROPS
    8307         for (HWData::GuestPropertyList::const_iterator it = mHWData->mGuestProperties.begin();
    8308              it != mHWData->mGuestProperties.end();
    8309              ++it)
    8310         {
    8311             HWData::GuestProperty property = *it;
    8312 
    8313             /* Remove transient guest properties at shutdown unless we
    8314              * are saving state */
    8315             if (   (   mData->mMachineState == MachineState_PoweredOff
    8316                     || mData->mMachineState == MachineState_Aborted
    8317                     || mData->mMachineState == MachineState_Teleported)
    8318                 && property.mFlags & guestProp::TRANSIENT)
    8319                 continue;
    8320             settings::GuestProperty prop;
    8321             prop.strName = property.strName;
    8322             prop.strValue = property.strValue;
    8323             prop.timestamp = property.mTimestamp;
    8324             char szFlags[guestProp::MAX_FLAGS_LEN + 1];
    8325             guestProp::writeFlags(property.mFlags, szFlags);
    8326             prop.strFlags = szFlags;
    8327 
    8328             data.llGuestProperties.push_back(prop);
    8329         }
    8330 
    8331         data.strNotificationPatterns = mHWData->mGuestPropertyNotificationPatterns;
    8332         /* I presume this doesn't require a backup(). */
    8333         mData->mGuestPropertiesModified = FALSE;
    8334 #endif /* VBOX_WITH_GUEST_PROPS defined */
    8335     }
    8336     catch(std::bad_alloc &)
    8337     {
    8338         return E_OUTOFMEMORY;
     182        SSMR3Close(pSSM);
    8339183    }
    8340184
    8341     AssertComRC(rc);
    8342     return rc;
     185    if (RT_SUCCESS(vrc))
     186    {
     187        *pu32Width = u32Width;
     188        *pu32Height = u32Height;
     189    }
     190
     191    LogFlowFunc(("vrc %Rrc\n", vrc));
     192    return vrc;
    8343193}
    8344194
    8345 /**
    8346  *  Saves the storage controller configuration.
    8347  *
    8348  *  @param aNode    <StorageControllers> node to save the VM hardware confguration to.
    8349  */
    8350 HRESULT Machine::saveStorageControllers(settings::Storage &data)
    8351 {
    8352     data.llStorageControllers.clear();
    8353 
    8354     for (StorageControllerList::const_iterator it = mStorageControllers->begin();
    8355          it != mStorageControllers->end();
    8356          ++it)
    8357     {
    8358         HRESULT rc;
    8359         ComObjPtr<StorageController> pCtl = *it;
    8360 
    8361         settings::StorageController ctl;
    8362         ctl.strName = pCtl->getName();
    8363         ctl.controllerType = pCtl->getControllerType();
    8364         ctl.storageBus = pCtl->getStorageBus();
    8365         ctl.ulInstance = pCtl->getInstance();
    8366 
    8367         /* Save the port count. */
    8368         ULONG portCount;
    8369         rc = pCtl->COMGETTER(PortCount)(&portCount);
    8370         ComAssertComRCRet(rc, rc);
    8371         ctl.ulPortCount = portCount;
    8372 
    8373         /* Save fUseHostIOCache */
    8374         BOOL fUseHostIOCache;
    8375         rc = pCtl->COMGETTER(UseHostIOCache)(&fUseHostIOCache);
    8376         ComAssertComRCRet(rc, rc);
    8377         ctl.fUseHostIOCache = !!fUseHostIOCache;
    8378 
    8379         /* Save IDE emulation settings. */
    8380         if (ctl.controllerType == StorageControllerType_IntelAhci)
    8381         {
    8382             if (    (FAILED(rc = pCtl->GetIDEEmulationPort(0, (LONG*)&ctl.lIDE0MasterEmulationPort)))
    8383                  || (FAILED(rc = pCtl->GetIDEEmulationPort(1, (LONG*)&ctl.lIDE0SlaveEmulationPort)))
    8384                  || (FAILED(rc = pCtl->GetIDEEmulationPort(2, (LONG*)&ctl.lIDE1MasterEmulationPort)))
    8385                  || (FAILED(rc = pCtl->GetIDEEmulationPort(3, (LONG*)&ctl.lIDE1SlaveEmulationPort)))
    8386                )
    8387                 ComAssertComRCRet(rc, rc);
    8388         }
    8389 
    8390         /* save the devices now. */
    8391         rc = saveStorageDevices(pCtl, ctl);
    8392         ComAssertComRCRet(rc, rc);
    8393 
    8394         data.llStorageControllers.push_back(ctl);
    8395     }
    8396 
    8397     return S_OK;
    8398 }
    8399 
    8400 /**
    8401  *  Saves the hard disk confguration.
    8402  */
    8403 HRESULT Machine::saveStorageDevices(ComObjPtr<StorageController> aStorageController,
    8404                                     settings::StorageController &data)
    8405 {
    8406     MediaData::AttachmentList atts;
    8407 
    8408     HRESULT rc = getMediumAttachmentsOfController(Bstr(aStorageController->getName()), atts);
    8409     if (FAILED(rc)) return rc;
    8410 
    8411     data.llAttachedDevices.clear();
    8412     for (MediaData::AttachmentList::const_iterator it = atts.begin();
    8413          it != atts.end();
    8414          ++it)
    8415     {
    8416         settings::AttachedDevice dev;
    8417 
    8418         MediumAttachment *pAttach = *it;
    8419         Medium *pMedium = pAttach->getMedium();
    8420 
    8421         dev.deviceType = pAttach->getType();
    8422         dev.lPort = pAttach->getPort();
    8423         dev.lDevice = pAttach->getDevice();
    8424         if (pMedium)
    8425         {
    8426             if (pMedium->isHostDrive())
    8427                 dev.strHostDriveSrc = pMedium->getLocation();
    8428             else
    8429                 dev.uuid = pMedium->getId();
    8430             dev.fPassThrough = pAttach->getPassthrough();
    8431         }
    8432 
    8433         data.llAttachedDevices.push_back(dev);
    8434     }
    8435 
    8436     return S_OK;
    8437 }
    8438 
    8439 /**
    8440  *  Saves machine state settings as defined by aFlags
    8441  *  (SaveSTS_* values).
    8442  *
    8443  *  @param aFlags   Combination of SaveSTS_* flags.
    8444  *
    8445  *  @note Locks objects for writing.
    8446  */
    8447 HRESULT Machine::saveStateSettings(int aFlags)
    8448 {
    8449     if (aFlags == 0)
    8450         return S_OK;
    8451 
    8452     AutoCaller autoCaller(this);
    8453     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    8454 
    8455     /* This object's write lock is also necessary to serialize file access
    8456      * (prevent concurrent reads and writes) */
    8457     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    8458 
    8459     HRESULT rc = S_OK;
    8460 
    8461     Assert(mData->pMachineConfigFile);
    8462 
    8463     try
    8464     {
    8465         if (aFlags & SaveSTS_CurStateModified)
    8466             mData->pMachineConfigFile->fCurrentStateModified = true;
    8467 
    8468         if (aFlags & SaveSTS_StateFilePath)
    8469         {
    8470             if (!mSSData->mStateFilePath.isEmpty())
    8471                 /* try to make the file name relative to the settings file dir */
    8472                 copyPathRelativeToMachine(mSSData->mStateFilePath, mData->pMachineConfigFile->strStateFile);
    8473             else
    8474                 mData->pMachineConfigFile->strStateFile.setNull();
    8475         }
    8476 
    8477         if (aFlags & SaveSTS_StateTimeStamp)
    8478         {
    8479             Assert(    mData->mMachineState != MachineState_Aborted
    8480                     || mSSData->mStateFilePath.isEmpty());
    8481 
    8482             mData->pMachineConfigFile->timeLastStateChange = mData->mLastStateChange;
    8483 
    8484             mData->pMachineConfigFile->fAborted = (mData->mMachineState == MachineState_Aborted);
    8485 //@todo live migration             mData->pMachineConfigFile->fTeleported = (mData->mMachineState == MachineState_Teleported);
    8486         }
    8487 
    8488         mData->pMachineConfigFile->write(mData->m_strConfigFileFull);
    8489     }
    8490     catch (...)
    8491     {
    8492         rc = VirtualBox::handleUnexpectedExceptions(RT_SRC_POS);
    8493     }
    8494 
    8495     return rc;
    8496 }
    8497 
    8498 /**
    8499  * Creates differencing hard disks for all normal hard disks attached to this
    8500  * machine and a new set of attachments to refer to created disks.
    8501  *
    8502  * Used when taking a snapshot or when deleting the current state. Gets called
    8503  * from SessionMachine::BeginTakingSnapshot() and SessionMachine::restoreSnapshotHandler().
    8504  *
    8505  * This method assumes that mMediaData contains the original hard disk attachments
    8506  * it needs to create diffs for. On success, these attachments will be replaced
    8507  * with the created diffs. On failure, #deleteImplicitDiffs() is implicitly
    8508  * called to delete created diffs which will also rollback mMediaData and restore
    8509  * whatever was backed up before calling this method.
    8510  *
    8511  * Attachments with non-normal hard disks are left as is.
    8512  *
    8513  * If @a aOnline is @c false then the original hard disks that require implicit
    8514  * diffs will be locked for reading. Otherwise it is assumed that they are
    8515  * already locked for writing (when the VM was started). Note that in the latter
    8516  * case it is responsibility of the caller to lock the newly created diffs for
    8517  * writing if this method succeeds.
    8518  *
    8519  * @param aProgress         Progress object to run (must contain at least as
    8520  *                          many operations left as the number of hard disks
    8521  *                          attached).
    8522  * @param aOnline           Whether the VM was online prior to this operation.
    8523  * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
    8524  *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
    8525  *
    8526  * @note The progress object is not marked as completed, neither on success nor
    8527  *       on failure. This is a responsibility of the caller.
    8528  *
    8529  * @note Locks this object for writing.
    8530  */
    8531 HRESULT Machine::createImplicitDiffs(IProgress *aProgress,
    8532                                      ULONG aWeight,
    8533                                      bool aOnline,
    8534                                      bool *pfNeedsSaveSettings)
    8535 {
    8536     LogFlowThisFunc(("aOnline=%d\n", aOnline));
    8537 
    8538     AutoCaller autoCaller(this);
    8539     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    8540 
    8541     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    8542 
    8543     /* must be in a protective state because we leave the lock below */
    8544     AssertReturn(   mData->mMachineState == MachineState_Saving
    8545                  || mData->mMachineState == MachineState_LiveSnapshotting
    8546                  || mData->mMachineState == MachineState_RestoringSnapshot
    8547                  || mData->mMachineState == MachineState_DeletingSnapshot
    8548                  , E_FAIL);
    8549 
    8550     HRESULT rc = S_OK;
    8551 
    8552     MediumLockListMap lockedMediaOffline;
    8553     MediumLockListMap *lockedMediaMap;
    8554     if (aOnline)
    8555         lockedMediaMap = &mData->mSession.mLockedMedia;
    8556     else
    8557         lockedMediaMap = &lockedMediaOffline;
    8558 
    8559     try
    8560     {
    8561         if (!aOnline)
    8562         {
    8563             /* lock all attached hard disks early to detect "in use"
    8564              * situations before creating actual diffs */
    8565             for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
    8566                  it != mMediaData->mAttachments.end();
    8567                  ++it)
    8568             {
    8569                 MediumAttachment* pAtt = *it;
    8570                 if (pAtt->getType() == DeviceType_HardDisk)
    8571                 {
    8572                     Medium* pMedium = pAtt->getMedium();
    8573                     Assert(pMedium);
    8574 
    8575                     MediumLockList *pMediumLockList(new MediumLockList());
    8576                     rc = pMedium->createMediumLockList(true /* fFailIfInaccessible */,
    8577                                                        false /* fMediumLockWrite */,
    8578                                                        NULL,
    8579                                                        *pMediumLockList);
    8580                     if (FAILED(rc))
    8581                     {
    8582                         delete pMediumLockList;
    8583                         throw rc;
    8584                     }
    8585                     rc = lockedMediaMap->Insert(pAtt, pMediumLockList);
    8586                     if (FAILED(rc))
    8587                     {
    8588                         throw setError(rc,
    8589                                        tr("Collecting locking information for all attached media failed"));
    8590                     }
    8591                 }
    8592             }
    8593 
    8594             /* Now lock all media. If this fails, nothing is locked. */
    8595             rc = lockedMediaMap->Lock();
    8596             if (FAILED(rc))
    8597             {
    8598                 throw setError(rc,
    8599                                tr("Locking of attached media failed"));
    8600             }
    8601         }
    8602 
    8603         /* remember the current list (note that we don't use backup() since
    8604          * mMediaData may be already backed up) */
    8605         MediaData::AttachmentList atts = mMediaData->mAttachments;
    8606 
    8607         /* start from scratch */
    8608         mMediaData->mAttachments.clear();
    8609 
    8610         /* go through remembered attachments and create diffs for normal hard
    8611          * disks and attach them */
    8612         for (MediaData::AttachmentList::const_iterator it = atts.begin();
    8613              it != atts.end();
    8614              ++it)
    8615         {
    8616             MediumAttachment* pAtt = *it;
    8617 
    8618             DeviceType_T devType = pAtt->getType();
    8619             Medium* pMedium = pAtt->getMedium();
    8620 
    8621             if (   devType != DeviceType_HardDisk
    8622                 || pMedium == NULL
    8623                 || pMedium->getType() != MediumType_Normal)
    8624             {
    8625                 /* copy the attachment as is */
    8626 
    8627                 /** @todo the progress object created in Console::TakeSnaphot
    8628                  * only expects operations for hard disks. Later other
    8629                  * device types need to show up in the progress as well. */
    8630                 if (devType == DeviceType_HardDisk)
    8631                 {
    8632                     if (pMedium == NULL)
    8633                         aProgress->SetNextOperation(Bstr(tr("Skipping attachment without medium")),
    8634                                                     aWeight);        // weight
    8635                     else
    8636                         aProgress->SetNextOperation(BstrFmt(tr("Skipping medium '%s'"),
    8637                                                             pMedium->getBase()->getName().c_str()),
    8638                                                     aWeight);        // weight
    8639                 }
    8640 
    8641                 mMediaData->mAttachments.push_back(pAtt);
    8642                 continue;
    8643             }
    8644 
    8645             /* need a diff */
    8646             aProgress->SetNextOperation(BstrFmt(tr("Creating differencing hard disk for '%s'"),
    8647                                                 pMedium->getBase()->getName().c_str()),
    8648                                         aWeight);        // weight
    8649 
    8650             ComObjPtr<Medium> diff;
    8651             diff.createObject();
    8652             rc = diff->init(mParent,
    8653                             pMedium->getPreferredDiffFormat(),
    8654                             Utf8Str(mUserData->m_strSnapshotFolderFull).append(RTPATH_SLASH_STR),
    8655                             pMedium->getRegistryMachineId(),        // store the diff in the same registry as the parent
    8656                             pfNeedsSaveSettings);
    8657             if (FAILED(rc)) throw rc;
    8658 
    8659             /** @todo r=bird: How is the locking and diff image cleaned up if we fail before
    8660              *        the push_back?  Looks like we're going to leave medium with the
    8661              *        wrong kind of lock (general issue with if we fail anywhere at all)
    8662              *        and an orphaned VDI in the snapshots folder. */
    8663 
    8664             /* update the appropriate lock list */
    8665             MediumLockList *pMediumLockList;
    8666             rc = lockedMediaMap->Get(pAtt, pMediumLockList);
    8667             AssertComRCThrowRC(rc);
    8668             if (aOnline)
    8669             {
    8670                 rc = pMediumLockList->Update(pMedium, false);
    8671                 AssertComRCThrowRC(rc);
    8672             }
    8673 
    8674             /* leave the lock before the potentially lengthy operation */
    8675             alock.leave();
    8676             rc = pMedium->createDiffStorage(diff, MediumVariant_Standard,
    8677                                             pMediumLockList,
    8678                                             NULL /* aProgress */,
    8679                                             true /* aWait */,
    8680                                             pfNeedsSaveSettings);
    8681             alock.enter();
    8682             if (FAILED(rc)) throw rc;
    8683 
    8684             rc = lockedMediaMap->Unlock();
    8685             AssertComRCThrowRC(rc);
    8686             rc = pMediumLockList->Append(diff, true);
    8687             AssertComRCThrowRC(rc);
    8688             rc = lockedMediaMap->Lock();
    8689             AssertComRCThrowRC(rc);
    8690 
    8691             rc = diff->addBackReference(mData->mUuid);
    8692             AssertComRCThrowRC(rc);
    8693 
    8694             /* add a new attachment */
    8695             ComObjPtr<MediumAttachment> attachment;
    8696             attachment.createObject();
    8697             rc = attachment->init(this,
    8698                                   diff,
    8699                                   pAtt->getControllerName(),
    8700                                   pAtt->getPort(),
    8701                                   pAtt->getDevice(),
    8702                                   DeviceType_HardDisk,
    8703                                   true /* aImplicit */,
    8704                                   0 /* No bandwidth limit */);
    8705             if (FAILED(rc)) throw rc;
    8706 
    8707             rc = lockedMediaMap->ReplaceKey(pAtt, attachment);
    8708             AssertComRCThrowRC(rc);
    8709             mMediaData->mAttachments.push_back(attachment);
    8710         }
    8711     }
    8712     catch (HRESULT aRC) { rc = aRC; }
    8713 
    8714     /* unlock all hard disks we locked */
    8715     if (!aOnline)
    8716     {
    8717         ErrorInfoKeeper eik;
    8718 
    8719         rc = lockedMediaMap->Clear();
    8720         AssertComRC(rc);
    8721     }
    8722 
    8723     if (FAILED(rc))
    8724     {
    8725         MultiResult mrc = rc;
    8726 
    8727         mrc = deleteImplicitDiffs(pfNeedsSaveSettings);
    8728     }
    8729 
    8730     return rc;
    8731 }
    8732 
    8733 /**
    8734  * Deletes implicit differencing hard disks created either by
    8735  * #createImplicitDiffs() or by #AttachMedium() and rolls back mMediaData.
    8736  *
    8737  * Note that to delete hard disks created by #AttachMedium() this method is
    8738  * called from #fixupMedia() when the changes are rolled back.
    8739  *
    8740  * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
    8741  *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
    8742  *
    8743  * @note Locks this object for writing.
    8744  */
    8745 HRESULT Machine::deleteImplicitDiffs(bool *pfNeedsSaveSettings)
    8746 {
    8747     AutoCaller autoCaller(this);
    8748     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    8749 
    8750     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    8751     LogFlowThisFuncEnter();
    8752 
    8753     AssertReturn(mMediaData.isBackedUp(), E_FAIL);
    8754 
    8755     HRESULT rc = S_OK;
    8756 
    8757     MediaData::AttachmentList implicitAtts;
    8758 
    8759     const MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments;
    8760 
    8761     /* enumerate new attachments */
    8762     for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
    8763          it != mMediaData->mAttachments.end();
    8764          ++it)
    8765     {
    8766         ComObjPtr<Medium> hd = (*it)->getMedium();
    8767         if (hd.isNull())
    8768             continue;
    8769 
    8770         if ((*it)->isImplicit())
    8771         {
    8772             /* deassociate and mark for deletion */
    8773             LogFlowThisFunc(("Detaching '%s', pending deletion\n", (*it)->getLogName()));
    8774             rc = hd->removeBackReference(mData->mUuid);
    8775             AssertComRC(rc);
    8776             implicitAtts.push_back(*it);
    8777             continue;
    8778         }
    8779 
    8780         /* was this hard disk attached before? */
    8781         if (!findAttachment(oldAtts, hd))
    8782         {
    8783             /* no: de-associate */
    8784             LogFlowThisFunc(("Detaching '%s', no deletion\n", (*it)->getLogName()));
    8785             rc = hd->removeBackReference(mData->mUuid);
    8786             AssertComRC(rc);
    8787             continue;
    8788         }
    8789         LogFlowThisFunc(("Not detaching '%s'\n", (*it)->getLogName()));
    8790     }
    8791 
    8792     /* rollback hard disk changes */
    8793     mMediaData.rollback();
    8794 
    8795     MultiResult mrc(S_OK);
    8796 
    8797     /* delete unused implicit diffs */
    8798     if (implicitAtts.size() != 0)
    8799     {
    8800         /* will leave the lock before the potentially lengthy
    8801          * operation, so protect with the special state (unless already
    8802          * protected) */
    8803         MachineState_T oldState = mData->mMachineState;
    8804         if (    oldState != MachineState_Saving
    8805              && oldState != MachineState_LiveSnapshotting
    8806              && oldState != MachineState_RestoringSnapshot
    8807              && oldState != MachineState_DeletingSnapshot
    8808              && oldState != MachineState_DeletingSnapshotOnline
    8809              && oldState != MachineState_DeletingSnapshotPaused
    8810            )
    8811             setMachineState(MachineState_SettingUp);
    8812 
    8813         alock.leave();
    8814 
    8815         for (MediaData::AttachmentList::const_iterator it = implicitAtts.begin();
    8816              it != implicitAtts.end();
    8817              ++it)
    8818         {
    8819             LogFlowThisFunc(("Deleting '%s'\n", (*it)->getLogName()));
    8820             ComObjPtr<Medium> hd = (*it)->getMedium();
    8821 
    8822             rc = hd->deleteStorage(NULL /*aProgress*/, true /*aWait*/,
    8823                                    pfNeedsSaveSettings);
    8824             AssertMsg(SUCCEEDED(rc), ("rc=%Rhrc it=%s hd=%s\n", rc, (*it)->getLogName(), hd->getLocationFull().c_str() ));
    8825             mrc = rc;
    8826         }
    8827 
    8828         alock.enter();
    8829 
    8830         if (mData->mMachineState == MachineState_SettingUp)
    8831         {
    8832             setMachineState(oldState);
    8833         }
    8834     }
    8835 
    8836     return mrc;
    8837 }
    8838 
    8839 /**
    8840  * Looks through the given list of media attachments for one with the given parameters
    8841  * and returns it, or NULL if not found. The list is a parameter so that backup lists
    8842  * can be searched as well if needed.
    8843  *
    8844  * @param list
    8845  * @param aControllerName
    8846  * @param aControllerPort
    8847  * @param aDevice
    8848  * @return
    8849  */
    8850 MediumAttachment* Machine::findAttachment(const MediaData::AttachmentList &ll,
    8851                                           IN_BSTR aControllerName,
    8852                                           LONG aControllerPort,
    8853                                           LONG aDevice)
    8854 {
    8855    for (MediaData::AttachmentList::const_iterator it = ll.begin();
    8856         it != ll.end();
    8857         ++it)
    8858     {
    8859         MediumAttachment *pAttach = *it;
    8860         if (pAttach->matches(aControllerName, aControllerPort, aDevice))
    8861             return pAttach;
    8862     }
    8863 
    8864     return NULL;
    8865 }
    8866 
    8867 /**
    8868  * Looks through the given list of media attachments for one with the given parameters
    8869  * and returns it, or NULL if not found. The list is a parameter so that backup lists
    8870  * can be searched as well if needed.
    8871  *
    8872  * @param list
    8873  * @param aControllerName
    8874  * @param aControllerPort
    8875  * @param aDevice
    8876  * @return
    8877  */
    8878 MediumAttachment* Machine::findAttachment(const MediaData::AttachmentList &ll,
    8879                                           ComObjPtr<Medium> pMedium)
    8880 {
    8881    for (MediaData::AttachmentList::const_iterator it = ll.begin();
    8882         it != ll.end();
    8883         ++it)
    8884     {
    8885         MediumAttachment *pAttach = *it;
    8886         ComObjPtr<Medium> pMediumThis = pAttach->getMedium();
    8887         if (pMediumThis == pMedium)
    8888             return pAttach;
    8889     }
    8890 
    8891     return NULL;
    8892 }
    8893 
    8894 /**
    8895  * Looks through the given list of media attachments for one with the given parameters
    8896  * and returns it, or NULL if not found. The list is a parameter so that backup lists
    8897  * can be searched as well if needed.
    8898  *
    8899  * @param list
    8900  * @param aControllerName
    8901  * @param aControllerPort
    8902  * @param aDevice
    8903  * @return
    8904  */
    8905 MediumAttachment* Machine::findAttachment(const MediaData::AttachmentList &ll,
    8906                                           Guid &id)
    8907 {
    8908    for (MediaData::AttachmentList::const_iterator it = ll.begin();
    8909          it != ll.end();
    8910          ++it)
    8911     {
    8912         MediumAttachment *pAttach = *it;
    8913         ComObjPtr<Medium> pMediumThis = pAttach->getMedium();
    8914         if (pMediumThis->getId() == id)
    8915             return pAttach;
    8916     }
    8917 
    8918     return NULL;
    8919 }
    8920 
    8921 /**
    8922  * Main implementation for Machine::DetachDevice. This also gets called
    8923  * from Machine::prepareUnregister() so it has been taken out for simplicity.
    8924  *
    8925  * @param pAttach Medium attachment to detach.
    8926  * @param writeLock Machine write lock which the caller must have locked once. This may be released temporarily in here.
    8927  * @param pSnapshot If NULL, then the detachment is for the current machine. Otherwise this is for a SnapshotMachine, and this must be its snapshot.
    8928  * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
    8929  *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
    8930  * @return
    8931  */
    8932 HRESULT Machine::detachDevice(MediumAttachment *pAttach,
    8933                               AutoWriteLock &writeLock,
    8934                               Snapshot *pSnapshot,
    8935                               bool *pfNeedsSaveSettings)
    8936 {
    8937     ComObjPtr<Medium> oldmedium = pAttach->getMedium();
    8938     DeviceType_T mediumType = pAttach->getType();
    8939 
    8940     LogFlowThisFunc(("Entering, medium of attachment is %s\n", oldmedium ? oldmedium->getLocationFull().c_str() : "NULL"));
    8941 
    8942     if (pAttach->isImplicit())
    8943     {
    8944         /* attempt to implicitly delete the implicitly created diff */
    8945 
    8946             /// @todo move the implicit flag from MediumAttachment to Medium
    8947             /// and forbid any hard disk operation when it is implicit. Or maybe
    8948             /// a special media state for it to make it even more simple.
    8949 
    8950         Assert(mMediaData.isBackedUp());
    8951 
    8952             /* will leave the lock before the potentially lengthy operation, so
    8953             * protect with the special state */
    8954         MachineState_T oldState = mData->mMachineState;
    8955         setMachineState(MachineState_SettingUp);
    8956 
    8957         writeLock.release();
    8958 
    8959         HRESULT rc = oldmedium->deleteStorage(NULL /*aProgress*/, true /*aWait*/,
    8960                                               pfNeedsSaveSettings);
    8961 
    8962         writeLock.acquire();
    8963 
    8964         setMachineState(oldState);
    8965 
    8966         if (FAILED(rc)) return rc;
    8967     }
    8968 
    8969     setModified(IsModified_Storage);
    8970     mMediaData.backup();
    8971 
    8972     // we cannot use erase (it) below because backup() above will create
    8973     // a copy of the list and make this copy active, but the iterator
    8974     // still refers to the original and is not valid for the copy
    8975     mMediaData->mAttachments.remove(pAttach);
    8976 
    8977     if (!oldmedium.isNull())
    8978     {
    8979         // if this is from a snapshot, do not defer detachment to commitMedia()
    8980         if (pSnapshot)
    8981             oldmedium->removeBackReference(mData->mUuid, pSnapshot->getId());
    8982         // else if non-hard disk media, do not defer detachment to commitMedia() either
    8983         else if (mediumType != DeviceType_HardDisk)
    8984             oldmedium->removeBackReference(mData->mUuid);
    8985     }
    8986 
    8987     return S_OK;
    8988 }
    8989 
    8990 /**
    8991  * Goes thru all medium attachments of the list and calls detachDevice() on each
    8992  * of them and attaches all Medium objects found in the process to the given list,
    8993  * depending on cleanupMode.
    8994  *
    8995  * This gets called from Machine::Unregister, both for the actual Machine and
    8996  * the SnapshotMachine objects that might be found in the snapshots.
    8997  *
    8998  * Requires caller and locking.
    8999  *
    9000  * @param writeLock Machine lock from top-level caller; this gets passed to detachDevice.
    9001  * @param pSnapshot Must be NULL when called for a "real" Machine or a snapshot object if called for a SnapshotMachine.
    9002  * @param cleanupMode If DetachAllReturnHardDisksOnly, only hard disk media get added to llMedia; if Full, then all media get added;
    9003  *          otherwise no media get added.
    9004  * @param llMedia Caller's list to receive Medium objects which got detached so caller can close() them, depending on cleanupMode.
    9005  * @return
    9006  */
    9007 HRESULT Machine::detachAllMedia(AutoWriteLock &writeLock,
    9008                                 Snapshot *pSnapshot,
    9009                                 CleanupMode_T cleanupMode,
    9010                                 MediaList &llMedia)
    9011 {
    9012     Assert(isWriteLockOnCurrentThread());
    9013 
    9014     HRESULT rc;
    9015 
    9016     // make a temporary list because detachDevice invalidates iterators into
    9017     // mMediaData->mAttachments
    9018     MediaData::AttachmentList llAttachments2 = mMediaData->mAttachments;
    9019 
    9020     for (MediaData::AttachmentList::iterator it = llAttachments2.begin();
    9021          it != llAttachments2.end();
    9022          ++it)
    9023     {
    9024         ComObjPtr<MediumAttachment> pAttach = *it;
    9025         ComObjPtr<Medium> pMedium = pAttach->getMedium();
    9026 
    9027         if (!pMedium.isNull())
    9028         {
    9029             DeviceType_T devType = pMedium->getDeviceType();
    9030             if (    (    cleanupMode == CleanupMode_DetachAllReturnHardDisksOnly
    9031                       && devType == DeviceType_HardDisk)
    9032                  || (cleanupMode == CleanupMode_Full)
    9033                )
    9034                 llMedia.push_back(pMedium);
    9035         }
    9036 
    9037         // real machine: then we need to use the proper method
    9038         rc = detachDevice(pAttach,
    9039                           writeLock,
    9040                           pSnapshot,
    9041                           NULL /* pfNeedsSaveSettings */);
    9042 
    9043         if (FAILED(rc))
    9044             return rc;
    9045     }
    9046 
    9047     return S_OK;
    9048 }
    9049 
    9050 /**
    9051  * Perform deferred hard disk detachments.
    9052  *
    9053  * Does nothing if the hard disk attachment data (mMediaData) is not changed (not
    9054  * backed up).
    9055  *
    9056  * If @a aOnline is @c true then this method will also unlock the old hard disks
    9057  * for which the new implicit diffs were created and will lock these new diffs for
    9058  * writing.
    9059  *
    9060  * @param aOnline       Whether the VM was online prior to this operation.
    9061  *
    9062  * @note Locks this object for writing!
    9063  */
    9064 void Machine::commitMedia(bool aOnline /*= false*/)
    9065 {
    9066     AutoCaller autoCaller(this);
    9067     AssertComRCReturnVoid(autoCaller.rc());
    9068 
    9069     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    9070 
    9071     LogFlowThisFunc(("Entering, aOnline=%d\n", aOnline));
    9072 
    9073     HRESULT rc = S_OK;
    9074 
    9075     /* no attach/detach operations -- nothing to do */
    9076     if (!mMediaData.isBackedUp())
    9077         return;
    9078 
    9079     MediaData::AttachmentList &oldAtts = mMediaData.backedUpData()->mAttachments;
    9080     bool fMediaNeedsLocking = false;
    9081 
    9082     /* enumerate new attachments */
    9083     for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
    9084          it != mMediaData->mAttachments.end();
    9085          ++it)
    9086     {
    9087         MediumAttachment *pAttach = *it;
    9088 
    9089         pAttach->commit();
    9090 
    9091         Medium* pMedium = pAttach->getMedium();
    9092         bool fImplicit = pAttach->isImplicit();
    9093 
    9094         LogFlowThisFunc(("Examining current medium '%s' (implicit: %d)\n",
    9095                          (pMedium) ? pMedium->getName().c_str() : "NULL",
    9096                          fImplicit));
    9097 
    9098         /** @todo convert all this Machine-based voodoo to MediumAttachment
    9099          * based commit logic. */
    9100         if (fImplicit)
    9101         {
    9102             /* convert implicit attachment to normal */
    9103             pAttach->setImplicit(false);
    9104 
    9105             if (    aOnline
    9106                  && pMedium
    9107                  && pAttach->getType() == DeviceType_HardDisk
    9108                )
    9109             {
    9110                 ComObjPtr<Medium> parent = pMedium->getParent();
    9111                 AutoWriteLock parentLock(parent COMMA_LOCKVAL_SRC_POS);
    9112 
    9113                 /* update the appropriate lock list */
    9114                 MediumLockList *pMediumLockList;
    9115                 rc = mData->mSession.mLockedMedia.Get(pAttach, pMediumLockList);
    9116                 AssertComRC(rc);
    9117                 if (pMediumLockList)
    9118                 {
    9119                     /* unlock if there's a need to change the locking */
    9120                     if (!fMediaNeedsLocking)
    9121                     {
    9122                         rc = mData->mSession.mLockedMedia.Unlock();
    9123                         AssertComRC(rc);
    9124                         fMediaNeedsLocking = true;
    9125                     }
    9126                     rc = pMediumLockList->Update(parent, false);
    9127                     AssertComRC(rc);
    9128                     rc = pMediumLockList->Append(pMedium, true);
    9129                     AssertComRC(rc);
    9130                 }
    9131             }
    9132 
    9133             continue;
    9134         }
    9135 
    9136         if (pMedium)
    9137         {
    9138             /* was this medium attached before? */
    9139             for (MediaData::AttachmentList::iterator oldIt = oldAtts.begin();
    9140                  oldIt != oldAtts.end();
    9141                  ++oldIt)
    9142             {
    9143                 MediumAttachment *pOldAttach = *oldIt;
    9144                 if (pOldAttach->getMedium() == pMedium)
    9145                 {
    9146                     LogFlowThisFunc(("--> medium '%s' was attached before, will not remove\n", pMedium->getName().c_str()));
    9147 
    9148                     /* yes: remove from old to avoid de-association */
    9149                     oldAtts.erase(oldIt);
    9150                     break;
    9151                 }
    9152             }
    9153         }
    9154     }
    9155 
    9156     /* enumerate remaining old attachments and de-associate from the
    9157      * current machine state */
    9158     for (MediaData::AttachmentList::const_iterator it = oldAtts.begin();
    9159          it != oldAtts.end();
    9160          ++it)
    9161     {
    9162         MediumAttachment *pAttach = *it;
    9163         Medium* pMedium = pAttach->getMedium();
    9164 
    9165         /* Detach only hard disks, since DVD/floppy media is detached
    9166          * instantly in MountMedium. */
    9167         if (pAttach->getType() == DeviceType_HardDisk && pMedium)
    9168         {
    9169             LogFlowThisFunc(("detaching medium '%s' from machine\n", pMedium->getName().c_str()));
    9170 
    9171             /* now de-associate from the current machine state */
    9172             rc = pMedium->removeBackReference(mData->mUuid);
    9173             AssertComRC(rc);
    9174 
    9175             if (aOnline)
    9176             {
    9177                 /* unlock since medium is not used anymore */
    9178                 MediumLockList *pMediumLockList;
    9179                 rc = mData->mSession.mLockedMedia.Get(pAttach, pMediumLockList);
    9180                 AssertComRC(rc);
    9181                 if (pMediumLockList)
    9182                 {
    9183                     rc = mData->mSession.mLockedMedia.Remove(pAttach);
    9184                     AssertComRC(rc);
    9185                 }
    9186             }
    9187         }
    9188     }
    9189 
    9190     /* take media locks again so that the locking state is consistent */
    9191     if (fMediaNeedsLocking)
    9192     {
    9193         Assert(aOnline);
    9194         rc = mData->mSession.mLockedMedia.Lock();
    9195         AssertComRC(rc);
    9196     }
    9197 
    9198     /* commit the hard disk changes */
    9199     mMediaData.commit();
    9200 
    9201     if (isSessionMachine())
    9202     {
    9203         /* attach new data to the primary machine and reshare it */
    9204         mPeer->mMediaData.attach(mMediaData);
    9205     }
    9206 
    9207     return;
    9208 }
    9209 
    9210 /**
    9211  * Perform deferred deletion of implicitly created diffs.
    9212  *
    9213  * Does nothing if the hard disk attachment data (mMediaData) is not changed (not
    9214  * backed up).
    9215  *
    9216  * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
    9217  *                by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
    9218  *
    9219  * @note Locks this object for writing!
    9220  */
    9221 void Machine::rollbackMedia()
    9222 {
    9223     AutoCaller autoCaller(this);
    9224     AssertComRCReturnVoid (autoCaller.rc());
    9225 
    9226     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    9227 
    9228     LogFlowThisFunc(("Entering\n"));
    9229 
    9230     HRESULT rc = S_OK;
    9231 
    9232     /* no attach/detach operations -- nothing to do */
    9233     if (!mMediaData.isBackedUp())
    9234         return;
    9235 
    9236     /* enumerate new attachments */
    9237     for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
    9238          it != mMediaData->mAttachments.end();
    9239          ++it)
    9240     {
    9241         MediumAttachment *pAttach = *it;
    9242         /* Fix up the backrefs for DVD/floppy media. */
    9243         if (pAttach->getType() != DeviceType_HardDisk)
    9244         {
    9245             Medium* pMedium = pAttach->getMedium();
    9246             if (pMedium)
    9247             {
    9248                 rc = pMedium->removeBackReference(mData->mUuid);
    9249                 AssertComRC(rc);
    9250             }
    9251         }
    9252 
    9253         (*it)->rollback();
    9254 
    9255         pAttach = *it;
    9256         /* Fix up the backrefs for DVD/floppy media. */
    9257         if (pAttach->getType() != DeviceType_HardDisk)
    9258         {
    9259             Medium* pMedium = pAttach->getMedium();
    9260             if (pMedium)
    9261             {
    9262                 rc = pMedium->addBackReference(mData->mUuid);
    9263                 AssertComRC(rc);
    9264             }
    9265         }
    9266     }
    9267 
    9268     /** @todo convert all this Machine-based voodoo to MediumAttachment
    9269      * based rollback logic. */
    9270     // @todo r=dj the below totally fails if this gets called from Machine::rollback(),
    9271     // which gets called if Machine::registeredInit() fails...
    9272     deleteImplicitDiffs(NULL /*pfNeedsSaveSettings*/);
    9273 
    9274     return;
    9275 }
    9276 
    9277 /**
    9278  *  Returns true if the settings file is located in the directory named exactly
    9279  *  as the machine. This will be true if the machine settings structure was
    9280  *  created by default in #openConfigLoader().
    9281  *
    9282  *  @param aSettingsDir if not NULL, the full machine settings file directory
    9283  *                      name will be assigned there.
    9284  *
    9285  *  @note Doesn't lock anything.
    9286  *  @note Not thread safe (must be called from this object's lock).
    9287  */
    9288 bool Machine::isInOwnDir(Utf8Str *aSettingsDir /* = NULL */) const
    9289 {
    9290     Utf8Str settingsDir = mData->m_strConfigFileFull;
    9291     settingsDir.stripFilename();
    9292     Utf8Str strDirName = RTPathFilename(settingsDir.c_str());
    9293 
    9294     AssertReturn(!strDirName.isEmpty(), false);
    9295 
    9296     /* if we don't rename anything on name change, return false shorlty */
    9297     if (!mUserData->s.fNameSync)
    9298         return false;
    9299 
    9300     if (aSettingsDir)
    9301         *aSettingsDir = settingsDir;
    9302 
    9303     return strDirName == mUserData->s.strName;
    9304 }
    9305 
    9306 /**
    9307  * Discards all changes to machine settings.
    9308  *
    9309  * @param aNotify   Whether to notify the direct session about changes or not.
    9310  *
    9311  * @note Locks objects for writing!
    9312  */
    9313 void Machine::rollback(bool aNotify)
    9314 {
    9315     AutoCaller autoCaller(this);
    9316     AssertComRCReturn(autoCaller.rc(), (void)0);
    9317 
    9318     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    9319 
    9320     if (!mStorageControllers.isNull())
    9321     {
    9322         if (mStorageControllers.isBackedUp())
    9323         {
    9324             /* unitialize all new devices (absent in the backed up list). */
    9325             StorageControllerList::const_iterator it = mStorageControllers->begin();
    9326             StorageControllerList *backedList = mStorageControllers.backedUpData();
    9327             while (it != mStorageControllers->end())
    9328             {
    9329                 if (   std::find(backedList->begin(), backedList->end(), *it)
    9330                     == backedList->end()
    9331                    )
    9332                 {
    9333                     (*it)->uninit();
    9334                 }
    9335                 ++it;
    9336             }
    9337 
    9338             /* restore the list */
    9339             mStorageControllers.rollback();
    9340         }
    9341 
    9342         /* rollback any changes to devices after restoring the list */
    9343         if (mData->flModifications & IsModified_Storage)
    9344         {
    9345             StorageControllerList::const_iterator it = mStorageControllers->begin();
    9346             while (it != mStorageControllers->end())
    9347             {
    9348                 (*it)->rollback();
    9349                 ++it;
    9350             }
    9351         }
    9352     }
    9353 
    9354     mUserData.rollback();
    9355 
    9356     mHWData.rollback();
    9357 
    9358     if (mData->flModifications & IsModified_Storage)
    9359         rollbackMedia();
    9360 
    9361     if (mBIOSSettings)
    9362         mBIOSSettings->rollback();
    9363 
    9364 #ifdef VBOX_WITH_VRDP
    9365     if (mVRDPServer && (mData->flModifications & IsModified_VRDPServer))
    9366         mVRDPServer->rollback();
    9367 #endif
    9368 
    9369     if (mAudioAdapter)
    9370         mAudioAdapter->rollback();
    9371 
    9372     if (mUSBController && (mData->flModifications & IsModified_USB))
    9373         mUSBController->rollback();
    9374 
    9375     ComPtr<INetworkAdapter> networkAdapters[RT_ELEMENTS(mNetworkAdapters)];
    9376     ComPtr<ISerialPort> serialPorts[RT_ELEMENTS(mSerialPorts)];
    9377     ComPtr<IParallelPort> parallelPorts[RT_ELEMENTS(mParallelPorts)];
    9378 
    9379     if (mData->flModifications & IsModified_NetworkAdapters)
    9380         for (ULONG slot = 0; slot < RT_ELEMENTS(mNetworkAdapters); slot++)
    9381             if (    mNetworkAdapters[slot]
    9382                  && mNetworkAdapters[slot]->isModified())
    9383             {
    9384                 mNetworkAdapters[slot]->rollback();
    9385                 networkAdapters[slot] = mNetworkAdapters[slot];
    9386             }
    9387 
    9388     if (mData->flModifications & IsModified_SerialPorts)
    9389         for (ULONG slot = 0; slot < RT_ELEMENTS(mSerialPorts); slot++)
    9390             if (    mSerialPorts[slot]
    9391                  && mSerialPorts[slot]->isModified())
    9392             {
    9393                 mSerialPorts[slot]->rollback();
    9394                 serialPorts[slot] = mSerialPorts[slot];
    9395             }
    9396 
    9397     if (mData->flModifications & IsModified_ParallelPorts)
    9398         for (ULONG slot = 0; slot < RT_ELEMENTS(mParallelPorts); slot++)
    9399             if (    mParallelPorts[slot]
    9400                  && mParallelPorts[slot]->isModified())
    9401             {
    9402                 mParallelPorts[slot]->rollback();
    9403                 parallelPorts[slot] = mParallelPorts[slot];
    9404             }
    9405 
    9406     if (aNotify)
    9407     {
    9408         /* inform the direct session about changes */
    9409 
    9410         ComObjPtr<Machine> that = this;
    9411         uint32_t flModifications = mData->flModifications;
    9412         alock.leave();
    9413 
    9414         if (flModifications & IsModified_SharedFolders)
    9415             that->onSharedFolderChange();
    9416 
    9417         if (flModifications & IsModified_VRDPServer)
    9418             that->onVRDPServerChange(/* aRestart */ TRUE);
    9419         if (flModifications & IsModified_USB)
    9420             that->onUSBControllerChange();
    9421 
    9422         for (ULONG slot = 0; slot < RT_ELEMENTS(networkAdapters); slot ++)
    9423             if (networkAdapters[slot])
    9424                 that->onNetworkAdapterChange(networkAdapters[slot], FALSE);
    9425         for (ULONG slot = 0; slot < RT_ELEMENTS(serialPorts); slot ++)
    9426             if (serialPorts[slot])
    9427                 that->onSerialPortChange(serialPorts[slot]);
    9428         for (ULONG slot = 0; slot < RT_ELEMENTS(parallelPorts); slot ++)
    9429             if (parallelPorts[slot])
    9430                 that->onParallelPortChange(parallelPorts[slot]);
    9431 
    9432         if (flModifications & IsModified_Storage)
    9433             that->onStorageControllerChange();
    9434     }
    9435 }
    9436 
    9437 /**
    9438  * Commits all the changes to machine settings.
    9439  *
    9440  * Note that this operation is supposed to never fail.
    9441  *
    9442  * @note Locks this object and children for writing.
    9443  */
    9444 void Machine::commit()
    9445 {
    9446     AutoCaller autoCaller(this);
    9447     AssertComRCReturnVoid(autoCaller.rc());
    9448 
    9449     AutoCaller peerCaller(mPeer);
    9450     AssertComRCReturnVoid(peerCaller.rc());
    9451 
    9452     AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
    9453 
    9454     /*
    9455      *  use safe commit to ensure Snapshot machines (that share mUserData)
    9456      *  will still refer to a valid memory location
    9457      */
    9458     mUserData.commitCopy();
    9459 
    9460     mHWData.commit();
    9461 
    9462     if (mMediaData.isBackedUp())
    9463         commitMedia();
    9464 
    9465     mBIOSSettings->commit();
    9466 #ifdef VBOX_WITH_VRDP
    9467     mVRDPServer->commit();
    9468 #endif
    9469     mAudioAdapter->commit();
    9470     mUSBController->commit();
    9471 
    9472     for (ULONG slot = 0; slot < RT_ELEMENTS(mNetworkAdapters); slot++)
    9473         mNetworkAdapters[slot]->commit();
    9474     for (ULONG slot = 0; slot < RT_ELEMENTS(mSerialPorts); slot++)
    9475         mSerialPorts[slot]->commit();
    9476     for (ULONG slot = 0; slot < RT_ELEMENTS(mParallelPorts); slot++)
    9477         mParallelPorts[slot]->commit();
    9478 
    9479     bool commitStorageControllers = false;
    9480 
    9481     if (mStorageControllers.isBackedUp())
    9482     {
    9483         mStorageControllers.commit();
    9484 
    9485         if (mPeer)
    9486         {
    9487             AutoWriteLock peerlock(mPeer COMMA_LOCKVAL_SRC_POS);
    9488 
    9489             /* Commit all changes to new controllers (this will reshare data with
    9490              * peers for thos who have peers) */
    9491             StorageControllerList *newList = new StorageControllerList();
    9492             StorageControllerList::const_iterator it = mStorageControllers->begin();
    9493             while (it != mStorageControllers->end())
    9494             {
    9495                 (*it)->commit();
    9496 
    9497                 /* look if this controller has a peer device */
    9498                 ComObjPtr<StorageController> peer = (*it)->getPeer();
    9499                 if (!peer)
    9500                 {
    9501                     /* no peer means the device is a newly created one;
    9502                      * create a peer owning data this device share it with */
    9503                     peer.createObject();
    9504                     peer->init(mPeer, *it, true /* aReshare */);
    9505                 }
    9506                 else
    9507                 {
    9508                     /* remove peer from the old list */
    9509                     mPeer->mStorageControllers->remove(peer);
    9510                 }
    9511                 /* and add it to the new list */
    9512                 newList->push_back(peer);
    9513 
    9514                 ++it;
    9515             }
    9516 
    9517             /* uninit old peer's controllers that are left */
    9518             it = mPeer->mStorageControllers->begin();
    9519             while (it != mPeer->mStorageControllers->end())
    9520             {
    9521                 (*it)->uninit();
    9522                 ++it;
    9523             }
    9524 
    9525             /* attach new list of controllers to our peer */
    9526             mPeer->mStorageControllers.attach(newList);
    9527         }
    9528         else
    9529         {
    9530             /* we have no peer (our parent is the newly created machine);
    9531              * just commit changes to devices */
    9532             commitStorageControllers = true;
    9533         }
    9534     }
    9535     else
    9536     {
    9537         /* the list of controllers itself is not changed,
    9538          * just commit changes to controllers themselves */
    9539         commitStorageControllers = true;
    9540     }
    9541 
    9542     if (commitStorageControllers)
    9543     {
    9544         StorageControllerList::const_iterator it = mStorageControllers->begin();
    9545         while (it != mStorageControllers->end())
    9546         {
    9547             (*it)->commit();
    9548             ++it;
    9549         }
    9550     }
    9551 
    9552     if (isSessionMachine())
    9553     {
    9554         /* attach new data to the primary machine and reshare it */
    9555         mPeer->mUserData.attach(mUserData);
    9556         mPeer->mHWData.attach(mHWData);
    9557         /* mMediaData is reshared by fixupMedia */
    9558         // mPeer->mMediaData.attach(mMediaData);
    9559         Assert(mPeer->mMediaData.data() == mMediaData.data());
    9560     }
    9561 }
    9562 
    9563 /**
    9564  * Copies all the hardware data from the given machine.
    9565  *
    9566  * Currently, only called when the VM is being restored from a snapshot. In
    9567  * particular, this implies that the VM is not running during this method's
    9568  * call.
    9569  *
    9570  * @note This method must be called from under this object's lock.
    9571  *
    9572  * @note This method doesn't call #commit(), so all data remains backed up and
    9573  *       unsaved.
    9574  */
    9575 void Machine::copyFrom(Machine *aThat)
    9576 {
    9577     AssertReturnVoid(!isSnapshotMachine());
    9578     AssertReturnVoid(aThat->isSnapshotMachine());
    9579 
    9580     AssertReturnVoid(!Global::IsOnline(mData->mMachineState));
    9581 
    9582     mHWData.assignCopy(aThat->mHWData);
    9583 
    9584     // create copies of all shared folders (mHWData after attiching a copy
    9585     // contains just references to original objects)
    9586     for (HWData::SharedFolderList::iterator it = mHWData->mSharedFolders.begin();
    9587          it != mHWData->mSharedFolders.end();
    9588          ++it)
    9589     {
    9590         ComObjPtr<SharedFolder> folder;
    9591         folder.createObject();
    9592         HRESULT rc = folder->initCopy(getMachine(), *it);
    9593         AssertComRC(rc);
    9594         *it = folder;
    9595     }
    9596 
    9597     mBIOSSettings->copyFrom(aThat->mBIOSSettings);
    9598 #ifdef VBOX_WITH_VRDP
    9599     mVRDPServer->copyFrom(aThat->mVRDPServer);
    9600 #endif
    9601     mAudioAdapter->copyFrom(aThat->mAudioAdapter);
    9602     mUSBController->copyFrom(aThat->mUSBController);
    9603 
    9604     /* create private copies of all controllers */
    9605     mStorageControllers.backup();
    9606     mStorageControllers->clear();
    9607     for (StorageControllerList::iterator it = aThat->mStorageControllers->begin();
    9608          it != aThat->mStorageControllers->end();
    9609          ++it)
    9610     {
    9611         ComObjPtr<StorageController> ctrl;
    9612         ctrl.createObject();
    9613         ctrl->initCopy(this, *it);
    9614         mStorageControllers->push_back(ctrl);
    9615     }
    9616 
    9617     for (ULONG slot = 0; slot < RT_ELEMENTS(mNetworkAdapters); slot++)
    9618         mNetworkAdapters[slot]->copyFrom(aThat->mNetworkAdapters[slot]);
    9619     for (ULONG slot = 0; slot < RT_ELEMENTS(mSerialPorts); slot++)
    9620         mSerialPorts[slot]->copyFrom(aThat->mSerialPorts[slot]);
    9621     for (ULONG slot = 0; slot < RT_ELEMENTS(mParallelPorts); slot++)
    9622         mParallelPorts[slot]->copyFrom(aThat->mParallelPorts[slot]);
    9623 }
    9624 
    9625 #ifdef VBOX_WITH_RESOURCE_USAGE_API
    9626 
    9627 void Machine::registerMetrics(PerformanceCollector *aCollector, Machine *aMachine, RTPROCESS pid)
    9628 {
    9629     AssertReturnVoid(isWriteLockOnCurrentThread());
    9630     AssertPtrReturnVoid(aCollector);
    9631 
    9632     pm::CollectorHAL *hal = aCollector->getHAL();
    9633     /* Create sub metrics */
    9634     pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
    9635         "Percentage of processor time spent in user mode by the VM process.");
    9636     pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
    9637         "Percentage of processor time spent in kernel mode by the VM process.");
    9638     pm::SubMetric *ramUsageUsed  = new pm::SubMetric("RAM/Usage/Used",
    9639         "Size of resident portion of VM process in memory.");
    9640     /* Create and register base metrics */
    9641     pm::BaseMetric *cpuLoad = new pm::MachineCpuLoadRaw(hal, aMachine, pid,
    9642                                                         cpuLoadUser, cpuLoadKernel);
    9643     aCollector->registerBaseMetric(cpuLoad);
    9644     pm::BaseMetric *ramUsage = new pm::MachineRamUsage(hal, aMachine, pid,
    9645                                                        ramUsageUsed);
    9646     aCollector->registerBaseMetric(ramUsage);
    9647 
    9648     aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
    9649     aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
    9650                                                 new pm::AggregateAvg()));
    9651     aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
    9652                                               new pm::AggregateMin()));
    9653     aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
    9654                                               new pm::AggregateMax()));
    9655     aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
    9656     aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
    9657                                               new pm::AggregateAvg()));
    9658     aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
    9659                                               new pm::AggregateMin()));
    9660     aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
    9661                                               new pm::AggregateMax()));
    9662 
    9663     aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
    9664     aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
    9665                                               new pm::AggregateAvg()));
    9666     aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
    9667                                               new pm::AggregateMin()));
    9668     aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
    9669                                               new pm::AggregateMax()));
    9670 
    9671 
    9672     /* Guest metrics */
    9673     mGuestHAL = new pm::CollectorGuestHAL(this, hal);
    9674 
    9675     /* Create sub metrics */
    9676     pm::SubMetric *guestLoadUser = new pm::SubMetric("Guest/CPU/Load/User",
    9677         "Percentage of processor time spent in user mode as seen by the guest.");
    9678     pm::SubMetric *guestLoadKernel = new pm::SubMetric("Guest/CPU/Load/Kernel",
    9679         "Percentage of processor time spent in kernel mode as seen by the guest.");
    9680     pm::SubMetric *guestLoadIdle = new pm::SubMetric("Guest/CPU/Load/Idle",
    9681         "Percentage of processor time spent idling as seen by the guest.");
    9682 
    9683     /* The total amount of physical ram is fixed now, but we'll support dynamic guest ram configurations in the future. */
    9684     pm::SubMetric *guestMemTotal = new pm::SubMetric("Guest/RAM/Usage/Total",      "Total amount of physical guest RAM.");
    9685     pm::SubMetric *guestMemFree = new pm::SubMetric("Guest/RAM/Usage/Free",        "Free amount of physical guest RAM.");
    9686     pm::SubMetric *guestMemBalloon = new pm::SubMetric("Guest/RAM/Usage/Balloon",  "Amount of ballooned physical guest RAM.");
    9687     pm::SubMetric *guestMemShared = new pm::SubMetric("Guest/RAM/Usage/Shared",  "Amount of shared physical guest RAM.");
    9688     pm::SubMetric *guestMemCache = new pm::SubMetric("Guest/RAM/Usage/Cache",        "Total amount of guest (disk) cache memory.");
    9689 
    9690     pm::SubMetric *guestPagedTotal = new pm::SubMetric("Guest/Pagefile/Usage/Total",    "Total amount of space in the page file.");
    9691 
    9692     /* Create and register base metrics */
    9693     pm::BaseMetric *guestCpuLoad = new pm::GuestCpuLoad(mGuestHAL, aMachine, guestLoadUser, guestLoadKernel, guestLoadIdle);
    9694     aCollector->registerBaseMetric(guestCpuLoad);
    9695 
    9696     pm::BaseMetric *guestCpuMem = new pm::GuestRamUsage(mGuestHAL, aMachine, guestMemTotal, guestMemFree, guestMemBalloon, guestMemShared,
    9697                                                         guestMemCache, guestPagedTotal);
    9698     aCollector->registerBaseMetric(guestCpuMem);
    9699 
    9700     aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadUser, 0));
    9701     aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadUser, new pm::AggregateAvg()));
    9702     aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadUser, new pm::AggregateMin()));
    9703     aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadUser, new pm::AggregateMax()));
    9704 
    9705     aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadKernel, 0));
    9706     aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadKernel, new pm::AggregateAvg()));
    9707     aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadKernel, new pm::AggregateMin()));
    9708     aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadKernel, new pm::AggregateMax()));
    9709 
    9710     aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadIdle, 0));
    9711     aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadIdle, new pm::AggregateAvg()));
    9712     aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadIdle, new pm::AggregateMin()));
    9713     aCollector->registerMetric(new pm::Metric(guestCpuLoad, guestLoadIdle, new pm::AggregateMax()));
    9714 
    9715     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemTotal, 0));
    9716     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemTotal, new pm::AggregateAvg()));
    9717     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemTotal, new pm::AggregateMin()));
    9718     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemTotal, new pm::AggregateMax()));
    9719 
    9720     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemFree, 0));
    9721     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemFree, new pm::AggregateAvg()));
    9722     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemFree, new pm::AggregateMin()));
    9723     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemFree, new pm::AggregateMax()));
    9724 
    9725     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemBalloon, 0));
    9726     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemBalloon, new pm::AggregateAvg()));
    9727     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemBalloon, new pm::AggregateMin()));
    9728     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemBalloon, new pm::AggregateMax()));
    9729 
    9730     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemShared, 0));
    9731     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemShared, new pm::AggregateAvg()));
    9732     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemShared, new pm::AggregateMin()));
    9733     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemShared, new pm::AggregateMax()));
    9734 
    9735     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemCache, 0));
    9736     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemCache, new pm::AggregateAvg()));
    9737     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemCache, new pm::AggregateMin()));
    9738     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestMemCache, new pm::AggregateMax()));
    9739 
    9740     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestPagedTotal, 0));
    9741     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestPagedTotal, new pm::AggregateAvg()));
    9742     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestPagedTotal, new pm::AggregateMin()));
    9743     aCollector->registerMetric(new pm::Metric(guestCpuMem, guestPagedTotal, new pm::AggregateMax()));
    9744 }
    9745 
    9746 void Machine::unregisterMetrics(PerformanceCollector *aCollector, Machine *aMachine)
    9747 {
    9748     AssertReturnVoid(isWriteLockOnCurrentThread());
    9749 
    9750     if (aCollector)
    9751     {
    9752         aCollector->unregisterMetricsFor(aMachine);
    9753         aCollector->unregisterBaseMetricsFor(aMachine);
    9754     }
    9755 
    9756     if (mGuestHAL)
    9757     {
    9758         delete mGuestHAL;
    9759         mGuestHAL = NULL;
    9760     }
    9761 }
    9762 
    9763 #endif /* VBOX_WITH_RESOURCE_USAGE_API */
    9764 
    9765 
    9766 ////////////////////////////////////////////////////////////////////////////////
    9767 
    9768 DEFINE_EMPTY_CTOR_DTOR(SessionMachine)
    9769 
    9770 HRESULT SessionMachine::FinalConstruct()
    9771 {
    9772     LogFlowThisFunc(("\n"));
    9773 
    9774 #if defined(RT_OS_WINDOWS)
    9775     mIPCSem = NULL;
    9776 #elif defined(RT_OS_OS2)
    9777     mIPCSem = NULLHANDLE;
    9778 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
    9779     mIPCSem = -1;
    9780 #else
    9781 # error "Port me!"
    9782 #endif
    9783 
    9784     return S_OK;
    9785 }
    9786 
    9787 void SessionMachine::FinalRelease()
    9788 {
    9789     LogFlowThisFunc(("\n"));
    9790 
    9791     uninit(Uninit::Unexpected);
    9792 }
    9793 
    9794 /**
    9795  *  @note Must be called only by Machine::openSession() from its own write lock.
    9796  */
    9797 HRESULT SessionMachine::init(Machine *aMachine)
    9798 {
    9799     LogFlowThisFuncEnter();
    9800     LogFlowThisFunc(("mName={%s}\n", aMachine->mUserData->s.strName.c_str()));
    9801 
    9802     AssertReturn(aMachine, E_INVALIDARG);
    9803 
    9804     AssertReturn(aMachine->lockHandle()->isWriteLockOnCurrentThread(), E_FAIL);
    9805 
    9806     /* Enclose the state transition NotReady->InInit->Ready */
    9807     AutoInitSpan autoInitSpan(this);
    9808     AssertReturn(autoInitSpan.isOk(), E_FAIL);
    9809 
    9810     /* create the interprocess semaphore */
    9811 #if defined(RT_OS_WINDOWS)
    9812     mIPCSemName = aMachine->mData->m_strConfigFileFull;
    9813     for (size_t i = 0; i < mIPCSemName.length(); i++)
    9814         if (mIPCSemName[i] == '\\')
    9815             mIPCSemName[i] = '/';
    9816     mIPCSem = ::CreateMutex(NULL, FALSE, mIPCSemName);
    9817     ComAssertMsgRet(mIPCSem,
    9818                     ("Cannot create IPC mutex '%ls', err=%d",
    9819                      mIPCSemName.raw(), ::GetLastError()),
    9820                     E_FAIL);
    9821 #elif defined(RT_OS_OS2)
    9822     Utf8Str ipcSem = Utf8StrFmt("\\SEM32\\VBOX\\VM\\{%RTuuid}",
    9823                                 aMachine->mData->mUuid.raw());
    9824     mIPCSemName = ipcSem;
    9825     APIRET arc = ::DosCreateMutexSem((PSZ)ipcSem.raw(), &mIPCSem, 0, FALSE);
    9826     ComAssertMsgRet(arc == NO_ERROR,
    9827                     ("Cannot create IPC mutex '%s', arc=%ld",
    9828                      ipcSem.raw(), arc),
    9829                     E_FAIL);
    9830 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
    9831 # ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
    9832 #  if defined(RT_OS_FREEBSD) && (HC_ARCH_BITS == 64)
    9833     /** @todo Check that this still works correctly. */
    9834     AssertCompileSize(key_t, 8);
    9835 #  else
    9836     AssertCompileSize(key_t, 4);
    9837 #  endif
    9838     key_t key;
    9839     mIPCSem = -1;
    9840     mIPCKey = "0";
    9841     for (uint32_t i = 0; i < 1 << 24; i++)
    9842     {
    9843         key = ((uint32_t)'V' << 24) | i;
    9844         int sem = ::semget(key, 1, S_IRUSR | S_IWUSR | IPC_CREAT | IPC_EXCL);
    9845         if (sem >= 0 || (errno != EEXIST && errno != EACCES))
    9846         {
    9847             mIPCSem = sem;
    9848             if (sem >= 0)
    9849                 mIPCKey = BstrFmt("%u", key);
    9850             break;
    9851         }
    9852     }
    9853 # else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
    9854     Utf8Str semName = aMachine->mData->m_strConfigFileFull;
    9855     char *pszSemName = NULL;
    9856     RTStrUtf8ToCurrentCP(&pszSemName, semName);
    9857     key_t key = ::ftok(pszSemName, 'V');
    9858     RTStrFree(pszSemName);
    9859 
    9860     mIPCSem = ::semget(key, 1, S_IRWXU | S_IRWXG | S_IRWXO | IPC_CREAT);
    9861 # endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
    9862 
    9863     int errnoSave = errno;
    9864     if (mIPCSem < 0 && errnoSave == ENOSYS)
    9865     {
    9866         setError(E_FAIL,
    9867                  tr("Cannot create IPC semaphore. Most likely your host kernel lacks "
    9868                     "support for SysV IPC. Check the host kernel configuration for "
    9869                     "CONFIG_SYSVIPC=y"));
    9870         return E_FAIL;
    9871     }
    9872     /* ENOSPC can also be the result of VBoxSVC crashes without properly freeing
    9873      * the IPC semaphores */
    9874     if (mIPCSem < 0 && errnoSave == ENOSPC)
    9875     {
    9876 #ifdef RT_OS_LINUX
    9877         setError(E_FAIL,
    9878                  tr("Cannot create IPC semaphore because the system limit for the "
    9879                     "maximum number of semaphore sets (SEMMNI), or the system wide "
    9880                     "maximum number of sempahores (SEMMNS) would be exceeded. The "
    9881                     "current set of SysV IPC semaphores can be determined from "
    9882                     "the file /proc/sysvipc/sem"));
    9883 #else
    9884         setError(E_FAIL,
    9885                  tr("Cannot create IPC semaphore because the system-imposed limit "
    9886                     "on the maximum number of allowed  semaphores or semaphore "
    9887                     "identifiers system-wide would be exceeded"));
    9888 #endif
    9889         return E_FAIL;
    9890     }
    9891     ComAssertMsgRet(mIPCSem >= 0, ("Cannot create IPC semaphore, errno=%d", errnoSave),
    9892                     E_FAIL);
    9893     /* set the initial value to 1 */
    9894     int rv = ::semctl(mIPCSem, 0, SETVAL, 1);
    9895     ComAssertMsgRet(rv == 0, ("Cannot init IPC semaphore, errno=%d", errno),
    9896                     E_FAIL);
    9897 #else
    9898 # error "Port me!"
    9899 #endif
    9900 
    9901     /* memorize the peer Machine */
    9902     unconst(mPeer) = aMachine;
    9903     /* share the parent pointer */
    9904     unconst(mParent) = aMachine->mParent;
    9905 
    9906     /* take the pointers to data to share */
    9907     mData.share(aMachine->mData);
    9908     mSSData.share(aMachine->mSSData);
    9909 
    9910     mUserData.share(aMachine->mUserData);
    9911     mHWData.share(aMachine->mHWData);
    9912     mMediaData.share(aMachine->mMediaData);
    9913 
    9914     mStorageControllers.allocate();
    9915     for (StorageControllerList::const_iterator it = aMachine->mStorageControllers->begin();
    9916          it != aMachine->mStorageControllers->end();
    9917          ++it)
    9918     {
    9919         ComObjPtr<StorageController> ctl;
    9920         ctl.createObject();
    9921         ctl->init(this, *it);
    9922         mStorageControllers->push_back(ctl);
    9923     }
    9924 
    9925     unconst(mBIOSSettings).createObject();
    9926     mBIOSSettings->init(this, aMachine->mBIOSSettings);
    9927 #ifdef VBOX_WITH_VRDP
    9928     /* create another VRDPServer object that will be mutable */
    9929     unconst(mVRDPServer).createObject();
    9930     mVRDPServer->init(this, aMachine->mVRDPServer);
    9931 #endif
    9932     /* create another audio adapter object that will be mutable */
    9933     unconst(mAudioAdapter).createObject();
    9934     mAudioAdapter->init(this, aMachine->mAudioAdapter);
    9935     /* create a list of serial ports that will be mutable */
    9936     for (ULONG slot = 0; slot < RT_ELEMENTS(mSerialPorts); slot++)
    9937     {
    9938         unconst(mSerialPorts[slot]).createObject();
    9939         mSerialPorts[slot]->init(this, aMachine->mSerialPorts[slot]);
    9940     }
    9941     /* create a list of parallel ports that will be mutable */
    9942     for (ULONG slot = 0; slot < RT_ELEMENTS(mParallelPorts); slot++)
    9943     {
    9944         unconst(mParallelPorts[slot]).createObject();
    9945         mParallelPorts[slot]->init(this, aMachine->mParallelPorts[slot]);
    9946     }
    9947     /* create another USB controller object that will be mutable */
    9948     unconst(mUSBController).createObject();
    9949     mUSBController->init(this, aMachine->mUSBController);
    9950 
    9951     /* create a list of network adapters that will be mutable */
    9952     for (ULONG slot = 0; slot < RT_ELEMENTS(mNetworkAdapters); slot++)
    9953     {
    9954         unconst(mNetworkAdapters[slot]).createObject();
    9955         mNetworkAdapters[slot]->init(this, aMachine->mNetworkAdapters[slot]);
    9956     }
    9957 
    9958     /* default is to delete saved state on Saved -> PoweredOff transition */
    9959     mRemoveSavedState = true;
    9960 
    9961     /* Confirm a successful initialization when it's the case */
    9962     autoInitSpan.setSucceeded();
    9963 
    9964     LogFlowThisFuncLeave();
    9965     return S_OK;
    9966 }
    9967 
    9968 /**
    9969  *  Uninitializes this session object. If the reason is other than
    9970  *  Uninit::Unexpected, then this method MUST be called from #checkForDeath().
    9971  *
    9972  *  @param aReason          uninitialization reason
    9973  *
    9974  *  @note Locks mParent + this object for writing.
    9975  */
    9976 void SessionMachine::uninit(Uninit::Reason aReason)
    9977 {
    9978     LogFlowThisFuncEnter();
    9979     LogFlowThisFunc(("reason=%d\n", aReason));
    9980 
    9981     /*
    9982      *  Strongly reference ourselves to prevent this object deletion after
    9983      *  mData->mSession.mMachine.setNull() below (which can release the last
    9984      *  reference and call the destructor). Important: this must be done before
    9985      *  accessing any members (and before AutoUninitSpan that does it as well).
    9986      *  This self reference will be released as the very last step on return.
    9987      */
    9988     ComObjPtr<SessionMachine> selfRef = this;
    9989 
    9990     /* Enclose the state transition Ready->InUninit->NotReady */
    9991     AutoUninitSpan autoUninitSpan(this);
    9992     if (autoUninitSpan.uninitDone())
    9993     {
    9994         LogFlowThisFunc(("Already uninitialized\n"));
    9995         LogFlowThisFuncLeave();
    9996         return;
    9997     }
    9998 
    9999     if (autoUninitSpan.initFailed())
    10000     {
    10001         /* We've been called by init() because it's failed. It's not really
    10002          * necessary (nor it's safe) to perform the regular uninit sequense
    10003          * below, the following is enough.
    10004          */
    10005         LogFlowThisFunc(("Initialization failed.\n"));
    10006 #if defined(RT_OS_WINDOWS)
    10007         if (mIPCSem)
    10008             ::CloseHandle(mIPCSem);
    10009         mIPCSem = NULL;
    10010 #elif defined(RT_OS_OS2)
    10011         if (mIPCSem != NULLHANDLE)
    10012             ::DosCloseMutexSem(mIPCSem);
    10013         mIPCSem = NULLHANDLE;
    10014 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
    10015         if (mIPCSem >= 0)
    10016             ::semctl(mIPCSem, 0, IPC_RMID);
    10017         mIPCSem = -1;
    10018 # ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
    10019         mIPCKey = "0";
    10020 # endif /* VBOX_WITH_NEW_SYS_V_KEYGEN */
    10021 #else
    10022 # error "Port me!"
    10023 #endif
    10024         uninitDataAndChildObjects();
    10025         mData.free();
    10026         unconst(mParent) = NULL;
    10027         unconst(mPeer) = NULL;
    10028         LogFlowThisFuncLeave();
    10029         return;
    10030     }
    10031 
    10032     MachineState_T lastState;
    10033     {
    10034         AutoReadLock tempLock(this COMMA_LOCKVAL_SRC_POS);
    10035         lastState = mData->mMachineState;
    10036     }
    10037     NOREF(lastState);
    10038 
    10039 #ifdef VBOX_WITH_USB
    10040     // release all captured USB devices, but do this before requesting the locks below
    10041     if (aReason == Uninit::Abnormal && Global::IsOnline(lastState))
    10042     {
    10043         /* Console::captureUSBDevices() is called in the VM process only after
    10044          * setting the machine state to Starting or Restoring.
    10045          * Console::detachAllUSBDevices() will be called upon successful
    10046          * termination. So, we need to release USB devices only if there was
    10047          * an abnormal termination of a running VM.
    10048          *
    10049          * This is identical to SessionMachine::DetachAllUSBDevices except
    10050          * for the aAbnormal argument. */
    10051         HRESULT rc = mUSBController->notifyProxy(false /* aInsertFilters */);
    10052         AssertComRC(rc);
    10053         NOREF(rc);
    10054 
    10055         USBProxyService *service = mParent->host()->usbProxyService();
    10056         if (service)
    10057             service->detachAllDevicesFromVM(this, true /* aDone */, true /* aAbnormal */);
    10058     }
    10059 #endif /* VBOX_WITH_USB */
    10060 
    10061     // we need to lock this object in uninit() because the lock is shared
    10062     // with mPeer (as well as data we modify below). mParent->addProcessToReap()
    10063     // and others need mParent lock, and USB needs host lock.
    10064     AutoMultiWriteLock3 multilock(mParent, mParent->host(), this COMMA_LOCKVAL_SRC_POS);
    10065 
    10066     // Trigger async cleanup tasks, avoid doing things here which are not
    10067     // vital to be done immediately and maybe need more locks. This calls
    10068     // Machine::unregisterMetrics().
    10069     mParent->onMachineUninit(mPeer);
    10070 
    10071     if (aReason == Uninit::Abnormal)
    10072     {
    10073         LogWarningThisFunc(("ABNORMAL client termination! (wasBusy=%d)\n",
    10074                              Global::IsOnlineOrTransient(lastState)));
    10075 
    10076         /* reset the state to Aborted */
    10077         if (mData->mMachineState != MachineState_Aborted)
    10078             setMachineState(MachineState_Aborted);
    10079     }
    10080 
    10081     // any machine settings modified?
    10082     if (mData->flModifications)
    10083     {
    10084         LogWarningThisFunc(("Discarding unsaved settings changes!\n"));
    10085         rollback(false /* aNotify */);
    10086     }
    10087 
    10088     Assert(mSnapshotData.mStateFilePath.isEmpty() || !mSnapshotData.mSnapshot);
    10089     if (!mSnapshotData.mStateFilePath.isEmpty())
    10090     {
    10091         LogWarningThisFunc(("canceling failed save state request!\n"));
    10092         endSavingState(FALSE /* aSuccess  */);
    10093     }
    10094     else if (!mSnapshotData.mSnapshot.isNull())
    10095     {
    10096         LogWarningThisFunc(("canceling untaken snapshot!\n"));
    10097 
    10098         /* delete all differencing hard disks created (this will also attach
    10099          * their parents back by rolling back mMediaData) */
    10100         rollbackMedia();
    10101         /* delete the saved state file (it might have been already created) */
    10102         if (mSnapshotData.mSnapshot->stateFilePath().length())
    10103             RTFileDelete(mSnapshotData.mSnapshot->stateFilePath().c_str());
    10104 
    10105         mSnapshotData.mSnapshot->uninit();
    10106     }
    10107 
    10108     if (!mData->mSession.mType.isEmpty())
    10109     {
    10110         /* mType is not null when this machine's process has been started by
    10111          * Machine::launchVMProcess(), therefore it is our child.  We
    10112          * need to queue the PID to reap the process (and avoid zombies on
    10113          * Linux). */
    10114         Assert(mData->mSession.mPid != NIL_RTPROCESS);
    10115         mParent->addProcessToReap(mData->mSession.mPid);
    10116     }
    10117 
    10118     mData->mSession.mPid = NIL_RTPROCESS;
    10119 
    10120     if (aReason == Uninit::Unexpected)
    10121     {
    10122         /* Uninitialization didn't come from #checkForDeath(), so tell the
    10123          * client watcher thread to update the set of machines that have open
    10124          * sessions. */
    10125         mParent->updateClientWatcher();
    10126     }
    10127 
    10128     /* uninitialize all remote controls */
    10129     if (mData->mSession.mRemoteControls.size())
    10130     {
    10131         LogFlowThisFunc(("Closing remote sessions (%d):\n",
    10132                           mData->mSession.mRemoteControls.size()));
    10133 
    10134         Data::Session::RemoteControlList::iterator it =
    10135             mData->mSession.mRemoteControls.begin();
    10136         while (it != mData->mSession.mRemoteControls.end())
    10137         {
    10138             LogFlowThisFunc(("  Calling remoteControl->Uninitialize()...\n"));
    10139             HRESULT rc = (*it)->Uninitialize();
    10140             LogFlowThisFunc(("  remoteControl->Uninitialize() returned %08X\n", rc));
    10141             if (FAILED(rc))
    10142                 LogWarningThisFunc(("Forgot to close the remote session?\n"));
    10143             ++it;
    10144         }
    10145         mData->mSession.mRemoteControls.clear();
    10146     }
    10147 
    10148     /*
    10149      *  An expected uninitialization can come only from #checkForDeath().
    10150      *  Otherwise it means that something's got really wrong (for examlple,
    10151      *  the Session implementation has released the VirtualBox reference
    10152      *  before it triggered #OnSessionEnd(), or before releasing IPC semaphore,
    10153      *  etc). However, it's also possible, that the client releases the IPC
    10154      *  semaphore correctly (i.e. before it releases the VirtualBox reference),
    10155      *  but the VirtualBox release event comes first to the server process.
    10156      *  This case is practically possible, so we should not assert on an
    10157      *  unexpected uninit, just log a warning.
    10158      */
    10159 
    10160     if ((aReason == Uninit::Unexpected))
    10161         LogWarningThisFunc(("Unexpected SessionMachine uninitialization!\n"));
    10162 
    10163     if (aReason != Uninit::Normal)
    10164     {
    10165         mData->mSession.mDirectControl.setNull();
    10166     }
    10167     else
    10168     {
    10169         /* this must be null here (see #OnSessionEnd()) */
    10170         Assert(mData->mSession.mDirectControl.isNull());
    10171         Assert(mData->mSession.mState == SessionState_Unlocking);
    10172         Assert(!mData->mSession.mProgress.isNull());
    10173     }
    10174     if (mData->mSession.mProgress)
    10175     {
    10176         if (aReason == Uninit::Normal)
    10177             mData->mSession.mProgress->notifyComplete(S_OK);
    10178         else
    10179             mData->mSession.mProgress->notifyComplete(E_FAIL,
    10180                                                       COM_IIDOF(ISession),
    10181                                                       getComponentName(),
    10182                                                       tr("The VM session was aborted"));
    10183         mData->mSession.mProgress.setNull();
    10184     }
    10185 
    10186     /* remove the association between the peer machine and this session machine */
    10187     Assert(   (SessionMachine*)mData->mSession.mMachine == this
    10188             || aReason == Uninit::Unexpected);
    10189 
    10190     /* reset the rest of session data */
    10191     mData->mSession.mMachine.setNull();
    10192     mData->mSession.mState = SessionState_Unlocked;
    10193     mData->mSession.mType.setNull();
    10194 
    10195     /* close the interprocess semaphore before leaving the exclusive lock */
    10196 #if defined(RT_OS_WINDOWS)
    10197     if (mIPCSem)
    10198         ::CloseHandle(mIPCSem);
    10199     mIPCSem = NULL;
    10200 #elif defined(RT_OS_OS2)
    10201     if (mIPCSem != NULLHANDLE)
    10202         ::DosCloseMutexSem(mIPCSem);
    10203     mIPCSem = NULLHANDLE;
    10204 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
    10205     if (mIPCSem >= 0)
    10206         ::semctl(mIPCSem, 0, IPC_RMID);
    10207     mIPCSem = -1;
    10208 # ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
    10209     mIPCKey = "0";
    10210 # endif /* VBOX_WITH_NEW_SYS_V_KEYGEN */
    10211 #else
    10212 # error "Port me!"
    10213 #endif
    10214 
    10215     /* fire an event */
    10216     mParent->onSessionStateChange(mData->mUuid, SessionState_Unlocked);
    10217 
    10218     uninitDataAndChildObjects();
    10219 
    10220     /* free the essential data structure last */
    10221     mData.free();
    10222 
    10223 #if 1 /** @todo Please review this change! (bird) */
    10224     /* drop the exclusive lock before setting the below two to NULL */
    10225     multilock.release();
    10226 #else
    10227     /* leave the exclusive lock before setting the below two to NULL */
    10228     multilock.leave();
    10229 #endif
    10230 
    10231     unconst(mParent) = NULL;
    10232     unconst(mPeer) = NULL;
    10233 
    10234     LogFlowThisFuncLeave();
    10235 }
    10236 
    10237 // util::Lockable interface
    10238 ////////////////////////////////////////////////////////////////////////////////
    10239 
    10240 /**
    10241  *  Overrides VirtualBoxBase::lockHandle() in order to share the lock handle
    10242  *  with the primary Machine instance (mPeer).
    10243  */
    10244 RWLockHandle *SessionMachine::lockHandle() const
    10245 {
    10246     AssertReturn(mPeer != NULL, NULL);
    10247     return mPeer->lockHandle();
    10248 }
    10249 
    10250 // IInternalMachineControl methods
    10251 ////////////////////////////////////////////////////////////////////////////////
    10252 
    10253 /**
    10254  *  @note Locks this object for writing.
    10255  */
    10256 STDMETHODIMP SessionMachine::SetRemoveSavedStateFile(BOOL aRemove)
    10257 {
    10258     AutoCaller autoCaller(this);
    10259     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10260 
    10261     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    10262 
    10263     mRemoveSavedState = aRemove;
    10264 
    10265     return S_OK;
    10266 }
    10267 
    10268 /**
    10269  *  @note Locks the same as #setMachineState() does.
    10270  */
    10271 STDMETHODIMP SessionMachine::UpdateState(MachineState_T aMachineState)
    10272 {
    10273     return setMachineState(aMachineState);
    10274 }
    10275 
    10276 /**
    10277  *  @note Locks this object for reading.
    10278  */
    10279 STDMETHODIMP SessionMachine::GetIPCId(BSTR *aId)
    10280 {
    10281     AutoCaller autoCaller(this);
    10282     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10283 
    10284     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    10285 
    10286 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    10287     mIPCSemName.cloneTo(aId);
    10288     return S_OK;
    10289 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
    10290 # ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
    10291     mIPCKey.cloneTo(aId);
    10292 # else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
    10293     mData->m_strConfigFileFull.cloneTo(aId);
    10294 # endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
    10295     return S_OK;
    10296 #else
    10297 # error "Port me!"
    10298 #endif
    10299 }
    10300 
    10301 /**
    10302  *  @note Locks this object for writing.
    10303  */
    10304 STDMETHODIMP SessionMachine::BeginPowerUp(IProgress *aProgress)
    10305 {
    10306     LogFlowThisFunc(("aProgress=%p\n", aProgress));
    10307     AutoCaller autoCaller(this);
    10308     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10309 
    10310     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    10311 
    10312     if (mData->mSession.mState != SessionState_Locked)
    10313         return VBOX_E_INVALID_OBJECT_STATE;
    10314 
    10315     if (!mData->mSession.mProgress.isNull())
    10316         mData->mSession.mProgress->setOtherProgressObject(aProgress);
    10317 
    10318     LogFlowThisFunc(("returns S_OK.\n"));
    10319     return S_OK;
    10320 }
    10321 
    10322 
    10323 /**
    10324  *  @note Locks this object for writing.
    10325  */
    10326 STDMETHODIMP SessionMachine::EndPowerUp(LONG iResult)
    10327 {
    10328     AutoCaller autoCaller(this);
    10329     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10330 
    10331     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    10332 
    10333     if (mData->mSession.mState != SessionState_Locked)
    10334         return VBOX_E_INVALID_OBJECT_STATE;
    10335 
    10336     /* Finalize the openRemoteSession progress object. */
    10337     if (mData->mSession.mProgress)
    10338     {
    10339         mData->mSession.mProgress->notifyComplete((HRESULT)iResult);
    10340         mData->mSession.mProgress.setNull();
    10341 
    10342         if (SUCCEEDED((HRESULT)iResult))
    10343         {
    10344 #ifdef VBOX_WITH_RESOURCE_USAGE_API
    10345             /* The VM has been powered up successfully, so it makes sense
    10346              * now to offer the performance metrics for a running machine
    10347              * object. Doing it earlier wouldn't be safe. */
    10348             registerMetrics(mParent->performanceCollector(), mPeer,
    10349                             mData->mSession.mPid);
    10350 #endif /* VBOX_WITH_RESOURCE_USAGE_API */
    10351 
    10352         }
    10353     }
    10354     return S_OK;
    10355 }
    10356 
    10357 /**
    10358  *  Goes through the USB filters of the given machine to see if the given
    10359  *  device matches any filter or not.
    10360  *
    10361  *  @note Locks the same as USBController::hasMatchingFilter() does.
    10362  */
    10363 STDMETHODIMP SessionMachine::RunUSBDeviceFilters(IUSBDevice *aUSBDevice,
    10364                                                  BOOL *aMatched,
    10365                                                  ULONG *aMaskedIfs)
    10366 {
    10367     LogFlowThisFunc(("\n"));
    10368 
    10369     CheckComArgNotNull(aUSBDevice);
    10370     CheckComArgOutPointerValid(aMatched);
    10371 
    10372     AutoCaller autoCaller(this);
    10373     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10374 
    10375 #ifdef VBOX_WITH_USB
    10376     *aMatched = mUSBController->hasMatchingFilter(aUSBDevice, aMaskedIfs);
    10377 #else
    10378     NOREF(aUSBDevice);
    10379     NOREF(aMaskedIfs);
    10380     *aMatched = FALSE;
    10381 #endif
    10382 
    10383     return S_OK;
    10384 }
    10385 
    10386 /**
    10387  *  @note Locks the same as Host::captureUSBDevice() does.
    10388  */
    10389 STDMETHODIMP SessionMachine::CaptureUSBDevice(IN_BSTR aId)
    10390 {
    10391     LogFlowThisFunc(("\n"));
    10392 
    10393     AutoCaller autoCaller(this);
    10394     AssertComRCReturnRC(autoCaller.rc());
    10395 
    10396 #ifdef VBOX_WITH_USB
    10397     /* if captureDeviceForVM() fails, it must have set extended error info */
    10398     MultiResult rc = mParent->host()->checkUSBProxyService();
    10399     if (FAILED(rc)) return rc;
    10400 
    10401     USBProxyService *service = mParent->host()->usbProxyService();
    10402     AssertReturn(service, E_FAIL);
    10403     return service->captureDeviceForVM(this, Guid(aId));
    10404 #else
    10405     NOREF(aId);
    10406     return E_NOTIMPL;
    10407 #endif
    10408 }
    10409 
    10410 /**
    10411  *  @note Locks the same as Host::detachUSBDevice() does.
    10412  */
    10413 STDMETHODIMP SessionMachine::DetachUSBDevice(IN_BSTR aId, BOOL aDone)
    10414 {
    10415     LogFlowThisFunc(("\n"));
    10416 
    10417     AutoCaller autoCaller(this);
    10418     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10419 
    10420 #ifdef VBOX_WITH_USB
    10421     USBProxyService *service = mParent->host()->usbProxyService();
    10422     AssertReturn(service, E_FAIL);
    10423     return service->detachDeviceFromVM(this, Guid(aId), !!aDone);
    10424 #else
    10425     NOREF(aId);
    10426     NOREF(aDone);
    10427     return E_NOTIMPL;
    10428 #endif
    10429 }
    10430 
    10431 /**
    10432  *  Inserts all machine filters to the USB proxy service and then calls
    10433  *  Host::autoCaptureUSBDevices().
    10434  *
    10435  *  Called by Console from the VM process upon VM startup.
    10436  *
    10437  *  @note Locks what called methods lock.
    10438  */
    10439 STDMETHODIMP SessionMachine::AutoCaptureUSBDevices()
    10440 {
    10441     LogFlowThisFunc(("\n"));
    10442 
    10443     AutoCaller autoCaller(this);
    10444     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10445 
    10446 #ifdef VBOX_WITH_USB
    10447     HRESULT rc = mUSBController->notifyProxy(true /* aInsertFilters */);
    10448     AssertComRC(rc);
    10449     NOREF(rc);
    10450 
    10451     USBProxyService *service = mParent->host()->usbProxyService();
    10452     AssertReturn(service, E_FAIL);
    10453     return service->autoCaptureDevicesForVM(this);
    10454 #else
    10455     return S_OK;
    10456 #endif
    10457 }
    10458 
    10459 /**
    10460  *  Removes all machine filters from the USB proxy service and then calls
    10461  *  Host::detachAllUSBDevices().
    10462  *
    10463  *  Called by Console from the VM process upon normal VM termination or by
    10464  *  SessionMachine::uninit() upon abnormal VM termination (from under the
    10465  *  Machine/SessionMachine lock).
    10466  *
    10467  *  @note Locks what called methods lock.
    10468  */
    10469 STDMETHODIMP SessionMachine::DetachAllUSBDevices(BOOL aDone)
    10470 {
    10471     LogFlowThisFunc(("\n"));
    10472 
    10473     AutoCaller autoCaller(this);
    10474     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10475 
    10476 #ifdef VBOX_WITH_USB
    10477     HRESULT rc = mUSBController->notifyProxy(false /* aInsertFilters */);
    10478     AssertComRC(rc);
    10479     NOREF(rc);
    10480 
    10481     USBProxyService *service = mParent->host()->usbProxyService();
    10482     AssertReturn(service, E_FAIL);
    10483     return service->detachAllDevicesFromVM(this, !!aDone, false /* aAbnormal */);
    10484 #else
    10485     NOREF(aDone);
    10486     return S_OK;
    10487 #endif
    10488 }
    10489 
    10490 /**
    10491  *  @note Locks this object for writing.
    10492  */
    10493 STDMETHODIMP SessionMachine::OnSessionEnd(ISession *aSession,
    10494                                           IProgress **aProgress)
    10495 {
    10496     LogFlowThisFuncEnter();
    10497 
    10498     AssertReturn(aSession, E_INVALIDARG);
    10499     AssertReturn(aProgress, E_INVALIDARG);
    10500 
    10501     AutoCaller autoCaller(this);
    10502 
    10503     LogFlowThisFunc(("callerstate=%d\n", autoCaller.state()));
    10504     /*
    10505      *  We don't assert below because it might happen that a non-direct session
    10506      *  informs us it is closed right after we've been uninitialized -- it's ok.
    10507      */
    10508     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    10509 
    10510     /* get IInternalSessionControl interface */
    10511     ComPtr<IInternalSessionControl> control(aSession);
    10512 
    10513     ComAssertRet(!control.isNull(), E_INVALIDARG);
    10514 
    10515     /* Creating a Progress object requires the VirtualBox lock, and
    10516      * thus locking it here is required by the lock order rules. */
    10517     AutoMultiWriteLock2 alock(mParent->lockHandle(), this->lockHandle() COMMA_LOCKVAL_SRC_POS);
    10518 
    10519     if (control == mData->mSession.mDirectControl)
    10520     {
    10521         ComAssertRet(aProgress, E_POINTER);
    10522 
    10523         /* The direct session is being normally closed by the client process
    10524          * ----------------------------------------------------------------- */
    10525 
    10526         /* go to the closing state (essential for all open*Session() calls and
    10527          * for #checkForDeath()) */
    10528         Assert(mData->mSession.mState == SessionState_Locked);
    10529         mData->mSession.mState = SessionState_Unlocking;
    10530 
    10531         /* set direct control to NULL to release the remote instance */
    10532         mData->mSession.mDirectControl.setNull();
    10533         LogFlowThisFunc(("Direct control is set to NULL\n"));
    10534 
    10535         if (mData->mSession.mProgress)
    10536         {
    10537             /* finalize the progress, someone might wait if a frontend
    10538              * closes the session before powering on the VM. */
    10539             mData->mSession.mProgress->notifyComplete(E_FAIL,
    10540                                                       COM_IIDOF(ISession),
    10541                                                       getComponentName(),
    10542                                                       tr("The VM session was closed before any attempt to power it on"));
    10543             mData->mSession.mProgress.setNull();
    10544         }
    10545 
    10546         /*  Create the progress object the client will use to wait until
    10547          * #checkForDeath() is called to uninitialize this session object after
    10548          * it releases the IPC semaphore.
    10549          * Note! Because we're "reusing" mProgress here, this must be a proxy
    10550          *       object just like for openRemoteSession. */
    10551         Assert(mData->mSession.mProgress.isNull());
    10552         ComObjPtr<ProgressProxy> progress;
    10553         progress.createObject();
    10554         ComPtr<IUnknown> pPeer(mPeer);
    10555         progress->init(mParent, pPeer,
    10556                        Bstr(tr("Closing session")),
    10557                        FALSE /* aCancelable */);
    10558         progress.queryInterfaceTo(aProgress);
    10559         mData->mSession.mProgress = progress;
    10560     }
    10561     else
    10562     {
    10563         /* the remote session is being normally closed */
    10564         Data::Session::RemoteControlList::iterator it =
    10565             mData->mSession.mRemoteControls.begin();
    10566         while (it != mData->mSession.mRemoteControls.end())
    10567         {
    10568             if (control == *it)
    10569                 break;
    10570             ++it;
    10571         }
    10572         BOOL found = it != mData->mSession.mRemoteControls.end();
    10573         ComAssertMsgRet(found, ("The session is not found in the session list!"),
    10574                          E_INVALIDARG);
    10575         mData->mSession.mRemoteControls.remove(*it);
    10576     }
    10577 
    10578     LogFlowThisFuncLeave();
    10579     return S_OK;
    10580 }
    10581 
    10582 /**
    10583  *  @note Locks this object for writing.
    10584  */
    10585 STDMETHODIMP SessionMachine::BeginSavingState(IProgress *aProgress, BSTR *aStateFilePath)
    10586 {
    10587     LogFlowThisFuncEnter();
    10588 
    10589     AssertReturn(aProgress, E_INVALIDARG);
    10590     AssertReturn(aStateFilePath, E_POINTER);
    10591 
    10592     AutoCaller autoCaller(this);
    10593     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10594 
    10595     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    10596 
    10597     AssertReturn(    mData->mMachineState == MachineState_Paused
    10598                   && mSnapshotData.mLastState == MachineState_Null
    10599                   && mSnapshotData.mProgressId.isEmpty()
    10600                   && mSnapshotData.mStateFilePath.isEmpty(),
    10601                  E_FAIL);
    10602 
    10603     /* memorize the progress ID and add it to the global collection */
    10604     Bstr progressId;
    10605     HRESULT rc = aProgress->COMGETTER(Id)(progressId.asOutParam());
    10606     AssertComRCReturn(rc, rc);
    10607     rc = mParent->addProgress(aProgress);
    10608     AssertComRCReturn(rc, rc);
    10609 
    10610     Bstr stateFilePath;
    10611     /* stateFilePath is null when the machine is not running */
    10612     if (mData->mMachineState == MachineState_Paused)
    10613     {
    10614         stateFilePath = Utf8StrFmt("%s%c{%RTuuid}.sav",
    10615                                    mUserData->m_strSnapshotFolderFull.c_str(),
    10616                                    RTPATH_DELIMITER, mData->mUuid.raw());
    10617     }
    10618 
    10619     /* fill in the snapshot data */
    10620     mSnapshotData.mLastState = mData->mMachineState;
    10621     mSnapshotData.mProgressId = Guid(progressId);
    10622     mSnapshotData.mStateFilePath = stateFilePath;
    10623 
    10624     /* set the state to Saving (this is expected by Console::SaveState()) */
    10625     setMachineState(MachineState_Saving);
    10626 
    10627     stateFilePath.cloneTo(aStateFilePath);
    10628 
    10629     return S_OK;
    10630 }
    10631 
    10632 /**
    10633  *  @note Locks mParent + this object for writing.
    10634  */
    10635 STDMETHODIMP SessionMachine::EndSavingState(BOOL aSuccess)
    10636 {
    10637     LogFlowThisFunc(("\n"));
    10638 
    10639     AutoCaller autoCaller(this);
    10640     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10641 
    10642     /* endSavingState() need mParent lock */
    10643     AutoMultiWriteLock2 alock(mParent, this COMMA_LOCKVAL_SRC_POS);
    10644 
    10645     AssertReturn(    mData->mMachineState == MachineState_Saving
    10646                   && mSnapshotData.mLastState != MachineState_Null
    10647                   && !mSnapshotData.mProgressId.isEmpty()
    10648                   && !mSnapshotData.mStateFilePath.isEmpty(),
    10649                  E_FAIL);
    10650 
    10651     /*
    10652      *  on success, set the state to Saved;
    10653      *  on failure, set the state to the state we had when BeginSavingState() was
    10654      *  called (this is expected by Console::SaveState() and
    10655      *  Console::saveStateThread())
    10656      */
    10657     if (aSuccess)
    10658         setMachineState(MachineState_Saved);
    10659     else
    10660         setMachineState(mSnapshotData.mLastState);
    10661 
    10662     return endSavingState(aSuccess);
    10663 }
    10664 
    10665 /**
    10666  *  @note Locks this object for writing.
    10667  */
    10668 STDMETHODIMP SessionMachine::AdoptSavedState(IN_BSTR aSavedStateFile)
    10669 {
    10670     LogFlowThisFunc(("\n"));
    10671 
    10672     CheckComArgStrNotEmptyOrNull(aSavedStateFile);
    10673 
    10674     AutoCaller autoCaller(this);
    10675     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10676 
    10677     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    10678 
    10679     AssertReturn(   mData->mMachineState == MachineState_PoweredOff
    10680                  || mData->mMachineState == MachineState_Teleported
    10681                  || mData->mMachineState == MachineState_Aborted
    10682                  , E_FAIL); /** @todo setError. */
    10683 
    10684     Utf8Str stateFilePathFull = aSavedStateFile;
    10685     int vrc = calculateFullPath(stateFilePathFull, stateFilePathFull);
    10686     if (RT_FAILURE(vrc))
    10687         return setError(VBOX_E_FILE_ERROR,
    10688                         tr("Invalid saved state file path '%ls' (%Rrc)"),
    10689                         aSavedStateFile,
    10690                         vrc);
    10691 
    10692     mSSData->mStateFilePath = stateFilePathFull;
    10693 
    10694     /* The below setMachineState() will detect the state transition and will
    10695      * update the settings file */
    10696 
    10697     return setMachineState(MachineState_Saved);
    10698 }
    10699 
    10700 STDMETHODIMP SessionMachine::PullGuestProperties(ComSafeArrayOut(BSTR, aNames),
    10701                                                  ComSafeArrayOut(BSTR, aValues),
    10702                                                  ComSafeArrayOut(LONG64, aTimestamps),
    10703                                                  ComSafeArrayOut(BSTR, aFlags))
    10704 {
    10705     LogFlowThisFunc(("\n"));
    10706 
    10707 #ifdef VBOX_WITH_GUEST_PROPS
    10708     using namespace guestProp;
    10709 
    10710     AutoCaller autoCaller(this);
    10711     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10712 
    10713     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    10714 
    10715     AssertReturn(!ComSafeArrayOutIsNull(aNames), E_POINTER);
    10716     AssertReturn(!ComSafeArrayOutIsNull(aValues), E_POINTER);
    10717     AssertReturn(!ComSafeArrayOutIsNull(aTimestamps), E_POINTER);
    10718     AssertReturn(!ComSafeArrayOutIsNull(aFlags), E_POINTER);
    10719 
    10720     size_t cEntries = mHWData->mGuestProperties.size();
    10721     com::SafeArray<BSTR> names(cEntries);
    10722     com::SafeArray<BSTR> values(cEntries);
    10723     com::SafeArray<LONG64> timestamps(cEntries);
    10724     com::SafeArray<BSTR> flags(cEntries);
    10725     unsigned i = 0;
    10726     for (HWData::GuestPropertyList::iterator it = mHWData->mGuestProperties.begin();
    10727          it != mHWData->mGuestProperties.end();
    10728          ++it)
    10729     {
    10730         char szFlags[MAX_FLAGS_LEN + 1];
    10731         it->strName.cloneTo(&names[i]);
    10732         it->strValue.cloneTo(&values[i]);
    10733         timestamps[i] = it->mTimestamp;
    10734         /* If it is NULL, keep it NULL. */
    10735         if (it->mFlags)
    10736         {
    10737             writeFlags(it->mFlags, szFlags);
    10738             Bstr(szFlags).cloneTo(&flags[i]);
    10739         }
    10740         else
    10741             flags[i] = NULL;
    10742         ++i;
    10743     }
    10744     names.detachTo(ComSafeArrayOutArg(aNames));
    10745     values.detachTo(ComSafeArrayOutArg(aValues));
    10746     timestamps.detachTo(ComSafeArrayOutArg(aTimestamps));
    10747     flags.detachTo(ComSafeArrayOutArg(aFlags));
    10748     return S_OK;
    10749 #else
    10750     ReturnComNotImplemented();
    10751 #endif
    10752 }
    10753 
    10754 STDMETHODIMP SessionMachine::PushGuestProperty(IN_BSTR aName,
    10755                                                IN_BSTR aValue,
    10756                                                LONG64 aTimestamp,
    10757                                                IN_BSTR aFlags)
    10758 {
    10759     LogFlowThisFunc(("\n"));
    10760 
    10761 #ifdef VBOX_WITH_GUEST_PROPS
    10762     using namespace guestProp;
    10763 
    10764     CheckComArgStrNotEmptyOrNull(aName);
    10765     if (aValue != NULL && (!VALID_PTR(aValue) || !VALID_PTR(aFlags)))
    10766         return E_POINTER;  /* aValue can be NULL to indicate deletion */
    10767 
    10768     try
    10769     {
    10770         /*
    10771          * Convert input up front.
    10772          */
    10773         Utf8Str     utf8Name(aName);
    10774         uint32_t    fFlags = NILFLAG;
    10775         if (aFlags)
    10776         {
    10777             Utf8Str utf8Flags(aFlags);
    10778             int vrc = validateFlags(utf8Flags.c_str(), &fFlags);
    10779             AssertRCReturn(vrc, E_INVALIDARG);
    10780         }
    10781 
    10782         /*
    10783          * Now grab the object lock, validate the state and do the update.
    10784          */
    10785         AutoCaller autoCaller(this);
    10786         if (FAILED(autoCaller.rc())) return autoCaller.rc();
    10787 
    10788         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    10789 
    10790         switch (mData->mMachineState)
    10791         {
    10792             case MachineState_Paused:
    10793             case MachineState_Running:
    10794             case MachineState_Teleporting:
    10795             case MachineState_TeleportingPausedVM:
    10796             case MachineState_LiveSnapshotting:
    10797             case MachineState_DeletingSnapshotOnline:
    10798             case MachineState_DeletingSnapshotPaused:
    10799             case MachineState_Saving:
    10800                 break;
    10801 
    10802             default:
    10803                 AssertMsgFailedReturn(("%s\n", Global::stringifyMachineState(mData->mMachineState)),
    10804                                       VBOX_E_INVALID_VM_STATE);
    10805         }
    10806 
    10807         setModified(IsModified_MachineData);
    10808         mHWData.backup();
    10809 
    10810         /** @todo r=bird: The careful memory handling doesn't work out here because
    10811          *  the catch block won't undo any damange we've done.  So, if push_back throws
    10812          *  bad_alloc then you've lost the value.
    10813          *
    10814          *  Another thing. Doing a linear search here isn't extremely efficient, esp.
    10815          *  since values that changes actually bubbles to the end of the list.  Using
    10816          *  something that has an efficient lookup and can tollerate a bit of updates
    10817          *  would be nice.  RTStrSpace is one suggestion (it's not perfect).  Some
    10818          *  combination of RTStrCache (for sharing names and getting uniqueness into
    10819          *  the bargain) and hash/tree is another. */
    10820         for (HWData::GuestPropertyList::iterator iter = mHWData->mGuestProperties.begin();
    10821              iter != mHWData->mGuestProperties.end();
    10822              ++iter)
    10823             if (utf8Name == iter->strName)
    10824             {
    10825                 mHWData->mGuestProperties.erase(iter);
    10826                 mData->mGuestPropertiesModified = TRUE;
    10827                 break;
    10828             }
    10829         if (aValue != NULL)
    10830         {
    10831             HWData::GuestProperty property = { aName, aValue, aTimestamp, fFlags };
    10832             mHWData->mGuestProperties.push_back(property);
    10833             mData->mGuestPropertiesModified = TRUE;
    10834         }
    10835 
    10836         /*
    10837          * Send a callback notification if appropriate
    10838          */
    10839         if (    mHWData->mGuestPropertyNotificationPatterns.isEmpty()
    10840              || RTStrSimplePatternMultiMatch(mHWData->mGuestPropertyNotificationPatterns.c_str(),
    10841                                              RTSTR_MAX,
    10842                                              utf8Name.c_str(),
    10843                                              RTSTR_MAX, NULL)
    10844            )
    10845         {
    10846             alock.leave();
    10847 
    10848             mParent->onGuestPropertyChange(mData->mUuid,
    10849                                            aName,
    10850                                            aValue,
    10851                                            aFlags);
    10852         }
    10853     }
    10854     catch (...)
    10855     {
    10856         return VirtualBox::handleUnexpectedExceptions(RT_SRC_POS);
    10857     }
    10858     return S_OK;
    10859 #else
    10860     ReturnComNotImplemented();
    10861 #endif
    10862 }
    10863 
    10864 // public methods only for internal purposes
    10865 /////////////////////////////////////////////////////////////////////////////
    10866 
    10867 /**
    10868  * Called from the client watcher thread to check for expected or unexpected
    10869  * death of the client process that has a direct session to this machine.
    10870  *
    10871  * On Win32 and on OS/2, this method is called only when we've got the
    10872  * mutex (i.e. the client has either died or terminated normally) so it always
    10873  * returns @c true (the client is terminated, the session machine is
    10874  * uninitialized).
    10875  *
    10876  * On other platforms, the method returns @c true if the client process has
    10877  * terminated normally or abnormally and the session machine was uninitialized,
    10878  * and @c false if the client process is still alive.
    10879  *
    10880  * @note Locks this object for writing.
    10881  */
    10882 bool SessionMachine::checkForDeath()
    10883 {
    10884     Uninit::Reason reason;
    10885     bool terminated = false;
    10886 
    10887     /* Enclose autoCaller with a block because calling uninit() from under it
    10888      * will deadlock. */
    10889     {
    10890         AutoCaller autoCaller(this);
    10891         if (!autoCaller.isOk())
    10892         {
    10893             /* return true if not ready, to cause the client watcher to exclude
    10894              * the corresponding session from watching */
    10895             LogFlowThisFunc(("Already uninitialized!\n"));
    10896             return true;
    10897         }
    10898 
    10899         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    10900 
    10901         /* Determine the reason of death: if the session state is Closing here,
    10902          * everything is fine. Otherwise it means that the client did not call
    10903          * OnSessionEnd() before it released the IPC semaphore. This may happen
    10904          * either because the client process has abnormally terminated, or
    10905          * because it simply forgot to call ISession::Close() before exiting. We
    10906          * threat the latter also as an abnormal termination (see
    10907          * Session::uninit() for details). */
    10908         reason = mData->mSession.mState == SessionState_Unlocking ?
    10909                  Uninit::Normal :
    10910                  Uninit::Abnormal;
    10911 
    10912 #if defined(RT_OS_WINDOWS)
    10913 
    10914         AssertMsg(mIPCSem, ("semaphore must be created"));
    10915 
    10916         /* release the IPC mutex */
    10917         ::ReleaseMutex(mIPCSem);
    10918 
    10919         terminated = true;
    10920 
    10921 #elif defined(RT_OS_OS2)
    10922 
    10923         AssertMsg(mIPCSem, ("semaphore must be created"));
    10924 
    10925         /* release the IPC mutex */
    10926         ::DosReleaseMutexSem(mIPCSem);
    10927 
    10928         terminated = true;
    10929 
    10930 #elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
    10931 
    10932         AssertMsg(mIPCSem >= 0, ("semaphore must be created"));
    10933 
    10934         int val = ::semctl(mIPCSem, 0, GETVAL);
    10935         if (val > 0)
    10936         {
    10937             /* the semaphore is signaled, meaning the session is terminated */
    10938             terminated = true;
    10939         }
    10940 
    10941 #else
    10942 # error "Port me!"
    10943 #endif
    10944 
    10945     } /* AutoCaller block */
    10946 
    10947     if (terminated)
    10948         uninit(reason);
    10949 
    10950     return terminated;
    10951 }
    10952 
    10953 /**
    10954  *  @note Locks this object for reading.
    10955  */
    10956 HRESULT SessionMachine::onNetworkAdapterChange(INetworkAdapter *networkAdapter, BOOL changeAdapter)
    10957 {
    10958     LogFlowThisFunc(("\n"));
    10959 
    10960     AutoCaller autoCaller(this);
    10961     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10962 
    10963     ComPtr<IInternalSessionControl> directControl;
    10964     {
    10965         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    10966         directControl = mData->mSession.mDirectControl;
    10967     }
    10968 
    10969     /* ignore notifications sent after #OnSessionEnd() is called */
    10970     if (!directControl)
    10971         return S_OK;
    10972 
    10973     return directControl->OnNetworkAdapterChange(networkAdapter, changeAdapter);
    10974 }
    10975 
    10976 /**
    10977  *  @note Locks this object for reading.
    10978  */
    10979 HRESULT SessionMachine::onSerialPortChange(ISerialPort *serialPort)
    10980 {
    10981     LogFlowThisFunc(("\n"));
    10982 
    10983     AutoCaller autoCaller(this);
    10984     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    10985 
    10986     ComPtr<IInternalSessionControl> directControl;
    10987     {
    10988         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    10989         directControl = mData->mSession.mDirectControl;
    10990     }
    10991 
    10992     /* ignore notifications sent after #OnSessionEnd() is called */
    10993     if (!directControl)
    10994         return S_OK;
    10995 
    10996     return directControl->OnSerialPortChange(serialPort);
    10997 }
    10998 
    10999 /**
    11000  *  @note Locks this object for reading.
    11001  */
    11002 HRESULT SessionMachine::onParallelPortChange(IParallelPort *parallelPort)
    11003 {
    11004     LogFlowThisFunc(("\n"));
    11005 
    11006     AutoCaller autoCaller(this);
    11007     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    11008 
    11009     ComPtr<IInternalSessionControl> directControl;
    11010     {
    11011         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    11012         directControl = mData->mSession.mDirectControl;
    11013     }
    11014 
    11015     /* ignore notifications sent after #OnSessionEnd() is called */
    11016     if (!directControl)
    11017         return S_OK;
    11018 
    11019     return directControl->OnParallelPortChange(parallelPort);
    11020 }
    11021 
    11022 /**
    11023  *  @note Locks this object for reading.
    11024  */
    11025 HRESULT SessionMachine::onStorageControllerChange()
    11026 {
    11027     LogFlowThisFunc(("\n"));
    11028 
    11029     AutoCaller autoCaller(this);
    11030     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    11031 
    11032     ComPtr<IInternalSessionControl> directControl;
    11033     {
    11034         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    11035         directControl = mData->mSession.mDirectControl;
    11036     }
    11037 
    11038     /* ignore notifications sent after #OnSessionEnd() is called */
    11039     if (!directControl)
    11040         return S_OK;
    11041 
    11042     return directControl->OnStorageControllerChange();
    11043 }
    11044 
    11045 /**
    11046  *  @note Locks this object for reading.
    11047  */
    11048 HRESULT SessionMachine::onMediumChange(IMediumAttachment *aAttachment, BOOL aForce)
    11049 {
    11050     LogFlowThisFunc(("\n"));
    11051 
    11052     AutoCaller autoCaller(this);
    11053     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    11054 
    11055     ComPtr<IInternalSessionControl> directControl;
    11056     {
    11057         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    11058         directControl = mData->mSession.mDirectControl;
    11059     }
    11060 
    11061     /* ignore notifications sent after #OnSessionEnd() is called */
    11062     if (!directControl)
    11063         return S_OK;
    11064 
    11065     return directControl->OnMediumChange(aAttachment, aForce);
    11066 }
    11067 
    11068 /**
    11069  *  @note Locks this object for reading.
    11070  */
    11071 HRESULT SessionMachine::onCPUChange(ULONG aCPU, BOOL aRemove)
    11072 {
    11073     LogFlowThisFunc(("\n"));
    11074 
    11075     AutoCaller autoCaller(this);
    11076     AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
    11077 
    11078     ComPtr<IInternalSessionControl> directControl;
    11079     {
    11080         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    11081         directControl = mData->mSession.mDirectControl;
    11082     }
    11083 
    11084     /* ignore notifications sent after #OnSessionEnd() is called */
    11085     if (!directControl)
    11086         return S_OK;
    11087 
    11088     return directControl->OnCPUChange(aCPU, aRemove);
    11089 }
    11090 
    11091 HRESULT SessionMachine::onCPUPriorityChange(ULONG aCpuPriority)
    11092 {
    11093     LogFlowThisFunc(("\n"));
    11094 
    11095     AutoCaller autoCaller(this);
    11096     AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
    11097 
    11098     ComPtr<IInternalSessionControl> directControl;
    11099     {
    11100         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    11101         directControl = mData->mSession.mDirectControl;
    11102     }
    11103 
    11104     /* ignore notifications sent after #OnSessionEnd() is called */
    11105     if (!directControl)
    11106         return S_OK;
    11107 
    11108     return directControl->OnCPUPriorityChange(aCpuPriority);
    11109 }
    11110 
    11111 /**
    11112  *  @note Locks this object for reading.
    11113  */
    11114 HRESULT SessionMachine::onVRDPServerChange(BOOL aRestart)
    11115 {
    11116     LogFlowThisFunc(("\n"));
    11117 
    11118     AutoCaller autoCaller(this);
    11119     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    11120 
    11121     ComPtr<IInternalSessionControl> directControl;
    11122     {
    11123         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    11124         directControl = mData->mSession.mDirectControl;
    11125     }
    11126 
    11127     /* ignore notifications sent after #OnSessionEnd() is called */
    11128     if (!directControl)
    11129         return S_OK;
    11130 
    11131     return directControl->OnVRDPServerChange(aRestart);
    11132 }
    11133 
    11134 /**
    11135  *  @note Locks this object for reading.
    11136  */
    11137 HRESULT SessionMachine::onUSBControllerChange()
    11138 {
    11139     LogFlowThisFunc(("\n"));
    11140 
    11141     AutoCaller autoCaller(this);
    11142     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    11143 
    11144     ComPtr<IInternalSessionControl> directControl;
    11145     {
    11146         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    11147         directControl = mData->mSession.mDirectControl;
    11148     }
    11149 
    11150     /* ignore notifications sent after #OnSessionEnd() is called */
    11151     if (!directControl)
    11152         return S_OK;
    11153 
    11154     return directControl->OnUSBControllerChange();
    11155 }
    11156 
    11157 /**
    11158  *  @note Locks this object for reading.
    11159  */
    11160 HRESULT SessionMachine::onSharedFolderChange()
    11161 {
    11162     LogFlowThisFunc(("\n"));
    11163 
    11164     AutoCaller autoCaller(this);
    11165     AssertComRCReturnRC(autoCaller.rc());
    11166 
    11167     ComPtr<IInternalSessionControl> directControl;
    11168     {
    11169         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    11170         directControl = mData->mSession.mDirectControl;
    11171     }
    11172 
    11173     /* ignore notifications sent after #OnSessionEnd() is called */
    11174     if (!directControl)
    11175         return S_OK;
    11176 
    11177     return directControl->OnSharedFolderChange(FALSE /* aGlobal */);
    11178 }
    11179 
    11180 /**
    11181  *  Returns @c true if this machine's USB controller reports it has a matching
    11182  *  filter for the given USB device and @c false otherwise.
    11183  *
    11184  *  @note Caller must have requested machine read lock.
    11185  */
    11186 bool SessionMachine::hasMatchingUSBFilter(const ComObjPtr<HostUSBDevice> &aDevice, ULONG *aMaskedIfs)
    11187 {
    11188     AutoCaller autoCaller(this);
    11189     /* silently return if not ready -- this method may be called after the
    11190      * direct machine session has been called */
    11191     if (!autoCaller.isOk())
    11192         return false;
    11193 
    11194 
    11195 #ifdef VBOX_WITH_USB
    11196     switch (mData->mMachineState)
    11197     {
    11198         case MachineState_Starting:
    11199         case MachineState_Restoring:
    11200         case MachineState_TeleportingIn:
    11201         case MachineState_Paused:
    11202         case MachineState_Running:
    11203         /** @todo Live Migration: snapshoting & teleporting. Need to fend things of
    11204          *        elsewhere... */
    11205             return mUSBController->hasMatchingFilter(aDevice, aMaskedIfs);
    11206         default: break;
    11207     }
    11208 #else
    11209     NOREF(aDevice);
    11210     NOREF(aMaskedIfs);
    11211 #endif
    11212     return false;
    11213 }
    11214 
    11215 /**
    11216  *  @note The calls shall hold no locks. Will temporarily lock this object for reading.
    11217  */
    11218 HRESULT SessionMachine::onUSBDeviceAttach(IUSBDevice *aDevice,
    11219                                           IVirtualBoxErrorInfo *aError,
    11220                                           ULONG aMaskedIfs)
    11221 {
    11222     LogFlowThisFunc(("\n"));
    11223 
    11224     AutoCaller autoCaller(this);
    11225 
    11226     /* This notification may happen after the machine object has been
    11227      * uninitialized (the session was closed), so don't assert. */
    11228     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    11229 
    11230     ComPtr<IInternalSessionControl> directControl;
    11231     {
    11232         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    11233         directControl = mData->mSession.mDirectControl;
    11234     }
    11235 
    11236     /* fail on notifications sent after #OnSessionEnd() is called, it is
    11237      * expected by the caller */
    11238     if (!directControl)
    11239         return E_FAIL;
    11240 
    11241     /* No locks should be held at this point. */
    11242     AssertMsg(RTLockValidatorWriteLockGetCount(RTThreadSelf()) == 0, ("%d\n", RTLockValidatorWriteLockGetCount(RTThreadSelf())));
    11243     AssertMsg(RTLockValidatorReadLockGetCount(RTThreadSelf()) == 0, ("%d\n", RTLockValidatorReadLockGetCount(RTThreadSelf())));
    11244 
    11245     return directControl->OnUSBDeviceAttach(aDevice, aError, aMaskedIfs);
    11246 }
    11247 
    11248 /**
    11249  *  @note The calls shall hold no locks. Will temporarily lock this object for reading.
    11250  */
    11251 HRESULT SessionMachine::onUSBDeviceDetach(IN_BSTR aId,
    11252                                           IVirtualBoxErrorInfo *aError)
    11253 {
    11254     LogFlowThisFunc(("\n"));
    11255 
    11256     AutoCaller autoCaller(this);
    11257 
    11258     /* This notification may happen after the machine object has been
    11259      * uninitialized (the session was closed), so don't assert. */
    11260     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    11261 
    11262     ComPtr<IInternalSessionControl> directControl;
    11263     {
    11264         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    11265         directControl = mData->mSession.mDirectControl;
    11266     }
    11267 
    11268     /* fail on notifications sent after #OnSessionEnd() is called, it is
    11269      * expected by the caller */
    11270     if (!directControl)
    11271         return E_FAIL;
    11272 
    11273     /* No locks should be held at this point. */
    11274     AssertMsg(RTLockValidatorWriteLockGetCount(RTThreadSelf()) == 0, ("%d\n", RTLockValidatorWriteLockGetCount(RTThreadSelf())));
    11275     AssertMsg(RTLockValidatorReadLockGetCount(RTThreadSelf()) == 0, ("%d\n", RTLockValidatorReadLockGetCount(RTThreadSelf())));
    11276 
    11277     return directControl->OnUSBDeviceDetach(aId, aError);
    11278 }
    11279 
    11280 // protected methods
    11281 /////////////////////////////////////////////////////////////////////////////
    11282 
    11283 /**
    11284  *  Helper method to finalize saving the state.
    11285  *
    11286  *  @note Must be called from under this object's lock.
    11287  *
    11288  *  @param aSuccess TRUE if the snapshot has been taken successfully
    11289  *
    11290  *  @note Locks mParent + this objects for writing.
    11291  */
    11292 HRESULT SessionMachine::endSavingState(BOOL aSuccess)
    11293 {
    11294     LogFlowThisFuncEnter();
    11295 
    11296     AutoCaller autoCaller(this);
    11297     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    11298 
    11299     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    11300 
    11301     HRESULT rc = S_OK;
    11302 
    11303     if (aSuccess)
    11304     {
    11305         mSSData->mStateFilePath = mSnapshotData.mStateFilePath;
    11306 
    11307         /* save all VM settings */
    11308         rc = saveSettings(NULL);
    11309                 // no need to check whether VirtualBox.xml needs saving also since
    11310                 // we can't have a name change pending at this point
    11311     }
    11312     else
    11313     {
    11314         /* delete the saved state file (it might have been already created) */
    11315         RTFileDelete(mSnapshotData.mStateFilePath.c_str());
    11316     }
    11317 
    11318     /* remove the completed progress object */
    11319     mParent->removeProgress(mSnapshotData.mProgressId);
    11320 
    11321     /* clear out the temporary saved state data */
    11322     mSnapshotData.mLastState = MachineState_Null;
    11323     mSnapshotData.mProgressId.clear();
    11324     mSnapshotData.mStateFilePath.setNull();
    11325 
    11326     LogFlowThisFuncLeave();
    11327     return rc;
    11328 }
    11329 
    11330 /**
    11331  * Locks the attached media.
    11332  *
    11333  * All attached hard disks are locked for writing and DVD/floppy are locked for
    11334  * reading. Parents of attached hard disks (if any) are locked for reading.
    11335  *
    11336  * This method also performs accessibility check of all media it locks: if some
    11337  * media is inaccessible, the method will return a failure and a bunch of
    11338  * extended error info objects per each inaccessible medium.
    11339  *
    11340  * Note that this method is atomic: if it returns a success, all media are
    11341  * locked as described above; on failure no media is locked at all (all
    11342  * succeeded individual locks will be undone).
    11343  *
    11344  * This method is intended to be called when the machine is in Starting or
    11345  * Restoring state and asserts otherwise.
    11346  *
    11347  * The locks made by this method must be undone by calling #unlockMedia() when
    11348  * no more needed.
    11349  */
    11350 HRESULT SessionMachine::lockMedia()
    11351 {
    11352     AutoCaller autoCaller(this);
    11353     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    11354 
    11355     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    11356 
    11357     AssertReturn(   mData->mMachineState == MachineState_Starting
    11358                  || mData->mMachineState == MachineState_Restoring
    11359                  || mData->mMachineState == MachineState_TeleportingIn, E_FAIL);
    11360     /* bail out if trying to lock things with already set up locking */
    11361     AssertReturn(mData->mSession.mLockedMedia.IsEmpty(), E_FAIL);
    11362 
    11363     MultiResult mrc(S_OK);
    11364 
    11365     /* Collect locking information for all medium objects attached to the VM. */
    11366     for (MediaData::AttachmentList::const_iterator it = mMediaData->mAttachments.begin();
    11367          it != mMediaData->mAttachments.end();
    11368          ++it)
    11369     {
    11370         MediumAttachment* pAtt = *it;
    11371         DeviceType_T devType = pAtt->getType();
    11372         Medium *pMedium = pAtt->getMedium();
    11373 
    11374         MediumLockList *pMediumLockList(new MediumLockList());
    11375         // There can be attachments without a medium (floppy/dvd), and thus
    11376         // it's impossible to create a medium lock list. It still makes sense
    11377         // to have the empty medium lock list in the map in case a medium is
    11378         // attached later.
    11379         if (pMedium != NULL)
    11380         {
    11381             MediumType_T mediumType = pMedium->getType();
    11382             bool fIsReadOnlyImage =    devType == DeviceType_DVD
    11383                                     || mediumType == MediumType_Shareable;
    11384             bool fIsVitalImage = (devType == DeviceType_HardDisk);
    11385 
    11386             mrc = pMedium->createMediumLockList(fIsVitalImage /* fFailIfInaccessible */,
    11387                                                 !fIsReadOnlyImage /* fMediumLockWrite */,
    11388                                                 NULL,
    11389                                                 *pMediumLockList);
    11390             if (FAILED(mrc))
    11391             {
    11392                 delete pMediumLockList;
    11393                 mData->mSession.mLockedMedia.Clear();
    11394                 break;
    11395             }
    11396         }
    11397 
    11398         HRESULT rc = mData->mSession.mLockedMedia.Insert(pAtt, pMediumLockList);
    11399         if (FAILED(rc))
    11400         {
    11401             mData->mSession.mLockedMedia.Clear();
    11402             mrc = setError(rc,
    11403                            tr("Collecting locking information for all attached media failed"));
    11404             break;
    11405         }
    11406     }
    11407 
    11408     if (SUCCEEDED(mrc))
    11409     {
    11410         /* Now lock all media. If this fails, nothing is locked. */
    11411         HRESULT rc = mData->mSession.mLockedMedia.Lock();
    11412         if (FAILED(rc))
    11413         {
    11414             mrc = setError(rc,
    11415                            tr("Locking of attached media failed"));
    11416         }
    11417     }
    11418 
    11419     return mrc;
    11420 }
    11421 
    11422 /**
    11423  * Undoes the locks made by by #lockMedia().
    11424  */
    11425 void SessionMachine::unlockMedia()
    11426 {
    11427     AutoCaller autoCaller(this);
    11428     AssertComRCReturnVoid(autoCaller.rc());
    11429 
    11430     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    11431 
    11432     /* we may be holding important error info on the current thread;
    11433      * preserve it */
    11434     ErrorInfoKeeper eik;
    11435 
    11436     HRESULT rc = mData->mSession.mLockedMedia.Clear();
    11437     AssertComRC(rc);
    11438 }
    11439 
    11440 /**
    11441  * Helper to change the machine state (reimplementation).
    11442  *
    11443  * @note Locks this object for writing.
    11444  */
    11445 HRESULT SessionMachine::setMachineState(MachineState_T aMachineState)
    11446 {
    11447     LogFlowThisFuncEnter();
    11448     LogFlowThisFunc(("aMachineState=%s\n", Global::stringifyMachineState(aMachineState) ));
    11449 
    11450     AutoCaller autoCaller(this);
    11451     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    11452 
    11453     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    11454 
    11455     MachineState_T oldMachineState = mData->mMachineState;
    11456 
    11457     AssertMsgReturn(oldMachineState != aMachineState,
    11458                     ("oldMachineState=%s, aMachineState=%s\n",
    11459                      Global::stringifyMachineState(oldMachineState), Global::stringifyMachineState(aMachineState)),
    11460                     E_FAIL);
    11461 
    11462     HRESULT rc = S_OK;
    11463 
    11464     int stsFlags = 0;
    11465     bool deleteSavedState = false;
    11466 
    11467     /* detect some state transitions */
    11468 
    11469     if (   (   oldMachineState == MachineState_Saved
    11470             && aMachineState   == MachineState_Restoring)
    11471         || (   (   oldMachineState == MachineState_PoweredOff
    11472                 || oldMachineState == MachineState_Teleported
    11473                 || oldMachineState == MachineState_Aborted
    11474                )
    11475             && (   aMachineState   == MachineState_TeleportingIn
    11476                 || aMachineState   == MachineState_Starting
    11477                )
    11478            )
    11479        )
    11480     {
    11481         /* The EMT thread is about to start */
    11482 
    11483         /* Nothing to do here for now... */
    11484 
    11485         /// @todo NEWMEDIA don't let mDVDDrive and other children
    11486         /// change anything when in the Starting/Restoring state
    11487     }
    11488     else if (   (   oldMachineState == MachineState_Running
    11489                  || oldMachineState == MachineState_Paused
    11490                  || oldMachineState == MachineState_Teleporting
    11491                  || oldMachineState == MachineState_LiveSnapshotting
    11492                  || oldMachineState == MachineState_Stuck
    11493                  || oldMachineState == MachineState_Starting
    11494                  || oldMachineState == MachineState_Stopping
    11495                  || oldMachineState == MachineState_Saving
    11496                  || oldMachineState == MachineState_Restoring
    11497                  || oldMachineState == MachineState_TeleportingPausedVM
    11498                  || oldMachineState == MachineState_TeleportingIn
    11499                  )
    11500              && (   aMachineState == MachineState_PoweredOff
    11501                  || aMachineState == MachineState_Saved
    11502                  || aMachineState == MachineState_Teleported
    11503                  || aMachineState == MachineState_Aborted
    11504                 )
    11505              /* ignore PoweredOff->Saving->PoweredOff transition when taking a
    11506               * snapshot */
    11507              && (   mSnapshotData.mSnapshot.isNull()
    11508                  || mSnapshotData.mLastState >= MachineState_Running /** @todo Live Migration: clean up (lazy bird) */
    11509                 )
    11510             )
    11511     {
    11512         /* The EMT thread has just stopped, unlock attached media. Note that as
    11513          * opposed to locking that is done from Console, we do unlocking here
    11514          * because the VM process may have aborted before having a chance to
    11515          * properly unlock all media it locked. */
    11516 
    11517         unlockMedia();
    11518     }
    11519 
    11520     if (oldMachineState == MachineState_Restoring)
    11521     {
    11522         if (aMachineState != MachineState_Saved)
    11523         {
    11524             /*
    11525              *  delete the saved state file once the machine has finished
    11526              *  restoring from it (note that Console sets the state from
    11527              *  Restoring to Saved if the VM couldn't restore successfully,
    11528              *  to give the user an ability to fix an error and retry --
    11529              *  we keep the saved state file in this case)
    11530              */
    11531             deleteSavedState = true;
    11532         }
    11533     }
    11534     else if (   oldMachineState == MachineState_Saved
    11535              && (   aMachineState == MachineState_PoweredOff
    11536                  || aMachineState == MachineState_Aborted
    11537                  || aMachineState == MachineState_Teleported
    11538                 )
    11539             )
    11540     {
    11541         /*
    11542          *  delete the saved state after Console::ForgetSavedState() is called
    11543          *  or if the VM process (owning a direct VM session) crashed while the
    11544          *  VM was Saved
    11545          */
    11546 
    11547         /// @todo (dmik)
    11548         //      Not sure that deleting the saved state file just because of the
    11549         //      client death before it attempted to restore the VM is a good
    11550         //      thing. But when it crashes we need to go to the Aborted state
    11551         //      which cannot have the saved state file associated... The only
    11552         //      way to fix this is to make the Aborted condition not a VM state
    11553         //      but a bool flag: i.e., when a crash occurs, set it to true and
    11554         //      change the state to PoweredOff or Saved depending on the
    11555         //      saved state presence.
    11556 
    11557         deleteSavedState = true;
    11558         mData->mCurrentStateModified = TRUE;
    11559         stsFlags |= SaveSTS_CurStateModified;
    11560     }
    11561 
    11562     if (   aMachineState == MachineState_Starting
    11563         || aMachineState == MachineState_Restoring
    11564         || aMachineState == MachineState_TeleportingIn
    11565        )
    11566     {
    11567         /* set the current state modified flag to indicate that the current
    11568          * state is no more identical to the state in the
    11569          * current snapshot */
    11570         if (!mData->mCurrentSnapshot.isNull())
    11571         {
    11572             mData->mCurrentStateModified = TRUE;
    11573             stsFlags |= SaveSTS_CurStateModified;
    11574         }
    11575     }
    11576 
    11577     if (deleteSavedState)
    11578     {
    11579         if (mRemoveSavedState)
    11580         {
    11581             Assert(!mSSData->mStateFilePath.isEmpty());
    11582             RTFileDelete(mSSData->mStateFilePath.c_str());
    11583         }
    11584         mSSData->mStateFilePath.setNull();
    11585         stsFlags |= SaveSTS_StateFilePath;
    11586     }
    11587 
    11588     /* redirect to the underlying peer machine */
    11589     mPeer->setMachineState(aMachineState);
    11590 
    11591     if (   aMachineState == MachineState_PoweredOff
    11592         || aMachineState == MachineState_Teleported
    11593         || aMachineState == MachineState_Aborted
    11594         || aMachineState == MachineState_Saved)
    11595     {
    11596         /* the machine has stopped execution
    11597          * (or the saved state file was adopted) */
    11598         stsFlags |= SaveSTS_StateTimeStamp;
    11599     }
    11600 
    11601     if (   (   oldMachineState == MachineState_PoweredOff
    11602             || oldMachineState == MachineState_Aborted
    11603             || oldMachineState == MachineState_Teleported
    11604            )
    11605         && aMachineState == MachineState_Saved)
    11606     {
    11607         /* the saved state file was adopted */
    11608         Assert(!mSSData->mStateFilePath.isEmpty());
    11609         stsFlags |= SaveSTS_StateFilePath;
    11610     }
    11611 
    11612     if (   aMachineState == MachineState_PoweredOff
    11613         || aMachineState == MachineState_Aborted
    11614         || aMachineState == MachineState_Teleported)
    11615     {
    11616         /* Make sure any transient guest properties get removed from the
    11617          * property store on shutdown. */
    11618 
    11619         HWData::GuestPropertyList::iterator it;
    11620         BOOL fNeedsSaving = mData->mGuestPropertiesModified;
    11621         if (!fNeedsSaving)
    11622             for (it = mHWData->mGuestProperties.begin();
    11623                  it != mHWData->mGuestProperties.end(); ++it)
    11624                 if (it->mFlags & guestProp::TRANSIENT)
    11625                 {
    11626                     fNeedsSaving = true;
    11627                     break;
    11628                 }
    11629         if (fNeedsSaving)
    11630         {
    11631             mData->mCurrentStateModified = TRUE;
    11632             stsFlags |= SaveSTS_CurStateModified;
    11633             SaveSettings();     // @todo r=dj why the public method? why first SaveSettings and then saveStateSettings?
    11634         }
    11635     }
    11636 
    11637     rc = saveStateSettings(stsFlags);
    11638 
    11639     if (   (   oldMachineState != MachineState_PoweredOff
    11640             && oldMachineState != MachineState_Aborted
    11641             && oldMachineState != MachineState_Teleported
    11642            )
    11643         && (   aMachineState == MachineState_PoweredOff
    11644             || aMachineState == MachineState_Aborted
    11645             || aMachineState == MachineState_Teleported
    11646            )
    11647        )
    11648     {
    11649         /* we've been shut down for any reason */
    11650         /* no special action so far */
    11651     }
    11652 
    11653     LogFlowThisFunc(("rc=%Rhrc [%s]\n", rc, Global::stringifyMachineState(mData->mMachineState) ));
    11654     LogFlowThisFuncLeave();
    11655     return rc;
    11656 }
    11657 
    11658 /**
    11659  *  Sends the current machine state value to the VM process.
    11660  *
    11661  *  @note Locks this object for reading, then calls a client process.
    11662  */
    11663 HRESULT SessionMachine::updateMachineStateOnClient()
    11664 {
    11665     AutoCaller autoCaller(this);
    11666     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
    11667 
    11668     ComPtr<IInternalSessionControl> directControl;
    11669     {
    11670         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    11671         AssertReturn(!!mData, E_FAIL);
    11672         directControl = mData->mSession.mDirectControl;
    11673 
    11674         /* directControl may be already set to NULL here in #OnSessionEnd()
    11675          * called too early by the direct session process while there is still
    11676          * some operation (like deleting the snapshot) in progress. The client
    11677          * process in this case is waiting inside Session::close() for the
    11678          * "end session" process object to complete, while #uninit() called by
    11679          * #checkForDeath() on the Watcher thread is waiting for the pending
    11680          * operation to complete. For now, we accept this inconsitent behavior
    11681          * and simply do nothing here. */
    11682 
    11683         if (mData->mSession.mState == SessionState_Unlocking)
    11684             return S_OK;
    11685 
    11686         AssertReturn(!directControl.isNull(), E_FAIL);
    11687     }
    11688 
    11689     return directControl->UpdateMachineState(mData->mMachineState);
    11690 }
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette