MediumImpl.cpp revision d19316699d7f91959d88c850fd7e0d64840f39a7
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * VirtualBox COM class implementation
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Copyright (C) 2008-2010 Sun Microsystems, Inc.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * available from http://www.virtualbox.org. This file is free software;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * you can redistribute it and/or modify it under the terms of the GNU
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * General Public License (GPL) as published by the Free Software
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * additional information or have any questions.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync////////////////////////////////////////////////////////////////////////////////
e99772f9bf09219c532812c859fbeea513c67e65vboxsync// Medium data definition
e99772f9bf09219c532812c859fbeea513c67e65vboxsync////////////////////////////////////////////////////////////////////////////////
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/** Describes how a machine refers to this image. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** Equality predicate for stdc++. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync struct EqualsTo : public std::unary_function <BackRef, bool>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync explicit EqualsTo(const Guid &aMachineId) : machineId(aMachineId) {}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** weak VirtualBox parent */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync // pParent and llChildren are protected by VirtualBox::getMediaTreeLockHandle()
e99772f9bf09219c532812c859fbeea513c67e65vboxsync MediaList llChildren; // to add a child, just call push_back; to remove a child, call child->deparent() which does a lookup
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** the following members are invalid after changing UUID on open */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync Utf8Str vdError; /*< Error remembered by the VD error callback. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync////////////////////////////////////////////////////////////////////////////////
e99772f9bf09219c532812c859fbeea513c67e65vboxsync////////////////////////////////////////////////////////////////////////////////
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Asynchronous task thread parameter bucket.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Note that instances of this class must be created using new() because the
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * task thread function will delete them when the task is complete!
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @note The constructor of this class adds a caller on the managed Medium
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * object which is automatically released upon destruction.
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncstruct Medium::Task : public com::SupportErrorInfoBase
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** Where to save the result when executed using #runNow(). */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync // Whether the caller needs to call VirtualBox::saveSettings() after
e99772f9bf09219c532812c859fbeea513c67e65vboxsync // the task function returns. Only used in synchronous (wait) mode;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync // otherwise the task will save the settings itself.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync void setData(ImageChain *aSrcChain, ImageChain *aParentChain)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* CreateBase */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* CreateBase, CreateDiff, Clone */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* CreateDiff, Clone */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Clone */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** Media to open, in {parent,child} order */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** Media which are parent of target, in {parent,child} order */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** The to-be parent medium object */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Merge */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** Media to merge, in {parent,child} order */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Compact */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** Media to open, in {parent,child} order */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync // SupportErrorInfoBase interface
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const GUID &mainInterfaceID() const { return COM_IIDOF(IMedium); }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const char *componentName() const { return Medium::ComponentName(); }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* remove callers added by setData() */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Starts a new thread driven by the Medium::taskThread() function and passes
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * this Task instance as an argument.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Note that if this method returns success, this Task object becomes an ownee
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * of the started thread and will be automatically deleted when the thread
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * terminates.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @note When the task is executed by this method, IProgress::notifyComplete()
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * is automatically called for the progress object associated with this
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * task when the task is finished to signal the operation completion for
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * other threads asynchronously waiting for it.
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync int vrc = RTThreadCreate(NULL, Medium::taskThread, this,
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync "Medium::Task");
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync ("Could not create Medium::Task thread (%Rrc)\n", vrc),
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * Runs Medium::taskThread() by passing it this Task instance as an argument
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * on the current thread instead of creating a new one.
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * This call implies that it is made on another temporary thread created for
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * some asynchronous task. Avoid calling it from a normal thread since the task
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * operatinos are potentially lengthy and will block the calling thread in this
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * Note that this Task object will be deleted by taskThread() when this method
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * @note When the task is executed by this method, IProgress::notifyComplete()
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * is not called for the progress object associated with this task when
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * the task is finished. Instead, the result of the operation is returned
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * by this method directly and it's the caller's responsibility to
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * complete the progress object in this case.
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsyncHRESULT Medium::Task::runNow(bool *pfNeedsSaveSettings)
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync /* NIL_RTTHREAD indicates synchronous call. */
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync////////////////////////////////////////////////////////////////////////////////
e99772f9bf09219c532812c859fbeea513c67e65vboxsync// Merge chain class
e99772f9bf09219c532812c859fbeea513c67e65vboxsync////////////////////////////////////////////////////////////////////////////////
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Helper class for merge operations.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @note It is assumed that when modifying methods of this class are called,
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Medium::getTreeLock() is held in read mode.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync for (iterator it = mChildren.begin(); it != mChildren.end(); ++ it)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync Assert((*it)->m->state == MediumState_LockedWrite ||
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else if ((*it)->m->state == MediumState_LockedRead)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AutoWriteLock alock(aMedium COMMA_LOCKVAL_SRC_POS);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync rc = checkChildrenAndAttachmentsAndImmutable(aMedium);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* We have to fetch the state with the COM method, cause it's possible
e99772f9bf09219c532812c859fbeea513c67e65vboxsync that the medium isn't fully initialized yet. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* go to Deleting */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* we will need parent to reparent target */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Include all images from base to source. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* we will need to reparent children */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync for (MediaList::const_iterator it = aMedium->getChildren().begin();
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AutoWriteLock alock(aMedium COMMA_LOCKVAL_SRC_POS);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* go to LockedWrite */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AutoWriteLock alock(aMedium COMMA_LOCKVAL_SRC_POS);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* go to Deleting */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync for (MediaList::const_iterator it = begin(); it != end(); ++it)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Do we have the target? */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync for (MediaList::const_iterator it = begin(); it != end(); ++it)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Do we have the source? */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const MediaList& children() const { return mChildren; }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync { AssertReturn(size() > 0, NULL); return mSource; }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync { AssertReturn(size() > 0, NULL); return mTarget; }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync // SupportErrorInfoBase interface
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const GUID &mainInterfaceID() const { return COM_IIDOF(IMedium); }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const char *componentName() const { return Medium::ComponentName(); }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync HRESULT check(Medium *aMedium, bool aChildren, bool aAttachments,
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* not going to multi-merge as it's too expensive */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync tr("Medium '%s' involved in the merge operation has more than one child medium (%d)"),
e99772f9bf09219c532812c859fbeea513c67e65vboxsync tr("Medium '%s' is attached to %d virtual machines"),
e99772f9bf09219c532812c859fbeea513c67e65vboxsync HRESULT checkChildrenAndAttachments(Medium *aMedium)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync HRESULT checkChildrenAndAttachmentsAndImmutable(Medium *aMedium)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** true if forward merge, false if backward */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** true to not perform attachment checks */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** Parent of the source when forward merge (if any) */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** Children of the source when backward merge (if any) */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** Source image */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /** Target image */
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync////////////////////////////////////////////////////////////////////////////////
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync// ImageChain class
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync////////////////////////////////////////////////////////////////////////////////
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * Helper class for image operations involving the entire parent chain.
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * @note It is assumed that when modifying methods of this class are called,
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync * Medium::getTreeLock() is held in read mode.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* empty? */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for (MediaList::const_iterator it = begin(); it != end(); ++ it)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync else if ((*it)->m->state == MediumState_LockedWrite)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Lock all disks in the chain in {parent, child} order,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * and make sure they are accessible. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /// @todo code duplication with SessionMachine::lockMedia, see below
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for (MediaList::const_iterator it = begin(); it != end(); ++ it)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* accessibility check must be first, otherwise locking
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * interferes with getting the medium state. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync rc = (*it)->COMGETTER(LastAccessError)(error.asOutParam());
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* collect multiple errors */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* be in sync with Medium::setStateError() */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Lock all disks in the chain in {parent, child} order,
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * and make sure they are accessible. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /// @todo code duplication with SessionMachine::lockMedia, see below
e99772f9bf09219c532812c859fbeea513c67e65vboxsync for (MediaList::const_iterator it = begin(); it != end(); ++ it)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* accessibility check must be first, otherwise locking
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * interferes with getting the medium state. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync rc = (*it)->COMGETTER(LastAccessError)(error.asOutParam());
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* collect multiple errors */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* be in sync with Medium::setStateError() */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync // SupportErrorInfoBase interface
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const GUID &mainInterfaceID() const { return COM_IIDOF(IMedium); }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync const char *componentName() const { return Medium::ComponentName(); }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync////////////////////////////////////////////////////////////////////////////////
e99772f9bf09219c532812c859fbeea513c67e65vboxsync// Medium constructor / destructor
e99772f9bf09219c532812c859fbeea513c67e65vboxsync////////////////////////////////////////////////////////////////////////////////
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Initialize the callbacks of the VD error interface */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync m->vdIfCallsError.cbSize = sizeof(VDINTERFACEERROR);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync m->vdIfCallsError.enmInterface = VDINTERFACETYPE_ERROR;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Initialize the callbacks of the VD config interface */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync m->vdIfCallsConfig.cbSize = sizeof(VDINTERFACECONFIG);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync m->vdIfCallsConfig.enmInterface = VDINTERFACETYPE_CONFIG;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync m->vdIfCallsConfig.pfnAreKeysValid = vdConfigAreKeysValid;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync m->vdIfCallsConfig.pfnQuerySize = vdConfigQuerySize;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Initialize the callbacks of the VD TCP interface (we always use the host
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * IP stack for now) */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync m->vdIfCallsTcpNet.cbSize = sizeof(VDINTERFACETCPNET);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync m->vdIfCallsTcpNet.enmInterface = VDINTERFACETYPE_TCPNET;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync m->vdIfCallsTcpNet.pfnClientConnect = RTTcpClientConnect;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync m->vdIfCallsTcpNet.pfnClientClose = RTTcpClientClose;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync m->vdIfCallsTcpNet.pfnGetLocalAddress = RTTcpGetLocalAddress;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync m->vdIfCallsTcpNet.pfnGetPeerAddress = RTTcpGetPeerAddress;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Initialize the per-disk interface chain */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync "Medium::vdInterfaceError",
e99772f9bf09219c532812c859fbeea513c67e65vboxsync "Medium::vdInterfaceConfig",
e99772f9bf09219c532812c859fbeea513c67e65vboxsync "Medium::vdInterfaceTcpNet",
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Initializes the hard disk object without creating or opening an associated
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * storage unit.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * For hard disks that don't have the VD_CAP_CREATE_FIXED or
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * VD_CAP_CREATE_DYNAMIC capability (and therefore cannot be created or deleted
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * with the means of VirtualBox) the associated storage unit is assumed to be
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * ready for use so the state of the hard disk object will be set to Created.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param aVirtualBox VirtualBox object.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param aLocation Storage unit location.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(aFormat != NULL && *aFormat != '\0', E_FAIL);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Enclose the state transition NotReady->InInit->Ready */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* share VirtualBox weakly (parent remains NULL so far) */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* no storage yet */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* cannot be a host drive */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* No storage unit is created yet, no need to queryInfo() */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (m->formatObj->capabilities() & MediumFormatCapabilities_File)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (!(m->formatObj->capabilities() & ( MediumFormatCapabilities_CreateFixed
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* storage for hard disks of this format can neither be explicitly
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * created by VirtualBox nor deleted, so we place the hard disk to
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Created state here and also add it to the registry */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AutoWriteLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync rc = m->pVirtualBox->registerHardDisk(this, pfNeedsSaveSettings);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Confirm a successful initialization when it's the case */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Initializes the medium object by opening the storage unit at the specified
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * location. The enOpenMode parameter defines whether the image will be opened
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * read/write or read-only.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Note that the UUID, format and the parent of this medium will be
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * determined when reading the medium storage unit, unless new values are
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * specified by the parameters. If the detected or set parent is
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * not known to VirtualBox, then this method will fail.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param aVirtualBox VirtualBox object.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param aLocation Storage unit location.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param enOpenMode Whether to open the image read/write or read-only.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param aDeviceType Device type of medium.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param aSetImageId Whether to set the image UUID or not.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param aImageId New image UUID if @aSetId is true. Empty string means
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * create a new UUID, and a zero UUID is invalid.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param aSetParentId Whether to set the parent UUID or not.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param aParentId New parent UUID if @aSetParentId is true. Empty string
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * means create a new UUID, and a zero UUID is valid.
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* Enclose the state transition NotReady->InInit->Ready */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* share VirtualBox weakly (parent remains NULL so far) */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* there must be a storage unit */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* remember device type for correct unregistering later */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* cannot be a host drive */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* remember the open mode (defaults to ReadWrite) */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* save the new uuid values, will be used by queryInfo() */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* get all the information about the medium from the storage unit */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* if the storage unit is not accessible, it's not acceptable for the
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * newly opened media so convert this into an error */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync rc = setError(E_FAIL, m->strLastAccessError.c_str());
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* storage format must be detected by queryInfo() if the medium is accessible */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Confirm a successful initialization when it's the case */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Initializes the medium object by loading its data from the given settings
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * node. In this mode, the image will always be opened read/write.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param aVirtualBox VirtualBox object.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param aParent Parent medium disk or NULL for a root (base) medium.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param aDeviceType Device type of the medium.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param aNode Configuration settings.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @note Locks VirtualBox lock for writing, getTreeLock() for writing.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync using namespace settings;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Enclose the state transition NotReady->InInit->Ready */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* share VirtualBox and parent weakly */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* register with VirtualBox/parent early, since uninit() will
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * unconditionally unregister on failure */
if (aParent)
m->autoReset = false;
++it)
return rc;
m->hostDrive = true;
return S_OK;
++it)
if (m->pParent)
deparent();
++it)
if (this == pParentsChild)
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return S_OK;
return E_POINTER;
return S_OK;
return E_POINTER;
return S_OK;
AutoMultiWriteLock2 mlock(&m->pVirtualBox->getMediaTreeLockHandle(), this->lockHandle() COMMA_LOCKVAL_SRC_POS);
switch (m->state)
case MediumState_Created:
case MediumState_Inaccessible:
return setStateError();
return S_OK;
if (m->pParent)
switch (aType)
case MediumType_Normal:
case MediumType_Immutable:
case MediumType_Writethrough:
return rc;
return E_POINTER;
return S_OK;
return E_POINTER;
return S_OK;
return E_POINTER;
return S_OK;
return E_POINTER;
return S_OK;
return S_OK;
if (m->pParent)
return S_OK;
return S_OK;
return S_OK;
return E_POINTER;
size_t i = 0;
return S_OK;
switch (m->state)
case MediumState_Created:
case MediumState_Inaccessible:
case MediumState_LockedRead:
return rc;
++size;
if (size > 0)
size_t j = 0;
++jt, ++j)
return S_OK;
while (m->queryInfoRunning)
if (aState)
switch (m->state)
case MediumState_Created:
case MediumState_Inaccessible:
case MediumState_LockedRead:
++m->readers;
return rc;
switch (m->state)
case MediumState_LockedRead:
--m->readers;
if (m->readers == 0)
if (aState)
return rc;
while (m->queryInfoRunning)
if (aState)
switch (m->state)
case MediumState_Created:
case MediumState_Inaccessible:
return rc;
switch (m->state)
case MediumState_LockedWrite:
if (aState)
return rc;
this->lockHandle()
bool wasCreated = true;
bool fNeedsSaveSettings = false;
switch (m->state)
case MediumState_NotCreated:
wasCreated = false;
case MediumState_Created:
case MediumState_Inaccessible:
return setStateError();
if (wasCreated)
uninit();
if (fNeedsSaveSettings)
return S_OK;
return S_OK;
switch (m->state)
case MediumState_Created:
case MediumState_Inaccessible:
return setStateError();
aName);
return rc;
size_t i = 0;
++it)
return S_OK;
for (size_t i = 0;
for (size_t i = 0;
return rc;
switch (m->state)
case MediumState_NotCreated:
return setStateError();
static_cast<IMedium*>(this),
return S_OK;
return rc;
return rc;
if (aParent)
hd;
hd;
static_cast <IMedium *>(this),
return rc;
hd;
static_cast <IMedium *>(this),
return rc;
this->lockHandle()
static_cast<IMedium*>(this),
return rc;
return m->pParent;
return m->llChildren;
return m->id;
return m->state;
return m->strLocation;
return m->strLocationFull;
return m->size;
LogFlowThisFunc(("ENTER, aMachineId: {%RTuuid}, aSnapshotId: {%RTuuid}\n", aMachineId.raw(), aSnapshotId.raw()));
switch (m->state)
case MediumState_Created:
case MediumState_Inaccessible:
case MediumState_LockedRead:
case MediumState_LockedWrite:
return setStateError();
if (m->numCreateDiffTasks > 0)
m->numCreateDiffTasks);
return S_OK;
return S_OK;
++jt)
#ifdef DEBUG
dumpBackRefs();
tr("Cannot attach medium '%s' {%RTuuid} from snapshot '%RTuuid': medium is already in use by this snapshot!"),
return S_OK;
return S_OK;
return NULL;
return NULL;
return NULL;
#ifdef DEBUG
++it2)
LogFlowThisFunc((" Backref from machine {%RTuuid} (fInCurState: %d)\n", ref.machineId.raw(), ref.fInCurState));
++jt2)
return S_OK;
++ it)
pBase = this;
level = 0;
if (m->pParent)
++level;
return pBase;
switch (m->type)
case MediumType_Normal:
case MediumType_Immutable:
case MediumType_Writethrough:
AssertFailedReturn(false);
if (m->pParent)
++it)
++it)
return S_OK;
vrc);
return S_OK;
switch (m->state)
case MediumState_Created:
return setStateError();
return S_OK;
bool *pfNeedsSaveSettings)
AutoMultiWriteLock2 mLock(&m->pVirtualBox->getMediaTreeLockHandle(), this->lockHandle() COMMA_LOCKVAL_SRC_POS);
return rc;
hdFrom = this;
return rc;
return strFormat;
return m->type;
return name;
E_FAIL);
if ( isImport
&& !m->hostDrive))
E_FAIL);
E_FAIL);
if (isImport)
* VDCreateBase/VDCreateDiff as a wanted UUID). Note that we
return S_OK;
return E_FAIL;
if (m->queryInfoRunning)
return S_OK;
bool success = false;
|| !isImport
m->queryInfoRunning = true;
if (m->hostDrive)
success = true;
throw S_OK;
m->vdDiskIfaces);
throw S_OK;
if (m->setImageId)
if (m->setParentId)
m->setImageId = false;
m->setParentId = false;
if (isImport)
tr("UUID {%RTuuid} of the medium '%s' does not match the value {%RTuuid} stored in the media registry ('%s')"),
&uuid,
throw S_OK;
if (isImport)
if (m->setImageId)
unsigned uImageFlags;
if (isImport)
&parent);
tr("Parent hard disk with UUID {%RTuuid} of the hard disk '%s' is not found in the media registry ('%s')"),
throw S_OK;
tr("Hard disk '%s' is differencing but it is not associated with any parent hard disk in the media registry ('%s')"),
throw S_OK;
tr("Parent UUID {%RTuuid} of the hard disk '%s' does not match UUID {%RTuuid} of its parent hard disk stored in the media registry ('%s')"),
throw S_OK;
success = true;
if (isImport)
if (success)
m->queryInfoRunning = false;
if (success)
return rc;
switch (m->state)
case MediumState_NotCreated:
case MediumState_Created:
case MediumState_LockedRead:
case MediumState_LockedWrite:
case MediumState_Inaccessible:
case MediumState_Creating:
case MediumState_Deleting:
AssertFailed();
return rc;
* @param pfNeedsSaveSettings 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 should invoke VirtualBox::saveSettings() because the global settings have changed.
* This only works in "wait" mode; otherwise saveSettings gets called automatically by the thread that was created,
bool aWait,
bool *pfNeedsSaveSettings)
this->lockHandle()
switch (m->state)
case MediumState_Created:
case MediumState_Inaccessible:
return setStateError();
++it)
#ifdef DEBUG
dumpBackRefs();
tr("Cannot delete storage: hard disk '%s' is still attached to the following %d virtual machine(s): %s"),
static_cast<IMedium*>(this),
if (aWait)
rc = task->runNow(NULL /* pfNeedsSaveSettings*/ ); // there is no save settings to do in taskThreadDelete()
return rc;
* @param pfNeedsSaveSettings 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 should invoke VirtualBox::saveSettings() because the global settings have changed.
* This only works in "wait" mode; otherwise saveSettings gets called automatically by the thread that was created,
bool aWait,
bool *pfNeedsSaveSettings)
++it)
tr("Hard disk '%s' is attached to a virtual machine with UUID {%RTuuid}. No differencing hard disks based on it may be created until it is detached"),
static_cast<IMedium*>(this),
BstrFmt(tr("Creating differencing hard disk storage unit '%s'"), aTarget->m->strLocationFull.raw()),
++m->numCreateDiffTasks;
if (aWait)
return rc;
bool forward;
forward = false;
if (parent == this)
forward = true;
else if (last == this)
return S_OK;
* @param pfNeedsSaveSettings 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 should invoke VirtualBox::saveSettings() because the global settings have changed.
* This only works in "wait" mode; otherwise saveSettings gets called automatically by the thread that was created,
bool aWait,
bool *pfNeedsSaveSettings)
static_cast<IMedium*>(this),
if (aWait)
return rc;
delete aChain;
++ it)
return S_OK;
return S_OK;
* @param pfNeedsSaveSettings 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 should invoke VirtualBox::saveSettings() because the global settings have changed.
if (m->pParent)
deparent();
switch (m->devType)
case DeviceType_DVD:
case DeviceType_Floppy:
case DeviceType_HardDisk:
if (pParentBackup)
return rc;
return error;
return VERR_CANCELLED;
return VERR_INVALID_STATE;
return VINF_SUCCESS;
return VERR_CFGM_VALUE_NOT_FOUND;
return VERR_CFGM_VALUE_NOT_FOUND;
return VINF_SUCCESS;
return VERR_CFGM_VALUE_NOT_FOUND;
return VERR_CFGM_NOT_ENOUGH_SPACE;
return VERR_CFGM_VALUE_NOT_FOUND;
return VINF_SUCCESS;
* asynchronously. As a result, we always save the VirtualBox.xml file when we're
bool fGenerateUuid = false;
if (fGenerateUuid)
NULL,
&geo,
&geo,
NULL,
bool fNeedsSaveSettings = false;
if (fNeedsSaveSettings)
if (fGenerateUuid)
return rc;
bool fNeedsSaveSettings = false;
bool fGenerateUuid = false;
if (fGenerateUuid)
m->vdDiskIfaces);
NULL,
? TRUE
: FALSE;
deparent();
if (fGenerateUuid)
if (fIsAsync)
if (fNeedsSaveSettings)
--m->numCreateDiffTasks;
return rc;
++it)
unsigned uOpenFlags = 0;
throw vrc;
throw vrc;
++it)
throw vrc;
throw vrc;
throw vrc;
catch (int aVRC)
++it)
++it;
if (*it == this)
if (fIsAsync)
if (!fIsAsync)
return rc;
* As a result, we always save the VirtualBox.xml file when we're done here.
bool fCreatingTarget = false;
bool fGenerateUuid = false;
if (fGenerateUuid)
++it)
++it)
NULL,
if (pParent)
if (fCreatingTarget)
if (fGenerateUuid)
return rc;
m->vdDiskIfaces);
return rc;
m->vdDiskIfaces);
m->vdDiskIfaces);
NULL,
m->vdDiskIfaces,
if (fIsAsync)
return rc;
last--;
++it)
return rc;
if (fIsAsync)
return VINF_SUCCESS;