VirtualBox

Changeset 33107 in vbox for trunk/src


Ignore:
Timestamp:
Oct 13, 2010 2:00:08 PM (14 years ago)
Author:
vboxsync
Message:

Main/Medium: add internal importFile method, intended to be used by Appliance to import streamOptimized VMDKs straight from OVA (or elsewhere)

Location:
trunk/src/VBox/Main
Files:
2 edited

Legend:

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

    r33082 r33107  
    611611};
    612612
     613class Medium::ImportTask : public Medium::Task
     614{
     615public:
     616    ImportTask(Medium *aMedium,
     617               Progress *aProgress,
     618               const char *aFilename,
     619               MediumFormat *aFormat,
     620               MediumVariant_T aVariant,
     621               void *aVDImageIOCallbacks,
     622               void *aVDImageIOUser,
     623               Medium *aParent,
     624               MediumLockList *aTargetMediumLockList,
     625               bool fKeepTargetMediumLockList = false)
     626        : Medium::Task(aMedium, aProgress),
     627          mFilename(aFilename),
     628          mFormat(aFormat),
     629          mVariant(aVariant),
     630          mParent(aParent),
     631          mpTargetMediumLockList(aTargetMediumLockList),
     632          mParentCaller(aParent),
     633          mfKeepTargetMediumLockList(fKeepTargetMediumLockList)
     634    {
     635        AssertReturnVoidStmt(aTargetMediumLockList != NULL, mRC = E_FAIL);
     636        /* aParent may be NULL */
     637        mRC = mParentCaller.rc();
     638        if (FAILED(mRC))
     639            return;
     640
     641        mVDImageIfaces = aMedium->m->vdImageIfaces;
     642        if (aVDImageIOCallbacks)
     643        {
     644            int vrc = VDInterfaceAdd(&mVDInterfaceIO, "Medium::vdInterfaceIO",
     645                                     VDINTERFACETYPE_IO, aVDImageIOCallbacks,
     646                                     aVDImageIOUser, &mVDImageIfaces);
     647            AssertRCReturnVoidStmt(vrc, mRC = E_FAIL);
     648        }
     649    }
     650
     651    ~ImportTask()
     652    {
     653        if (!mfKeepTargetMediumLockList && mpTargetMediumLockList)
     654            delete mpTargetMediumLockList;
     655    }
     656
     657    Utf8Str mFilename;
     658    ComObjPtr<MediumFormat> mFormat;
     659    MediumVariant_T mVariant;
     660    const ComObjPtr<Medium> mParent;
     661    MediumLockList *mpTargetMediumLockList;
     662    PVDINTERFACE mVDImageIfaces;
     663
     664private:
     665    virtual HRESULT handler();
     666
     667    AutoCaller mParentCaller;
     668    bool mfKeepTargetMediumLockList;
     669    VDINTERFACE mVDInterfaceIO;
     670};
     671
    613672/**
    614673 * Thread function for time-consuming medium tasks.
     
    742801{
    743802    return mMedium->taskExportHandler(*this);
     803}
     804
     805/**
     806 * Implementation code for the "import" task.
     807 */
     808HRESULT Medium::ImportTask::handler()
     809{
     810    return mMedium->taskImportHandler(*this);
    744811}
    745812
     
    51695236
    51705237HRESULT Medium::exportFile(const char *aFilename,
    5171                            ComObjPtr<MediumFormat> aFormat,
     5238                           const ComObjPtr<MediumFormat> &aFormat,
    51725239                           MediumVariant_T aVariant,
    51735240                           void *aVDImageIOCallbacks, void *aVDImageIOUser,
    5174                            ComObjPtr<Progress> aProgress)
     5241                           const ComObjPtr<Progress> &aProgress)
    51755242{
    51765243    AssertPtrReturn(aFilename, E_INVALIDARG);
     
    52205287        if (FAILED(rc))
    52215288            throw rc;
     5289    }
     5290    catch (HRESULT aRC) { rc = aRC; }
     5291
     5292    if (SUCCEEDED(rc))
     5293        rc = startThread(pTask);
     5294    else if (pTask != NULL)
     5295        delete pTask;
     5296
     5297    return rc;
     5298}
     5299
     5300HRESULT Medium::importFile(const char *aFilename,
     5301                           const ComObjPtr<MediumFormat> &aFormat,
     5302                           MediumVariant_T aVariant,
     5303                           void *aVDImageIOCallbacks, void *aVDImageIOUser,
     5304                           const ComObjPtr<Medium> &aParent,
     5305                           const ComObjPtr<Progress> &aProgress)
     5306{
     5307    AssertPtrReturn(aFilename, E_INVALIDARG);
     5308    AssertReturn(!aFormat.isNull(), E_INVALIDARG);
     5309    AssertReturn(!aProgress.isNull(), E_INVALIDARG);
     5310
     5311    AutoCaller autoCaller(this);
     5312    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     5313
     5314    HRESULT rc = S_OK;
     5315    Medium::Task *pTask = NULL;
     5316
     5317    try
     5318    {
     5319        // locking: we need the tree lock first because we access parent pointers
     5320        AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     5321        // and we need to write-lock the media involved
     5322        AutoMultiWriteLock2 alock(this, aParent COMMA_LOCKVAL_SRC_POS);
     5323
     5324        if (   m->state != MediumState_NotCreated
     5325            && m->state != MediumState_Created)
     5326            throw setStateError();
     5327
     5328        /* Build the target lock list. */
     5329        MediumLockList *pTargetMediumLockList(new MediumLockList());
     5330        rc = createMediumLockList(true /* fFailIfInaccessible */,
     5331                                  true /* fMediumLockWrite */,
     5332                                  aParent,
     5333                                  *pTargetMediumLockList);
     5334        if (FAILED(rc))
     5335        {
     5336            delete pTargetMediumLockList;
     5337            throw rc;
     5338        }
     5339
     5340        rc = pTargetMediumLockList->Lock();
     5341        if (FAILED(rc))
     5342        {
     5343            delete pTargetMediumLockList;
     5344            throw setError(rc,
     5345                           tr("Failed to lock target media '%s'"),
     5346                           getLocationFull().c_str());
     5347        }
     5348
     5349        /* setup task object to carry out the operation asynchronously */
     5350        pTask = new Medium::ImportTask(this, aProgress, aFilename, aFormat,
     5351                                       aVariant, aVDImageIOCallbacks,
     5352                                       aVDImageIOUser, aParent,
     5353                                       pTargetMediumLockList);
     5354        rc = pTask->rc();
     5355        AssertComRC(rc);
     5356        if (FAILED(rc))
     5357            throw rc;
     5358
     5359        if (m->state == MediumState_NotCreated)
     5360            m->state = MediumState_Creating;
    52225361    }
    52235362    catch (HRESULT aRC) { rc = aRC; }
     
    64476586            Utf8Str targetLocation(pTarget->m->strLocationFull);
    64486587
    6449             Assert(    pTarget->m->state == MediumState_Creating
    6450                     || pTarget->m->state == MediumState_LockedWrite);
     6588            Assert(   pTarget->m->state == MediumState_Creating
     6589                   || pTarget->m->state == MediumState_LockedWrite);
    64516590            Assert(m->state == MediumState_LockedRead);
    6452             Assert(pParent.isNull() || pParent->m->state == MediumState_LockedRead);
     6591            Assert(   pParent.isNull()
     6592                   || pParent->m->state == MediumState_LockedRead);
    64536593
    64546594            /* unlock before the potentially lengthy operation */
     
    70677207                Assert(pMedium->m->state == MediumState_LockedRead);
    70687208
    7069                 /** Open all media in read-only mode. */
     7209                /* Open all media in read-only mode. */
    70707210                vrc = VDOpen(hdd,
    70717211                             pMedium->m->strFormat.c_str(),
     
    71377277}
    71387278
     7279/**
     7280 * Implementation code for the "import" task.
     7281 *
     7282 * This only gets started from Medium::importFile() and always runs
     7283 * asynchronously. It potentially touches the media registry, so we
     7284 * always save the VirtualBox.xml file when we're done here.
     7285 *
     7286 * @param task
     7287 * @return
     7288 */
     7289HRESULT Medium::taskImportHandler(Medium::ImportTask &task)
     7290{
     7291    HRESULT rc = S_OK;
     7292
     7293    const ComObjPtr<Medium> &pParent = task.mParent;
     7294
     7295    bool fCreatingTarget = false;
     7296
     7297    uint64_t size = 0, logicalSize = 0;
     7298    MediumVariant_T variant = MediumVariant_Standard;
     7299    bool fGenerateUuid = false;
     7300
     7301    try
     7302    {
     7303        /* Lock all in {parent,child} order. The lock is also used as a
     7304         * signal from the task initiator (which releases it only after
     7305         * RTThreadCreate()) that we can start the job. */
     7306        AutoMultiWriteLock2 thisLock(this, pParent COMMA_LOCKVAL_SRC_POS);
     7307
     7308        fCreatingTarget = m->state == MediumState_Creating;
     7309
     7310        /* The object may request a specific UUID (through a special form of
     7311         * the setLocation() argument). Otherwise we have to generate it */
     7312        Guid targetId = m->id;
     7313        fGenerateUuid = targetId.isEmpty();
     7314        if (fGenerateUuid)
     7315        {
     7316            targetId.create();
     7317            /* VirtualBox::registerHardDisk() will need UUID */
     7318            unconst(m->id) = targetId;
     7319        }
     7320
     7321
     7322        PVBOXHDD hdd;
     7323        int vrc = VDCreate(m->vdDiskIfaces, &hdd);
     7324        ComAssertRCThrow(vrc, E_FAIL);
     7325
     7326        try
     7327        {
     7328            /* Open source medium. */
     7329            rc = VDOpen(hdd,
     7330                        task.mFormat->getId().c_str(),
     7331                        task.mFilename.c_str(),
     7332                        VD_OPEN_FLAGS_READONLY,
     7333                        task.mVDImageIfaces);
     7334            if (RT_FAILURE(vrc))
     7335                throw setError(VBOX_E_FILE_ERROR,
     7336                               tr("Could not open the medium storage unit '%s'%s"),
     7337                               task.mFilename.c_str(),
     7338                               vdError(vrc).c_str());
     7339
     7340            Utf8Str targetFormat(m->strFormat);
     7341            Utf8Str targetLocation(m->strLocationFull);
     7342
     7343            Assert(   m->state == MediumState_Creating
     7344                   || m->state == MediumState_LockedWrite);
     7345            Assert(   pParent.isNull()
     7346                   || pParent->m->state == MediumState_LockedRead);
     7347
     7348            /* unlock before the potentially lengthy operation */
     7349            thisLock.release();
     7350
     7351            /* ensure the target directory exists */
     7352            rc = VirtualBox::ensureFilePathExists(targetLocation);
     7353            if (FAILED(rc))
     7354                throw rc;
     7355
     7356            PVBOXHDD targetHdd;
     7357            vrc = VDCreate(m->vdDiskIfaces, &targetHdd);
     7358            ComAssertRCThrow(vrc, E_FAIL);
     7359
     7360            try
     7361            {
     7362                /* Open all media in the target chain. */
     7363                MediumLockList::Base::const_iterator targetListBegin =
     7364                    task.mpTargetMediumLockList->GetBegin();
     7365                MediumLockList::Base::const_iterator targetListEnd =
     7366                    task.mpTargetMediumLockList->GetEnd();
     7367                for (MediumLockList::Base::const_iterator it = targetListBegin;
     7368                     it != targetListEnd;
     7369                     ++it)
     7370                {
     7371                    const MediumLock &mediumLock = *it;
     7372                    const ComObjPtr<Medium> &pMedium = mediumLock.GetMedium();
     7373
     7374                    /* If the target medium is not created yet there's no
     7375                     * reason to open it. */
     7376                    if (pMedium == this && fCreatingTarget)
     7377                        continue;
     7378
     7379                    AutoReadLock alock(pMedium COMMA_LOCKVAL_SRC_POS);
     7380
     7381                    /* sanity check */
     7382                    Assert(    pMedium->m->state == MediumState_LockedRead
     7383                            || pMedium->m->state == MediumState_LockedWrite);
     7384
     7385                    unsigned uOpenFlags = VD_OPEN_FLAGS_NORMAL;
     7386                    if (pMedium->m->state != MediumState_LockedWrite)
     7387                        uOpenFlags = VD_OPEN_FLAGS_READONLY;
     7388                    if (pMedium->m->type == MediumType_Shareable)
     7389                        uOpenFlags |= VD_OPEN_FLAGS_SHAREABLE;
     7390
     7391                    /* Open all media in appropriate mode. */
     7392                    vrc = VDOpen(targetHdd,
     7393                                 pMedium->m->strFormat.c_str(),
     7394                                 pMedium->m->strLocationFull.c_str(),
     7395                                 uOpenFlags,
     7396                                 pMedium->m->vdImageIfaces);
     7397                    if (RT_FAILURE(vrc))
     7398                        throw setError(VBOX_E_FILE_ERROR,
     7399                                       tr("Could not open the medium storage unit '%s'%s"),
     7400                                       pMedium->m->strLocationFull.c_str(),
     7401                                       vdError(vrc).c_str());
     7402                }
     7403
     7404                /** @todo r=klaus target isn't locked, race getting the state */
     7405                vrc = VDCopy(hdd,
     7406                             VD_LAST_IMAGE,
     7407                             targetHdd,
     7408                             targetFormat.c_str(),
     7409                             (fCreatingTarget) ? targetLocation.c_str() : (char *)NULL,
     7410                             false /* fMoveByRename */,
     7411                             0 /* cbSize */,
     7412                             task.mVariant,
     7413                             targetId.raw(),
     7414                             VD_OPEN_FLAGS_NORMAL,
     7415                             NULL /* pVDIfsOperation */,
     7416                             task.mVDImageIfaces,
     7417                             task.mVDOperationIfaces);
     7418                if (RT_FAILURE(vrc))
     7419                    throw setError(VBOX_E_FILE_ERROR,
     7420                                   tr("Could not create the clone medium '%s'%s"),
     7421                                   targetLocation.c_str(), vdError(vrc).c_str());
     7422
     7423                size = VDGetFileSize(targetHdd, VD_LAST_IMAGE);
     7424                logicalSize = VDGetSize(targetHdd, VD_LAST_IMAGE);
     7425                unsigned uImageFlags;
     7426                vrc = VDGetImageFlags(targetHdd, 0, &uImageFlags);
     7427                if (RT_SUCCESS(vrc))
     7428                    variant = (MediumVariant_T)uImageFlags;
     7429            }
     7430            catch (HRESULT aRC) { rc = aRC; }
     7431
     7432            VDDestroy(targetHdd);
     7433        }
     7434        catch (HRESULT aRC) { rc = aRC; }
     7435
     7436        VDDestroy(hdd);
     7437    }
     7438    catch (HRESULT aRC) { rc = aRC; }
     7439
     7440    /* Only do the parent changes for newly created media. */
     7441    if (SUCCEEDED(rc) && fCreatingTarget)
     7442    {
     7443        /* we set mParent & children() */
     7444        AutoWriteLock alock2(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
     7445
     7446        Assert(m->pParent.isNull());
     7447
     7448        if (pParent)
     7449        {
     7450            /* associate the clone with the parent and deassociate
     7451             * from VirtualBox */
     7452            m->pParent = pParent;
     7453            pParent->m->llChildren.push_back(this);
     7454
     7455            /* register with mVirtualBox as the last step and move to
     7456             * Created state only on success (leaving an orphan file is
     7457             * better than breaking media registry consistency) */
     7458            rc = pParent->m->pVirtualBox->registerHardDisk(this, NULL /* pfNeedsGlobalSaveSettings */);
     7459
     7460            if (FAILED(rc))
     7461                /* break parent association on failure to register */
     7462                this->deparent();     // removes target from parent
     7463        }
     7464        else
     7465        {
     7466            /* just register  */
     7467            rc = m->pVirtualBox->registerHardDisk(this, NULL /* pfNeedsGlobalSaveSettings */);
     7468        }
     7469    }
     7470
     7471    if (fCreatingTarget)
     7472    {
     7473        AutoWriteLock mLock(this COMMA_LOCKVAL_SRC_POS);
     7474
     7475        if (SUCCEEDED(rc))
     7476        {
     7477            m->state = MediumState_Created;
     7478
     7479            m->size = size;
     7480            m->logicalSize = logicalSize;
     7481            m->variant = variant;
     7482        }
     7483        else
     7484        {
     7485            /* back to NotCreated on failure */
     7486            m->state = MediumState_NotCreated;
     7487
     7488            /* reset UUID to prevent it from being reused next time */
     7489            if (fGenerateUuid)
     7490                unconst(m->id).clear();
     7491        }
     7492    }
     7493
     7494    // now, at the end of this task (always asynchronous), save the settings
     7495    {
     7496        AutoWriteLock vboxlock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
     7497        m->pVirtualBox->saveSettings();
     7498    }
     7499
     7500    /* Everything is explicitly unlocked when the task exits,
     7501     * as the task destruction also destroys the target chain. */
     7502
     7503    /* Make sure the target chain is released early, otherwise it can
     7504     * lead to deadlocks with concurrent IAppliance activities. */
     7505    task.mpTargetMediumLockList->Clear();
     7506
     7507    return rc;
     7508}
     7509
    71397510/* vi: set tabstop=4 shiftwidth=4 expandtab: */
  • trunk/src/VBox/Main/include/MediumImpl.h

    r33078 r33107  
    246246     *
    247247     * @param aFilename             Filename to create (UTF8).
    248      * @param aFormat               Which medium format to use.
     248     * @param aFormat               Which medium format to use for export.
    249249     * @param aVariant              Which exact image format variant to use.
    250250     * @param aVDImageIOCallbacks   Pointer to the callback table for a
     
    255255     */
    256256    HRESULT exportFile(const char *aFilename,
    257                        ComObjPtr<MediumFormat> aFormat,
     257                       const ComObjPtr<MediumFormat> &aFormat,
    258258                       MediumVariant_T aVariant,
    259259                       void *aVDImageIOCallbacks, void *aVDImageIOUser,
    260                        ComObjPtr<Progress> aProgress);
     260                       const ComObjPtr<Progress> &aProgress);
     261    /**
     262     * Used by IAppliance to import disk images.
     263     *
     264     * @param aFilename             Filename to read (UTF8).
     265     * @param aFormat               Which medium format to use for import.
     266     * @param aVariant              Which exact image format variant to use.
     267     * @param aVDImageIOCallbacks   Pointer to the callback table for a
     268     *                              VDINTERFACEIO interface. May be NULL.
     269     * @param aVDImageIOUser        Opaque data for the callbacks.
     270     * @param aParent               Parent medium. May be NULL.
     271     * @param aProgress             Progress object to use.
     272     * @return
     273     */
     274    HRESULT importFile(const char *aFilename,
     275                       const ComObjPtr<MediumFormat> &aFormat,
     276                       MediumVariant_T aVariant,
     277                       void *aVDImageIOCallbacks, void *aVDImageIOUser,
     278                       const ComObjPtr<Medium> &aParent,
     279                       const ComObjPtr<Progress> &aProgress);
    261280
    262281    /** Returns a preferred format for a differencing hard disk. */
     
    311330    class MergeTask;
    312331    class ExportTask;
     332    class ImportTask;
    313333    friend class Task;
    314334    friend class CreateBaseTask;
     
    321341    friend class MergeTask;
    322342    friend class ExportTask;
     343    friend class ImportTask;
    323344
    324345    HRESULT startThread(Medium::Task *pTask);
     
    334355    HRESULT taskResizeHandler(Medium::ResizeTask &task);
    335356    HRESULT taskExportHandler(Medium::ExportTask &task);
     357    HRESULT taskImportHandler(Medium::ImportTask &task);
    336358
    337359    struct Data;            // opaque data struct, defined in MediumImpl.cpp
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