third_party/virtualbox/src/VBox/Main/src-server/MachineImpl.cpp
/**
 * Goes thru all media of the given list and
 *
 * 1) calls i_detachDevice() on each of them for this machine and
 * 2) adds all Medium objects found in the process to the given list,
 *    depending on cleanupMode.
 *
 * If cleanupMode is CleanupMode_DetachAllReturnHardDisksOnly, this only
 * adds hard disks to the list. If it is CleanupMode_Full, this adds all
 * media to the list.
 *
 * This gets called from Machine::Unregister, both for the actual Machine and
 * the SnapshotMachine objects that might be found in the snapshots.
 *
 * Requires caller and locking. The machine lock must be passed in because it
 * will be passed on to i_detachDevice which needs it for temporary unlocking.
 *
 * @param writeLock Machine lock from top-level caller; this gets passed to
 *                  i_detachDevice.
 * @param pSnapshot Must be NULL when called for a "real" Machine or a snapshot
 *                  object if called for a SnapshotMachine.
 * @param cleanupMode If DetachAllReturnHardDisksOnly, only hard disk media get
 *                  added to llMedia; if Full, then all media get added;
 *                  otherwise no media get added.
 * @param llMedia   Caller's list to receive Medium objects which got detached so
 *                  caller can close() them, depending on cleanupMode.
 * @return
 */
Goes thru all media of the given list and
1) calls i_detachDevice() on each of them for this machine and
2) adds all Medium objects found in the process to the given list,
depending on cleanupMode.

If cleanupMode is CleanupMode_DetachAllReturnHardDisksOnly, this only
adds hard disks to the list. If it is CleanupMode_Full, this adds all
media to the list.

This gets called from Machine::Unregister, both for the actual Machine and
the SnapshotMachine objects that might be found in the snapshots.

Requires caller and locking. The machine lock must be passed in because it
will be passed on to i_detachDevice which needs it for temporary unlocking.

@param writeLock Machine lock from top-level caller; this gets passed to
i_detachDevice.
@param pSnapshot Must be NULL when called for a "real" Machine or a snapshot
object if called for a SnapshotMachine.
@param cleanupMode If DetachAllReturnHardDisksOnly, only hard disk media get
added to llMedia; if Full, then all media get added;
otherwise no media get added.
@param llMedia   Caller's list to receive Medium objects which got detached so
caller can close() them, depending on cleanupMode.
@return
Goes thru all media of the given list and 1 ) calls i_detachDevice () on each of them for this machine and 2 ) adds all Medium objects found in the process to the given list depending on cleanupMode . If cleanupMode is CleanupMode_DetachAllReturnHardDisksOnly this only adds hard disks to the list . If it is CleanupMode_Full this adds all media to the list . This gets called from Machine :: Unregister both for the actual Machine and the SnapshotMachine objects that might be found in the snapshots . Requires caller and locking . The machine lock must be passed in because it will be passed on to i_detachDevice which needs it for temporary unlocking . @param writeLock Machine lock from top - level caller ; this gets passed to i_detachDevice . @param pSnapshot Must be NULL when called for a " real " Machine or a snapshot object if called for a SnapshotMachine . @param cleanupMode If DetachAllReturnHardDisksOnly only hard disk media get added to llMedia ; if Full then all media get added ; otherwise no media get added . @param llMedia Caller ' s list to receive Medium objects which got detached so caller can close () them depending on cleanupMode . @return
HRESULT Machine::i_detachAllMedia(AutoWriteLock &writeLock,
                                  Snapshot *pSnapshot,
                                  CleanupMode_T cleanupMode,
                                  MediaList &llMedia)
{
    Assert(isWriteLockOnCurrentThread());
    HRESULT rc;
    MediumAttachmentList llAttachments2 = *mMediumAttachments.data();
    for (MediumAttachmentList::iterator
         it = llAttachments2.begin();
         it != llAttachments2.end();
         ++it)
    {
        ComObjPtr<MediumAttachment> &pAttach = *it;
        ComObjPtr<Medium> pMedium = pAttach->i_getMedium();
        if (!pMedium.isNull())
        {
            AutoCaller mac(pMedium);
            if (FAILED(mac.rc())) return mac.rc();
            AutoReadLock lock(pMedium COMMA_LOCKVAL_SRC_POS);
            DeviceType_T devType = pMedium->i_getDeviceType();
            if (    (    cleanupMode == CleanupMode_DetachAllReturnHardDisksOnly
                      && devType == DeviceType_HardDisk)
                 || (cleanupMode == CleanupMode_Full)
               )
            {
                llMedia.push_back(pMedium);
                ComObjPtr<Medium> pParent = pMedium->i_getParent();
                lock.release();
                while (!pParent.isNull())
                {
                    AutoCaller mac1(pParent);
                    if (FAILED(mac1.rc())) return mac1.rc();
                    AutoReadLock lock1(pParent COMMA_LOCKVAL_SRC_POS);
                    if (pParent->i_getChildren().size() == 1)
                    {
                        if (   pParent->i_getMachineBackRefCount() == 0
                            && pParent->i_getType() == MediumType_Normal
                            && find(llMedia.begin(), llMedia.end(), pParent) == llMedia.end())
                            llMedia.push_back(pParent);
                    }
                    else
                        break;
                    pParent = pParent->i_getParent();
                }
            }
        }
        rc = i_detachDevice(pAttach, writeLock, pSnapshot);
        if (FAILED(rc))
            return rc;
    }
    return S_OK;
}
HRESULT Machine :: i_detachAllMedia ( AutoWriteLock & writeLock , Snapshot * pSnapshot , CleanupMode_T cleanupMode , MediaList & llMedia ) { Assert ( isWriteLockOnCurrentThread ( ) ) ; HRESULT rc ; MediumAttachmentList llAttachments2 = * mMediumAttachments . data ( ) ; for ( MediumAttachmentList :: iterator it = llAttachments2 . begin ( ) ; it != llAttachments2 . end ( ) ; ++ it ) { ComObjPtr < MediumAttachment > & pAttach = * it ; ComObjPtr < Medium > pMedium = pAttach -> i_getMedium ( ) ; if ( ! pMedium . isNull ( ) ) { AutoCaller mac ( pMedium ) ; if ( FAILED ( mac . rc ( ) ) ) return mac . rc ( ) ; AutoReadLock lock ( pMedium COMMA_LOCKVAL_SRC_POS ) ; DeviceType_T devType = pMedium -> i_getDeviceType ( ) ; if ( ( cleanupMode == CleanupMode_DetachAllReturnHardDisksOnly && devType == DeviceType_HardDisk ) || ( cleanupMode == CleanupMode_Full ) ) { llMedia . push_back ( pMedium ) ; ComObjPtr < Medium > pParent = pMedium -> i_getParent ( ) ; lock . release ( ) ; while ( ! pParent . isNull ( ) ) { AutoCaller mac1 ( pParent ) ; if ( FAILED ( mac1 . rc ( ) ) ) return mac1 . rc ( ) ; AutoReadLock lock1 ( pParent COMMA_LOCKVAL_SRC_POS ) ; if ( pParent -> i_getChildren ( ) . size ( ) == 1 ) { if ( pParent -> i_getMachineBackRefCount ( ) == 0 && pParent -> i_getType ( ) == MediumType_Normal && find ( llMedia . begin ( ) , llMedia . end ( ) , pParent ) == llMedia . end ( ) ) llMedia . push_back ( pParent ) ; } else break ; pParent = pParent -> i_getParent ( ) ; } } } rc = i_detachDevice ( pAttach , writeLock , pSnapshot ) ; if ( FAILED ( rc ) ) return rc ; } return S_OK ; }
Goes thru all media of the given list and
 1) calls i_detachDevice() on each of them for this machine and
 2) adds all Medium objects found in the process to the given list,
    depending on cleanupMode.
Goes thru all media of the given list and 1 ) calls i_detachDevice () on each of them for this machine and 2 ) adds all Medium objects found in the process to the given list depending on cleanupMode .
// make a temporary list because i_detachDevice invalidates iterators into // mMediumAttachments /* Not allowed to keep this lock as below we need the parent
                 * medium lock, and the lock order is parent to child. */ /*
                 * Search for medias which are not attached to any machine, but
                 * in the chain to an attached disk. Mediums are only consided
                 * if they are:
                 * - have only one child
                 * - no references to any machines
                 * - are of normal medium type
                 */ // real machine: then we need to use the proper method