VirtualBox

Changeset 15556 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Dec 15, 2008 10:31:49 PM (16 years ago)
Author:
vboxsync
Message:

Main, VBoxManage: Implemented IHardDisk2::cloneTo(). Resurrected 'clonehd' functionality.

File:
1 edited

Legend:

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

    r15486 r15556  
    5757struct HardDisk2::Task : public com::SupportErrorInfoBase
    5858{
    59     enum Operation { CreateDynamic, CreateFixed, CreateDiff, Merge, Delete };
     59    enum Operation { CreateDynamic, CreateFixed, CreateDiff,
     60                     Merge, Clone, Delete };
    6061
    6162    HardDisk2 *that;
     
    11281129                                              IProgress **aProgress)
    11291130{
    1130     if (aProgress == NULL)
    1131         return E_POINTER;
     1131    CheckComArgOutPointerValid (aProgress);
    11321132
    11331133    AutoCaller autoCaller (this);
     
    11841184                                            IProgress **aProgress)
    11851185{
    1186     if (aProgress == NULL)
    1187         return E_POINTER;
     1186    CheckComArgOutPointerValid (aProgress);
    11881187
    11891188    AutoCaller autoCaller (this);
     
    12391238STDMETHODIMP HardDisk2::DeleteStorage (IProgress **aProgress)
    12401239{
    1241     if (aProgress == NULL)
    1242         return E_POINTER;
     1240    CheckComArgOutPointerValid (aProgress);
     1241
     1242    AutoCaller autoCaller (this);
     1243    CheckComRCReturnRC (autoCaller.rc());
    12431244
    12441245    ComObjPtr <Progress> progress;
     
    12561257STDMETHODIMP HardDisk2::CreateDiffStorage (IHardDisk2 *aTarget, IProgress **aProgress)
    12571258{
    1258     if (aTarget == NULL)
    1259         return E_INVALIDARG;
    1260     if (aProgress == NULL)
    1261         return E_POINTER;
     1259    CheckComArgNotNull (aTarget);
     1260    CheckComArgOutPointerValid (aProgress);
    12621261
    12631262    AutoCaller autoCaller (this);
     
    13061305STDMETHODIMP HardDisk2::CloneTo (IHardDisk2 *aTarget, IProgress **aProgress)
    13071306{
     1307    CheckComArgNotNull (aTarget);
     1308    CheckComArgOutPointerValid (aProgress);
     1309
    13081310    AutoCaller autoCaller (this);
    13091311    CheckComRCReturnRC (autoCaller.rc());
    13101312
    1311     ReturnComNotImplemented();
     1313    ComObjPtr <HardDisk2> target;
     1314    HRESULT rc = mVirtualBox->cast (aTarget, target);
     1315    CheckComRCReturnRC (rc);
     1316
     1317    AutoMultiWriteLock2 alock (this, target);
     1318
     1319    /* We want to be locked for reading as long as the clone hard disk is being
     1320     * created*/
     1321    rc = LockRead (NULL);
     1322    CheckComRCReturnRC (rc);
     1323
     1324    ComObjPtr <Progress> progress;
     1325
     1326    try
     1327    {
     1328        if (target->m.state != MediaState_NotCreated)
     1329            throw target->setStateError();
     1330
     1331        progress.createObject();
     1332        rc = progress->init (mVirtualBox, static_cast <IHardDisk2 *> (this),
     1333            BstrFmt (tr ("Creating a clone hard disk '%s'"),
     1334                     target->name().raw()),
     1335            FALSE /* aCancelable */);
     1336        CheckComRCThrowRC (rc);
     1337
     1338        /* setup task object and thread to carry out the operation
     1339         * asynchronously */
     1340
     1341        std::auto_ptr <Task> task (new Task (this, progress, Task::Clone));
     1342        AssertComRCThrowRC (task->autoCaller.rc());
     1343
     1344        task->setData (target);
     1345
     1346        rc = task->startThread();
     1347        CheckComRCThrowRC (rc);
     1348
     1349        /* go to Creating state before leaving the lock */
     1350        target->m.state = MediaState_Creating;
     1351
     1352        /* task is now owned (or already deleted) by taskThread() so release it */
     1353        task.release();
     1354    }
     1355    catch (HRESULT aRC)
     1356    {
     1357        rc = aRC;
     1358    }
     1359
     1360    if (FAILED (rc))
     1361    {
     1362        HRESULT rc2 = UnlockRead (NULL);
     1363        AssertComRC (rc2);
     1364        /* Note: on success, taskThread() will unlock this */
     1365    }
     1366    else
     1367    {
     1368        /* return progress to the caller */
     1369        progress.queryInterfaceTo (aProgress);
     1370    }
     1371
     1372    return rc;
    13121373}
    13131374
     
    32033264            uint64_t size = 0, logicalSize = 0;
    32043265
    3205             /* the object may request a specific UUID (through a special
    3206              * form of the setLocation() argumet) */
     3266            /* The object may request a specific UUID (through a special form of
     3267             * the setLocation() argumet). Otherwise we have to generate it */
    32073268            Guid id = that->m.id;
     3269            bool generateUuid = id.isEmpty();
     3270            if (generateUuid)
     3271            {
     3272                id.create();
     3273                /* VirtualBox::registerHardDisk2() will need UUID */
     3274                unconst (that->m.id) = id;
     3275            }
    32083276
    32093277            try
     
    32383306                                        task->d.size * _1M,
    32393307                                        VD_IMAGE_FLAGS_NONE,
    3240                                         NULL, &geo, &geo,
    3241                                         id.isEmpty() ? NULL : id.raw(),
     3308                                        NULL, &geo, &geo, id.raw(),
    32423309                                        VD_OPEN_FLAGS_NORMAL,
    32433310                                        NULL, that->mm.vdDiskIfaces);
     
    32513318                    }
    32523319
    3253                     if (capabilities & HardDiskFormatCapabilities_Uuid)
    3254                     {
    3255                         RTUUID uuid;
    3256                         vrc = VDGetUuid (hdd, 0, &uuid);
    3257                         ComAssertRCThrow (vrc, E_FAIL);
    3258 
    3259                         if (!id.isEmpty())
    3260                             Assert (id == uuid);
    3261                         else
    3262                             id = uuid;
    3263                     }
    3264                     else
    3265                     {
    3266                         /* we have to generate an UUID ourselves */
    3267                         id.create();
    3268                     }
    3269 
    32703320                    size = VDGetFileSize (hdd, 0);
    32713321                    logicalSize = VDGetSize (hdd, 0) / _1M;
     
    32793329            if (SUCCEEDED (rc))
    32803330            {
    3281                 /* mVirtualBox->registerHardDisk2() needs a write lock */
    3282                 AutoWriteLock vboxLock (that->mVirtualBox);
    3283                 thatLock.enter();
    3284 
    3285                 unconst (that->m.id) = id;
    3286 
    3287                 that->m.size = size;
    3288                 that->mm.logicalSize = logicalSize;
    3289 
    32903331                /* register with mVirtualBox as the last step and move to
    32913332                 * Created state only on success (leaving an orphan file is
    32923333                 * better than breaking media registry consistency) */
    32933334                rc = that->mVirtualBox->registerHardDisk2 (that);
    3294 
    3295                 if (SUCCEEDED (rc))
    3296                     that->m.state = MediaState_Created;
    32973335            }
    32983336
    3299             if (FAILED (rc))
     3337            thatLock.maybeEnter();
     3338
     3339            if (SUCCEEDED (rc))
    33003340            {
    3301                 thatLock.maybeEnter();
    3302 
     3341                that->m.state = MediaState_Created;
     3342
     3343                that->m.size = size;
     3344                that->mm.logicalSize = logicalSize;
     3345            }
     3346            else
     3347            {
    33033348                /* back to NotCreated on failiure */
    33043349                that->m.state = MediaState_NotCreated;
     3350
     3351                /* reset UUID to prevent it from being reused next time */
     3352                if (generateUuid)
     3353                    unconst (that->m.id).clear();
    33053354            }
    33063355
     
    33203369
    33213370            uint64_t size = 0, logicalSize = 0;
     3371
     3372            /* The object may request a specific UUID (through a special form of
     3373             * the setLocation() argumet). Otherwise we have to generate it */
     3374            Guid targetId = target->m.id;
     3375            bool generateUuid = targetId.isEmpty();
     3376            if (generateUuid)
     3377            {
     3378                targetId.create();
     3379                /* VirtualBox::registerHardDisk2() will need UUID */
     3380                unconst (target->m.id) = targetId;
     3381            }
    33223382
    33233383            try
     
    33323392                Utf8Str targetFormat (target->mm.format);
    33333393                Utf8Str targetLocation (target->m.locationFull);
    3334                 Guid targetId = target->m.id;
    3335 
    3336                 /* UUID must have been set by setLocation() */
    3337                 Assert (!targetId.isEmpty());
    33383394
    33393395                Assert (target->m.state == MediaState_Creating);
     
    34343490                /* back to NotCreated on failiure */
    34353491                target->m.state = MediaState_NotCreated;
     3492
     3493                /* reset UUID to prevent it from being reused next time */
     3494                if (generateUuid)
     3495                    unconst (target->m.id).clear();
    34363496            }
    34373497
     
    37593819        ////////////////////////////////////////////////////////////////////////
    37603820
     3821        case Task::Clone:
     3822        {
     3823            ComObjPtr <HardDisk2> &target = task->d.target;
     3824
     3825            /* Lock both in {parent,child} order. The lock is also used as a
     3826             * signal from the task initiator (which releases it only after
     3827             * RTThreadCreate()) that we can start the job*/
     3828            AutoMultiWriteLock2 thatLock (that, target);
     3829
     3830            uint64_t size = 0, logicalSize = 0;
     3831
     3832            /* The object may request a specific UUID (through a special form of
     3833             * the setLocation() argumet). Otherwise we have to generate it */
     3834            Guid targetId = target->m.id;
     3835            bool generateUuid = targetId.isEmpty();
     3836            if (generateUuid)
     3837            {
     3838                targetId.create();
     3839                /* VirtualBox::registerHardDisk2() will need UUID */
     3840                unconst (target->m.id) = targetId;
     3841            }
     3842
     3843            try
     3844            {
     3845                PVBOXHDD hdd;
     3846                int vrc = VDCreate (that->mm.vdDiskIfaces, &hdd);
     3847                ComAssertRCThrow (vrc, E_FAIL);
     3848
     3849                Utf8Str format (that->mm.format);
     3850                Utf8Str location (that->m.locationFull);
     3851
     3852                Utf8Str targetFormat (target->mm.format);
     3853                Utf8Str targetLocation (target->m.locationFull);
     3854
     3855                Assert (target->m.state == MediaState_Creating);
     3856
     3857                Assert (that->m.state == MediaState_LockedRead);
     3858
     3859                /* unlock before the potentially lengthy operation */
     3860                thatLock.leave();
     3861
     3862                try
     3863                {
     3864                    vrc = VDOpen (hdd, format, location,
     3865                                  VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO,
     3866                                  NULL);
     3867                    if (RT_FAILURE (vrc))
     3868                    {
     3869                        throw setError (E_FAIL,
     3870                            tr ("Could not open the hard disk storage "
     3871                                "unit '%s'%s"),
     3872                            location.raw(), that->vdError (vrc).raw());
     3873                    }
     3874
     3875                    /* ensure the target directory exists */
     3876                    rc = VirtualBox::ensureFilePathExists (targetLocation);
     3877                    CheckComRCThrowRC (rc);
     3878
     3879                    /* needed for vdProgressCallback */
     3880                    that->mm.vdProgress = task->progress;
     3881
     3882                    PVBOXHDD targetHdd;
     3883                    int vrc = VDCreate (that->mm.vdDiskIfaces, &targetHdd);
     3884                    ComAssertRCThrow (vrc, E_FAIL);
     3885
     3886                    vrc = VDCopy (hdd, 0, targetHdd, targetFormat,
     3887                                  targetLocation, false, 0, targetId.raw(),
     3888                                  NULL, NULL, that->mm.vdDiskIfaces);
     3889
     3890                    that->mm.vdProgress = NULL;
     3891
     3892                    if (RT_FAILURE (vrc))
     3893                    {
     3894                        VDDestroy (targetHdd);
     3895
     3896                        throw setError (E_FAIL,
     3897                            tr ("Could not create the clone hard disk "
     3898                                "'%s'%s"),
     3899                            targetLocation.raw(), that->vdError (vrc).raw());
     3900                    }
     3901
     3902                    size = VDGetFileSize (hdd, 0);
     3903                    logicalSize = VDGetSize (hdd, 0) / _1M;
     3904
     3905                    VDDestroy (targetHdd);
     3906                }
     3907                catch (HRESULT aRC) { rc = aRC; }
     3908
     3909                VDDestroy (hdd);
     3910            }
     3911            catch (HRESULT aRC) { rc = aRC; }
     3912
     3913            if (SUCCEEDED (rc))
     3914            {
     3915                /* we set mParent & children() (note that thatLock is released
     3916                 * here), but lock VirtualBox first to follow the rule */
     3917                AutoMultiWriteLock2 alock (that->mVirtualBox->lockHandle(),
     3918                                           that->treeLock());
     3919
     3920                Assert (target->mParent.isNull());
     3921
     3922                if (!that->mParent.isNull())
     3923                {
     3924                    /* associate the clone with the original's parent and
     3925                     * deassociate from VirtualBox */
     3926                    target->mParent = that->mParent;
     3927                    that->mParent->addDependentChild (target);
     3928                    target->mVirtualBox->removeDependentChild (target);
     3929
     3930                    /* register with mVirtualBox as the last step and move to
     3931                     * Created state only on success (leaving an orphan file is
     3932                     * better than breaking media registry consistency) */
     3933                    rc = that->mVirtualBox->registerHardDisk2 (target);
     3934
     3935                    if (FAILED (rc))
     3936                    {
     3937                        /* break the parent association on failure to register */
     3938                        target->mVirtualBox->addDependentChild (target);
     3939                        that->mParent->removeDependentChild (target);
     3940                        target->mParent.setNull();
     3941                    }
     3942                }
     3943                else
     3944                {
     3945                    /* just register  */
     3946                    rc = that->mVirtualBox->registerHardDisk2 (target);
     3947                }
     3948            }
     3949
     3950            thatLock.maybeEnter();
     3951
     3952            if (SUCCEEDED (rc))
     3953            {
     3954                target->m.state = MediaState_Created;
     3955
     3956                target->m.size = size;
     3957                target->mm.logicalSize = logicalSize;
     3958            }
     3959            else
     3960            {
     3961                /* back to NotCreated on failiure */
     3962                target->m.state = MediaState_NotCreated;
     3963
     3964                /* reset UUID to prevent it from being reused next time */
     3965                if (generateUuid)
     3966                    unconst (target->m.id).clear();
     3967            }
     3968
     3969            if (isAsync)
     3970            {
     3971                /* unlock ourselves when done (unless in MediaState_LockedWrite
     3972                 * state because of taking the online snapshot*/
     3973                if (that->m.state != MediaState_LockedWrite)
     3974                {
     3975                    HRESULT rc2 = that->UnlockRead (NULL);
     3976                    AssertComRC (rc2);
     3977                }
     3978            }
     3979
     3980            /* Note that in sync mode, it's the caller's responsibility to
     3981             * unlock the hard disk */
     3982
     3983            break;
     3984        }
     3985
     3986        ////////////////////////////////////////////////////////////////////////
     3987
    37613988        case Task::Delete:
    37623989        {
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