third_party/virtualbox/src/VBox/Main/src-server/MachineImpl.cpp
/**
 * Saves and commits machine data, user data and hardware data.
 *
 * Note that on failure, the data remains uncommitted.
 *
 * @a aFlags may combine the following flags:
 *
 *  - SaveS_ResetCurStateModified: Resets mData->mCurrentStateModified to FALSE.
 *    Used when saving settings after an operation that makes them 100%
 *    correspond to the settings from the current snapshot.
 *  - SaveS_Force: settings will be saved without doing a deep compare of the
 *    settings structures. This is used when this is called because snapshots
 *    have changed to avoid the overhead of the deep compare.
 *
 * @note Must be called from under this object's write lock. Locks children for
 * writing.
 *
 * @param pfNeedsGlobalSaveSettings Optional pointer to a bool that must have been
 *          initialized to false and that will be set to true by this function if
 *          the caller must invoke VirtualBox::i_saveSettings() because the global
 *          settings have changed. This will happen if a machine rename has been
 *          saved and the global machine and media registries will therefore need
 *          updating.
 * @param   aFlags  Flags.
 */
Saves and commits machine data, user data and hardware data.
Note that on failure, the data remains uncommitted.

@a aFlags may combine the following flags.



@note Must be called from under this object's write lock. Locks children for
writing.

@param pfNeedsGlobalSaveSettings Optional pointer to a bool that must have been
initialized to false and that will be set to true by this function if
the caller must invoke VirtualBox::i_saveSettings() because the global
settings have changed. This will happen if a machine rename has been
saved and the global machine and media registries will therefore need
updating.
@param   aFlags  Flags.
Saves and commits machine data user data and hardware data . Note that on failure the data remains uncommitted . @a aFlags may combine the following flags . @note Must be called from under this object ' s write lock . Locks children for writing . @param pfNeedsGlobalSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true by this function if the caller must invoke VirtualBox :: i_saveSettings () because the global settings have changed . This will happen if a machine rename has been saved and the global machine and media registries will therefore need updating . @param aFlags Flags .
HRESULT Machine::i_saveSettings(bool *pfNeedsGlobalSaveSettings,
                                int  aFlags )
{
    LogFlowThisFuncEnter();
    AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
    i_ensureNoStateDependencies();
    AssertReturn(!i_isSnapshotMachine(),
                 E_FAIL);
    if (!mData->mAccessible)
        return setError(VBOX_E_INVALID_VM_STATE,
                        tr("The machine is not accessible, so cannot save settings"));
    HRESULT rc = S_OK;
    bool fNeedsWrite = false;
    rc = i_prepareSaveSettings(pfNeedsGlobalSaveSettings);
    if (FAILED(rc)) return rc;
    settings::MachineConfigFile *pOldConfig = mData->pMachineConfigFile;
    settings::MachineConfigFile *pNewConfig = NULL;
    try
    {
        pNewConfig = new settings::MachineConfigFile(NULL);
        pNewConfig->copyBaseFrom(*mData->pMachineConfigFile);
        i_copyMachineDataToSettings(*pNewConfig);
        if (aFlags & SaveS_ResetCurStateModified)
        {
            mData->mCurrentStateModified = FALSE;
            fNeedsWrite = true;     
        }
        else if (aFlags & SaveS_Force)
        {
            fNeedsWrite = true;     
        }
        else
        {
            if (!mData->mCurrentStateModified)
            {
                bool fAnySettingsChanged = !(*pNewConfig == *pOldConfig);
                mData->mCurrentStateModified = fAnySettingsChanged;
                fNeedsWrite = fAnySettingsChanged;
            }
            else
                fNeedsWrite = true;
        }
        pNewConfig->fCurrentStateModified = !!mData->mCurrentStateModified;
        if (fNeedsWrite)
            pNewConfig->write(mData->m_strConfigFileFull);
        mData->pMachineConfigFile = pNewConfig;
        delete pOldConfig;
        i_commit();
        mData->flModifications = 0;
    }
    catch (HRESULT err)
    {
        rc = err;
        delete pNewConfig;
        mData->pMachineConfigFile = pOldConfig;
    }
    catch (...)
    {
        rc = VirtualBoxBase::handleUnexpectedExceptions(this, RT_SRC_POS);
    }
    if (fNeedsWrite)
    {
        if (i_isSessionMachine())
            mParent->i_onMachineDataChange(mData->mUuid);
    }
    LogFlowThisFunc(("rc=%08X\n", rc));
    LogFlowThisFuncLeave();
    return rc;
}
HRESULT Machine :: i_saveSettings ( bool * pfNeedsGlobalSaveSettings , int aFlags ) { LogFlowThisFuncEnter ( ) ; AssertReturn ( isWriteLockOnCurrentThread ( ) , E_FAIL ) ; i_ensureNoStateDependencies ( ) ; AssertReturn ( ! i_isSnapshotMachine ( ) , E_FAIL ) ; if ( ! mData -> mAccessible ) return setError ( VBOX_E_INVALID_VM_STATE , tr ( " " ) ) ; HRESULT rc = S_OK ; bool fNeedsWrite = false ; rc = i_prepareSaveSettings ( pfNeedsGlobalSaveSettings ) ; if ( FAILED ( rc ) ) return rc ; settings :: MachineConfigFile * pOldConfig = mData -> pMachineConfigFile ; settings :: MachineConfigFile * pNewConfig = NULL ; try { pNewConfig = new settings :: MachineConfigFile ( NULL ) ; pNewConfig -> copyBaseFrom ( * mData -> pMachineConfigFile ) ; i_copyMachineDataToSettings ( * pNewConfig ) ; if ( aFlags & SaveS_ResetCurStateModified ) { mData -> mCurrentStateModified = FALSE ; fNeedsWrite = true ; } else if ( aFlags & SaveS_Force ) { fNeedsWrite = true ; } else { if ( ! mData -> mCurrentStateModified ) { bool fAnySettingsChanged = ! ( * pNewConfig == * pOldConfig ) ; mData -> mCurrentStateModified = fAnySettingsChanged ; fNeedsWrite = fAnySettingsChanged ; } else fNeedsWrite = true ; } pNewConfig -> fCurrentStateModified = ! ! mData -> mCurrentStateModified ; if ( fNeedsWrite ) pNewConfig -> write ( mData -> m_strConfigFileFull ) ; mData -> pMachineConfigFile = pNewConfig ; delete pOldConfig ; i_commit ( ) ; mData -> flModifications = 0 ; } catch ( HRESULT err ) { rc = err ; delete pNewConfig ; mData -> pMachineConfigFile = pOldConfig ; } catch ( ... ) { rc = VirtualBoxBase :: handleUnexpectedExceptions ( this , RT_SRC_POS ) ; } if ( fNeedsWrite ) { if ( i_isSessionMachine ( ) ) mParent -> i_onMachineDataChange ( mData -> mUuid ) ; } LogFlowThisFunc ( ( " \n " , rc ) ) ; LogFlowThisFuncLeave ( ) ; return rc ; }
Saves and commits machine data, user data and hardware data.
Saves and commits machine data user data and hardware data .
/*= 0*/ /* make sure child objects are unable to modify the settings while we are
     * saving them */ /* First, prepare to save settings. It will care about renaming the
     * settings directory and file if the machine name was changed and about
     * creating a new settings file if this is a new machine. */ // keep a pointer to the current settings structures // make a fresh one to have everyone write stuff into // now go and copy all the settings data from COM to the settings structures // (this calls i_saveSettings() on all the COM objects in the machine) // this gets set by takeSnapshot() (if offline snapshot) and restoreSnapshot() // always, no need to compare // always, no need to compare // do a deep compare of the settings that we just saved with the settings // previously stored in the config file; this invokes MachineConfigFile::operator== // which does a deep compare of all the settings, which is expensive but less expensive // than writing out XML in vain // could still be modified if any settings changed // now spit it all out! // after saving settings, we are no longer different from the XML on disk // we assume that error info is set by the thrower // restore old config /* Fire the data change event, even on failure (since we've already
         * committed all data). This is done only for SessionMachines because
         * mutable Machine instances are always not registered (i.e. private
         * to the client process that creates them) and thus don't need to
         * inform callbacks. */