VirtualBox

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


Ignore:
Timestamp:
Dec 21, 2007 6:57:02 PM (17 years ago)
Author:
vboxsync
Message:

Add rudimentary VHD support

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

Legend:

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

    r6140 r6173  
    776776            STR_CONV();
    777777            rc = CFGMR3InsertString(pCfg,   "Format",           psz);                   RC_CHECK();
     778            STR_FREE();
     779        }
     780        else if (hddType == HardDiskStorageType_VHDImage)
     781        {
     782            ComPtr<IVHDImage> vhdDisk = hardDisk;
     783            AssertBreak (!vhdDisk.isNull(), hrc = E_FAIL);
     784
     785            rc = CFGMR3InsertNode(pLunL0,   "AttachedDriver", &pLunL1);                 RC_CHECK();
     786            rc = CFGMR3InsertString(pLunL1, "Driver",         "VD");                    RC_CHECK();
     787            rc = CFGMR3InsertNode(pLunL1,   "Config", &pCfg);                           RC_CHECK();
     788            hrc = vhdDisk->COMGETTER(FilePath)(&str);                                   H();
     789            STR_CONV();
     790            rc = CFGMR3InsertString(pCfg,   "Path",             psz);                   RC_CHECK();
    778791            STR_FREE();
    779792        }
  • trunk/src/VBox/Main/HardDiskImpl.cpp

    r6076 r6173  
    10701070        { HardDiskStorageType_VMDKImage, ".vmdk" },
    10711071        { HardDiskStorageType_VirtualDiskImage, ".vdi" },
     1072        { HardDiskStorageType_VHDImage, ".vhd" },
    10721073    };
    10731074
     
    11381139                break;
    11391140            }
     1141            case HardDiskStorageType_VHDImage:
     1142            {
     1143                ComObjPtr <HVHDImage> obj;
     1144                obj.createObject();
     1145                rc = obj->init (aVirtualBox, NULL, aLocation,
     1146                                FALSE /* aRegistered */);
     1147                if (SUCCEEDED (rc))
     1148                {
     1149                    hardDisk = obj;
     1150                    return rc;
     1151                }
     1152                break;
     1153            }
    11401154            default:
    11411155            {
     
    50435057        that->mLastVDError = err;
    50445058    else
     5059       that->mLastVDError = Utf8StrFmt
     5060           ("%s.\n%s", that->mLastVDError.raw(), err.raw());
     5061}
     5062
     5063////////////////////////////////////////////////////////////////////////////////
     5064// HVHDImage class
     5065////////////////////////////////////////////////////////////////////////////////
     5066
     5067// constructor / destructor
     5068////////////////////////////////////////////////////////////////////////////////
     5069
     5070HRESULT HVHDImage::FinalConstruct()
     5071{
     5072    HRESULT rc = HardDisk::FinalConstruct();
     5073    if (FAILED (rc))
     5074        return rc;
     5075
     5076    mState = NotCreated;
     5077
     5078    mStateCheckSem = NIL_RTSEMEVENTMULTI;
     5079    mStateCheckWaiters = 0;
     5080
     5081    mSize = 0;
     5082    mActualSize = 0;
     5083
     5084    /* initialize the container */
     5085    int vrc = VDCreate ("VHD", VDError, this, &mContainer);
     5086    ComAssertRCRet (vrc, E_FAIL);
     5087
     5088    return S_OK;
     5089}
     5090
     5091void HVHDImage::FinalRelease()
     5092{
     5093    if (mContainer != NULL)
     5094        VDDestroy (mContainer);
     5095
     5096    HardDisk::FinalRelease();
     5097}
     5098
     5099// public initializer/uninitializer for internal purposes only
     5100////////////////////////////////////////////////////////////////////////////////
     5101
     5102// public methods for internal purposes only
     5103/////////////////////////////////////////////////////////////////////////////
     5104
     5105/**
     5106 *  Initializes the VHD hard disk object by reading its properties from
     5107 *  the given configuration node. The created hard disk will be marked as
     5108 *  registered on success.
     5109 *
     5110 *  @param aHDNode      <HardDisk> node
     5111 *  @param aVHDNode    <VirtualDiskImage> node
     5112 */
     5113HRESULT HVHDImage::init (VirtualBox *aVirtualBox, HardDisk *aParent,
     5114                         const settings::Key &aHDNode,
     5115                         const settings::Key &aVHDNode)
     5116{
     5117    LogFlowThisFunc (("\n"));
     5118
     5119    AssertReturn (!aHDNode.isNull() && !aVHDNode.isNull(), E_FAIL);
     5120
     5121    AutoLock alock (this);
     5122    ComAssertRet (!isReady(), E_UNEXPECTED);
     5123
     5124    mStorageType = HardDiskStorageType_VHDImage;
     5125
     5126    HRESULT rc = S_OK;
     5127
     5128    do
     5129    {
     5130        rc = protectedInit (aVirtualBox, aParent);
     5131        CheckComRCBreakRC (rc);
     5132
     5133        /* set ready to let protectedUninit() be called on failure */
     5134        setReady (true);
     5135
     5136        /* filePath (required) */
     5137        Bstr filePath = aVHDNode.stringValue("filePath");
     5138
     5139        rc = setFilePath (filePath);
     5140        CheckComRCBreakRC (rc);
     5141
     5142        LogFlowThisFunc (("'%ls'\n", mFilePathFull.raw()));
     5143
     5144        /* load basic settings and children */
     5145        rc = loadSettings (aHDNode);
     5146        CheckComRCBreakRC (rc);
     5147
     5148        if (mType != HardDiskType_WritethroughHardDisk)
     5149        {
     5150            rc = setError (E_FAIL,
     5151                tr ("Currently, non-Writethrough VHD images are not "
     5152                    "allowed ('%ls')"),
     5153                toString().raw());
     5154            break;
     5155        }
     5156
     5157        mState = Created;
     5158        mRegistered = TRUE;
     5159
     5160        /* Don't call queryInformation() for registered hard disks to
     5161         * prevent the calling thread (i.e. the VirtualBox server startup
     5162         * thread) from an unexpected freeze. The vital mId property (UUID)
     5163         * is read from the registry file in loadSettings(). To get the rest,
     5164         * the user will have to call COMGETTER(Accessible) manually. */
     5165    }
     5166    while (0);
     5167
     5168    if (FAILED (rc))
     5169        uninit();
     5170
     5171    return rc;
     5172}
     5173
     5174/**
     5175 *  Initializes the VHD hard disk object using the given image file name.
     5176 *
     5177 *  @param aVirtualBox  VirtualBox parent.
     5178 *  @param aParent      Currently, must always be @c NULL.
     5179 *  @param aFilePath    Path to the image file, or @c NULL to create an
     5180 *                      image-less object.
     5181 *  @param aRegistered  Whether to mark this disk as registered or not
     5182 *                      (ignored when @a aFilePath is @c NULL, assuming @c FALSE)
     5183 */
     5184HRESULT HVHDImage::init (VirtualBox *aVirtualBox, HardDisk *aParent,
     5185                          const BSTR aFilePath, BOOL aRegistered /* = FALSE */)
     5186{
     5187    LogFlowThisFunc (("aFilePath='%ls', aRegistered=%d\n", aFilePath, aRegistered));
     5188
     5189    AssertReturn (aParent == NULL, E_FAIL);
     5190
     5191    AutoLock alock (this);
     5192    ComAssertRet (!isReady(), E_UNEXPECTED);
     5193
     5194    mStorageType = HardDiskStorageType_VHDImage;
     5195
     5196    HRESULT rc = S_OK;
     5197
     5198    do
     5199    {
     5200        rc = protectedInit (aVirtualBox, aParent);
     5201        CheckComRCBreakRC (rc);
     5202
     5203        /* set ready to let protectedUninit() be called on failure */
     5204        setReady (true);
     5205
     5206        rc = setFilePath (aFilePath);
     5207        CheckComRCBreakRC (rc);
     5208
     5209        /* currently, all VHD hard disks are writethrough */
     5210        mType = HardDiskType_WritethroughHardDisk;
     5211
     5212        Assert (mId.isEmpty());
     5213
     5214        if (aFilePath && *aFilePath)
     5215        {
     5216            mRegistered = aRegistered;
     5217            mState = Created;
     5218
     5219            /* Call queryInformation() anyway (even if it will block), because
     5220             * it is the only way to get the UUID of the existing VDI and
     5221             * initialize the vital mId property. */
     5222            Bstr errMsg;
     5223            rc = queryInformation (&errMsg);
     5224            if (SUCCEEDED (rc))
     5225            {
     5226                /* We are constructing a new HVirtualDiskImage object. If there
     5227                 * is a fatal accessibility error (we cannot read image UUID),
     5228                 * we have to fail. We do so even on non-fatal errors as well,
     5229                 * because it's not worth to keep going with the inaccessible
     5230                 * image from the very beginning (when nothing else depends on
     5231                 * it yet). */
     5232                if (!errMsg.isNull())
     5233                    rc = setErrorBstr (E_FAIL, errMsg);
     5234            }
     5235        }
     5236        else
     5237        {
     5238            mRegistered = FALSE;
     5239            mState = NotCreated;
     5240            mId.create();
     5241        }
     5242    }
     5243    while (0);
     5244
     5245    if (FAILED (rc))
     5246        uninit();
     5247
     5248    return rc;
     5249}
     5250
     5251/**
     5252 *  Uninitializes the instance and sets the ready flag to FALSE.
     5253 *  Called either from FinalRelease(), by the parent when it gets destroyed,
     5254 *  or by a third party when it decides this object is no more valid.
     5255 */
     5256void HVHDImage::uninit()
     5257{
     5258    LogFlowThisFunc (("\n"));
     5259
     5260    AutoLock alock (this);
     5261    if (!isReady())
     5262        return;
     5263
     5264    HardDisk::protectedUninit (alock);
     5265}
     5266
     5267// IHardDisk properties
     5268////////////////////////////////////////////////////////////////////////////////
     5269
     5270STDMETHODIMP HVHDImage::COMGETTER(Description) (BSTR *aDescription)
     5271{
     5272    if (!aDescription)
     5273        return E_POINTER;
     5274
     5275    AutoLock alock (this);
     5276    CHECK_READY();
     5277
     5278    mDescription.cloneTo (aDescription);
     5279    return S_OK;
     5280}
     5281
     5282STDMETHODIMP HVHDImage::COMSETTER(Description) (INPTR BSTR aDescription)
     5283{
     5284    AutoLock alock (this);
     5285    CHECK_READY();
     5286
     5287    CHECK_BUSY_AND_READERS();
     5288
     5289    return E_NOTIMPL;
     5290
     5291/// @todo implement
     5292//
     5293//     if (mState >= Created)
     5294//     {
     5295//         int vrc = VDISetImageComment (Utf8Str (mFilePathFull), Utf8Str (aDescription));
     5296//         if (VBOX_FAILURE (vrc))
     5297//             return setError (E_FAIL,
     5298//                 tr ("Could not change the description of the VDI hard disk '%ls' "
     5299//                     "(%Vrc)"),
     5300//                 toString().raw(), vrc);
     5301//     }
     5302//
     5303//     mDescription = aDescription;
     5304//     return S_OK;
     5305}
     5306
     5307STDMETHODIMP HVHDImage::COMGETTER(Size) (ULONG64 *aSize)
     5308{
     5309    if (!aSize)
     5310        return E_POINTER;
     5311
     5312    AutoLock alock (this);
     5313    CHECK_READY();
     5314
     5315/// @todo will need this if we add suppord for differencing VMDKs
     5316//
     5317//     /* only a non-differencing image knows the logical size */
     5318//     if (isDifferencing())
     5319//         return root()->COMGETTER(Size) (aSize);
     5320
     5321    *aSize = mSize;
     5322    return S_OK;
     5323}
     5324
     5325STDMETHODIMP HVHDImage::COMGETTER(ActualSize) (ULONG64 *aActualSize)
     5326{
     5327    if (!aActualSize)
     5328        return E_POINTER;
     5329
     5330    AutoLock alock (this);
     5331    CHECK_READY();
     5332
     5333    *aActualSize = mActualSize;
     5334    return S_OK;
     5335}
     5336
     5337// IVirtualDiskImage properties
     5338////////////////////////////////////////////////////////////////////////////////
     5339
     5340STDMETHODIMP HVHDImage::COMGETTER(FilePath) (BSTR *aFilePath)
     5341{
     5342    if (!aFilePath)
     5343        return E_POINTER;
     5344
     5345    AutoLock alock (this);
     5346    CHECK_READY();
     5347
     5348    mFilePathFull.cloneTo (aFilePath);
     5349    return S_OK;
     5350}
     5351
     5352STDMETHODIMP HVHDImage::COMSETTER(FilePath) (INPTR BSTR aFilePath)
     5353{
     5354    AutoLock alock (this);
     5355    CHECK_READY();
     5356
     5357    if (mState != NotCreated)
     5358        return setError (E_ACCESSDENIED,
     5359            tr ("Cannot change the file path of the existing hard disk '%ls'"),
     5360            toString().raw());
     5361
     5362    CHECK_BUSY_AND_READERS();
     5363
     5364    /* append the default path if only a name is given */
     5365    Bstr path = aFilePath;
     5366    if (aFilePath && *aFilePath)
     5367    {
     5368        Utf8Str fp = aFilePath;
     5369        if (!RTPathHavePath (fp))
     5370        {
     5371            AutoReaderLock propsLock (mVirtualBox->systemProperties());
     5372            path = Utf8StrFmt ("%ls%c%s",
     5373                               mVirtualBox->systemProperties()->defaultVDIFolder().raw(),
     5374                               RTPATH_DELIMITER,
     5375                               fp.raw());
     5376        }
     5377    }
     5378
     5379    return setFilePath (path);
     5380}
     5381
     5382STDMETHODIMP HVHDImage::COMGETTER(Created) (BOOL *aCreated)
     5383{
     5384    if (!aCreated)
     5385        return E_POINTER;
     5386
     5387    AutoLock alock (this);
     5388    CHECK_READY();
     5389
     5390    *aCreated = mState >= Created;
     5391    return S_OK;
     5392}
     5393
     5394// IVHDImage methods
     5395/////////////////////////////////////////////////////////////////////////////
     5396
     5397STDMETHODIMP HVHDImage::CreateDynamicImage (ULONG64 aSize, IProgress **aProgress)
     5398{
     5399    if (!aProgress)
     5400        return E_POINTER;
     5401
     5402    AutoLock alock (this);
     5403    CHECK_READY();
     5404
     5405    return createImage (aSize, TRUE /* aDynamic */, aProgress);
     5406}
     5407
     5408STDMETHODIMP HVHDImage::CreateFixedImage (ULONG64 aSize, IProgress **aProgress)
     5409{
     5410    if (!aProgress)
     5411        return E_POINTER;
     5412
     5413    AutoLock alock (this);
     5414    CHECK_READY();
     5415
     5416    return createImage (aSize, FALSE /* aDynamic */, aProgress);
     5417}
     5418
     5419STDMETHODIMP HVHDImage::DeleteImage()
     5420{
     5421    AutoLock alock (this);
     5422    CHECK_READY();
     5423    CHECK_BUSY_AND_READERS();
     5424
     5425    return E_NOTIMPL;
     5426
     5427/// @todo later
     5428// We will need to parse the file in order to delete all related delta and
     5429// sparse images etc. We may also want to obey the .vmdk.lck file
     5430// which is (as far as I understood) created when the VMware VM is
     5431// running or saved etc.
     5432//
     5433//     if (mRegistered)
     5434//         return setError (E_ACCESSDENIED,
     5435//              tr ("Cannot delete an image of the registered hard disk image '%ls"),
     5436//              mFilePathFull.raw());
     5437//     if (mState == NotCreated)
     5438//         return setError (E_FAIL,
     5439//              tr ("Hard disk image has been already deleted or never created"));
     5440//
     5441//     int vrc = RTFileDelete (Utf8Str (mFilePathFull));
     5442//     if (VBOX_FAILURE (vrc))
     5443//         return setError (E_FAIL, tr ("Could not delete the image file '%ls' (%Vrc)"),
     5444//                          mFilePathFull.raw(), vrc);
     5445//
     5446//     mState = NotCreated;
     5447//
     5448//     /* reset the fields */
     5449//     mSize = 0;
     5450//     mActualSize = 0;
     5451//
     5452//     return S_OK;
     5453}
     5454
     5455// public/protected methods for internal purposes only
     5456/////////////////////////////////////////////////////////////////////////////
     5457
     5458/**
     5459 *  Attempts to mark the hard disk as registered.
     5460 *  Only VirtualBox can call this method.
     5461 */
     5462HRESULT HVHDImage::trySetRegistered (BOOL aRegistered)
     5463{
     5464    AutoLock alock (this);
     5465    CHECK_READY();
     5466
     5467    if (aRegistered)
     5468    {
     5469        if (mState == NotCreated)
     5470            return setError (E_FAIL,
     5471                tr ("Image file '%ls' is not yet created for this hard disk"),
     5472                mFilePathFull.raw());
     5473
     5474/// @todo will need this if we add suppord for differencing VHDs
     5475//         if (isDifferencing())
     5476//             return setError (E_FAIL,
     5477//                 tr ("Hard disk '%ls' is differencing and cannot be unregistered "
     5478//                     "explicitly"),
     5479//                 mFilePathFull.raw());
     5480    }
     5481    else
     5482    {
     5483        ComAssertRet (mState >= Created, E_FAIL);
     5484    }
     5485
     5486    return HardDisk::trySetRegistered (aRegistered);
     5487}
     5488
     5489/**
     5490 *  Checks accessibility of this hard disk image only (w/o parents).
     5491 *
     5492 *  @param aAccessError on output, a null string indicates the hard disk is
     5493 *                      accessible, otherwise contains a message describing
     5494 *                      the reason of inaccessibility.
     5495 */
     5496HRESULT HVHDImage::getAccessible (Bstr &aAccessError)
     5497{
     5498    AutoLock alock (this);
     5499    CHECK_READY();
     5500
     5501    if (mStateCheckSem != NIL_RTSEMEVENTMULTI)
     5502    {
     5503        /* An accessibility check in progress on some other thread,
     5504         * wait for it to finish. */
     5505
     5506        ComAssertRet (mStateCheckWaiters != (ULONG) ~0, E_FAIL);
     5507        ++ mStateCheckWaiters;
     5508        alock.leave();
     5509
     5510        int vrc = RTSemEventMultiWait (mStateCheckSem, RT_INDEFINITE_WAIT);
     5511
     5512        alock.enter();
     5513        AssertReturn (mStateCheckWaiters != 0, E_FAIL);
     5514        -- mStateCheckWaiters;
     5515        if (mStateCheckWaiters == 0)
     5516        {
     5517            RTSemEventMultiDestroy (mStateCheckSem);
     5518            mStateCheckSem = NIL_RTSEMEVENTMULTI;
     5519        }
     5520
     5521        AssertRCReturn (vrc, E_FAIL);
     5522
     5523        /* don't touch aAccessError, it has been already set */
     5524        return S_OK;
     5525    }
     5526
     5527    /* check the basic accessibility */
     5528    HRESULT rc = getBaseAccessible (aAccessError, true /* aCheckBusy */);
     5529    if (FAILED (rc) || !aAccessError.isNull())
     5530        return rc;
     5531
     5532    if (mState >= Created)
     5533    {
     5534        return queryInformation (&aAccessError);
     5535    }
     5536
     5537    aAccessError = Utf8StrFmt ("Hard disk image '%ls' is not yet created",
     5538                               mFilePathFull.raw());
     5539    return S_OK;
     5540}
     5541
     5542/**
     5543 *  Saves hard disk settings to the specified storage node and saves
     5544 *  all children to the specified hard disk node
     5545 *
     5546 *  @param aHDNode      <HardDisk> or <DiffHardDisk> node
     5547 *  @param aStorageNode <VirtualDiskImage> node
     5548 */
     5549HRESULT HVHDImage::saveSettings (settings::Key &aHDNode, settings::Key &aStorageNode)
     5550{
     5551    AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL);
     5552
     5553    AutoLock alock (this);
     5554    CHECK_READY();
     5555
     5556    /* filePath (required) */
     5557    aStorageNode.setValue <Bstr> ("filePath", mFilePath);
     5558
     5559    /* save basic settings and children */
     5560    return HardDisk::saveSettings (aHDNode);
     5561}
     5562
     5563/**
     5564 *  Checks if the given change of \a aOldPath to \a aNewPath affects the path
     5565 *  of this hard disk and updates it if necessary to reflect the new location.
     5566 *  Intended to be from HardDisk::updatePaths().
     5567 *
     5568 *  @param aOldPath old path (full)
     5569 *  @param aNewPath new path (full)
     5570 *
     5571 *  @note Locks this object for writing.
     5572 */
     5573void HVHDImage::updatePath (const char *aOldPath, const char *aNewPath)
     5574{
     5575    AssertReturnVoid (aOldPath);
     5576    AssertReturnVoid (aNewPath);
     5577
     5578    AutoLock alock (this);
     5579    AssertReturnVoid (isReady());
     5580
     5581    size_t oldPathLen = strlen (aOldPath);
     5582
     5583    Utf8Str path = mFilePathFull;
     5584    LogFlowThisFunc (("VHD.fullPath={%s}\n", path.raw()));
     5585
     5586    if (RTPathStartsWith (path, aOldPath))
     5587    {
     5588        Utf8Str newPath = Utf8StrFmt ("%s%s", aNewPath,
     5589                                              path.raw() + oldPathLen);
     5590        path = newPath;
     5591
     5592        mVirtualBox->calculateRelativePath (path, path);
     5593
     5594        unconst (mFilePathFull) = newPath;
     5595        unconst (mFilePath) = path;
     5596
     5597        LogFlowThisFunc (("-> updated: full={%s} short={%s}\n",
     5598                          newPath.raw(), path.raw()));
     5599    }
     5600}
     5601
     5602/**
     5603 *  Returns the string representation of this hard disk.
     5604 *  When \a aShort is false, returns the full image file path.
     5605 *  Otherwise, returns the image file name only.
     5606 *
     5607 *  @param aShort       if true, a short representation is returned
     5608 */
     5609Bstr HVHDImage::toString (bool aShort /* = false */)
     5610{
     5611    AutoLock alock (this);
     5612
     5613    if (!aShort)
     5614        return mFilePathFull;
     5615    else
     5616    {
     5617        Utf8Str fname = mFilePathFull;
     5618        return RTPathFilename (fname.mutableRaw());
     5619    }
     5620}
     5621
     5622/**
     5623 *  Creates a clone of this hard disk by storing hard disk data in the given
     5624 *  VDI file.
     5625 *
     5626 *  If the operation fails, @a aDeleteTarget will be set to @c true unless the
     5627 *  failure happened because the target file already existed.
     5628 *
     5629 *  @param aId              UUID to assign to the created image.
     5630 *  @param aTargetPath      VDI file where the cloned image is to be to stored.
     5631 *  @param aProgress        progress object to run during operation.
     5632 *  @param aDeleteTarget    Whether it is recommended to delete target on
     5633 *                          failure or not.
     5634 */
     5635HRESULT
     5636HVHDImage::cloneToImage (const Guid &aId, const Utf8Str &aTargetPath,
     5637                          Progress *aProgress, bool &aDeleteTarget)
     5638{
     5639    ComAssertMsgFailed (("Not implemented"));
     5640    return E_NOTIMPL;
     5641
     5642/// @todo will need this if we add suppord for differencing VHDs
     5643//  Use code from HVirtualDiskImage::cloneToImage as an example.
     5644}
     5645
     5646/**
     5647 *  Creates a new differencing image for this hard disk with the given
     5648 *  VDI file name.
     5649 *
     5650 *  @param aId          UUID to assign to the created image
     5651 *  @param aTargetPath  VDI file where to store the created differencing image
     5652 *  @param aProgress    progress object to run during operation
     5653 *                      (can be NULL)
     5654 */
     5655HRESULT
     5656HVHDImage::createDiffImage (const Guid &aId, const Utf8Str &aTargetPath,
     5657                             Progress *aProgress)
     5658{
     5659    ComAssertMsgFailed (("Not implemented"));
     5660    return E_NOTIMPL;
     5661
     5662/// @todo will need this if we add suppord for differencing VHDs
     5663//  Use code from HVirtualDiskImage::createDiffImage as an example.
     5664}
     5665
     5666// private methods
     5667/////////////////////////////////////////////////////////////////////////////
     5668
     5669/**
     5670 *  Helper to set a new file path.
     5671 *  Resolves a path relatively to the Virtual Box home directory.
     5672 *
     5673 *  @note
     5674 *      Must be called from under the object's lock!
     5675 */
     5676HRESULT HVHDImage::setFilePath (const BSTR aFilePath)
     5677{
     5678    if (aFilePath && *aFilePath)
     5679    {
     5680        /* get the full file name */
     5681        char filePathFull [RTPATH_MAX];
     5682        int vrc = RTPathAbsEx (mVirtualBox->homeDir(), Utf8Str (aFilePath),
     5683                               filePathFull, sizeof (filePathFull));
     5684        if (VBOX_FAILURE (vrc))
     5685            return setError (E_FAIL,
     5686                tr ("Invalid image file path '%ls' (%Vrc)"), aFilePath, vrc);
     5687
     5688        mFilePath = aFilePath;
     5689        mFilePathFull = filePathFull;
     5690    }
     5691    else
     5692    {
     5693        mFilePath.setNull();
     5694        mFilePathFull.setNull();
     5695    }
     5696
     5697    return S_OK;
     5698}
     5699
     5700/**
     5701 *  Helper to query information about the VDI hard disk.
     5702 *
     5703 *  @param aAccessError not used when NULL, otherwise see #getAccessible()
     5704 *
     5705 *  @note Must be called from under the object's lock, only after
     5706 *        CHECK_BUSY_AND_READERS() succeeds.
     5707 */
     5708HRESULT HVHDImage::queryInformation (Bstr *aAccessError)
     5709{
     5710    AssertReturn (isLockedOnCurrentThread(), E_FAIL);
     5711
     5712    /* create a lock object to completely release it later */
     5713    AutoLock alock (this);
     5714
     5715    AssertReturn (mStateCheckWaiters == 0, E_FAIL);
     5716
     5717    ComAssertRet (mState >= Created, E_FAIL);
     5718
     5719    HRESULT rc = S_OK;
     5720    int vrc = VINF_SUCCESS;
     5721
     5722    /* lazily create a semaphore */
     5723    vrc = RTSemEventMultiCreate (&mStateCheckSem);
     5724    ComAssertRCRet (vrc, E_FAIL);
     5725
     5726    /* Reference the disk to prevent any concurrent modifications
     5727     * after releasing the lock below (to unblock getters before
     5728     * a lengthy operation). */
     5729    addReader();
     5730
     5731    alock.leave();
     5732
     5733    /* VBoxVHDD management interface needs to be optimized: we're opening a
     5734     * file three times in a raw to get three bits of information. */
     5735
     5736    Utf8Str filePath = mFilePathFull;
     5737    Bstr errMsg;
     5738
     5739    /* reset any previous error report from VDError() */
     5740    mLastVDError.setNull();
     5741
     5742    do
     5743    {
     5744        Guid id, parentId;
     5745
     5746        /// @todo changed from VD_OPEN_FLAGS_READONLY to VD_OPEN_FLAGS_NORMAL,
     5747        /// because otherwise registering a VHD which so far has no UUID will
     5748        /// yield a null UUID. It cannot be added to a VHD opened readonly,
     5749        /// obviously. This of course changes locking behavior, but for now
     5750        /// this is acceptable. A better solution needs to be found later.
     5751        vrc = VDOpen (mContainer, filePath, VD_OPEN_FLAGS_NORMAL);
     5752        if (VBOX_FAILURE (vrc))
     5753            break;
     5754
     5755        vrc = VDGetUuid (mContainer, 0, id.ptr());
     5756        if (VBOX_FAILURE (vrc))
     5757            break;
     5758        vrc = VDGetParentUuid (mContainer, 0, parentId.ptr());
     5759        if (VBOX_FAILURE (vrc))
     5760            break;
     5761
     5762        if (!mId.isEmpty())
     5763        {
     5764            /* check that the actual UUID of the image matches the stored UUID */
     5765            if (mId != id)
     5766            {
     5767                errMsg = Utf8StrFmt (
     5768                    tr ("Actual UUID {%Vuuid} of the hard disk image '%s' doesn't "
     5769                        "match UUID {%Vuuid} stored in the registry"),
     5770                    id.ptr(), filePath.raw(), mId.ptr());
     5771                break;
     5772            }
     5773        }
     5774        else
     5775        {
     5776            /* assgn an UUID read from the image file */
     5777            mId = id;
     5778        }
     5779
     5780        if (mParent)
     5781        {
     5782            /* check parent UUID */
     5783            AutoLock parentLock (mParent);
     5784            if (mParent->id() != parentId)
     5785            {
     5786                errMsg = Utf8StrFmt (
     5787                    tr ("UUID {%Vuuid} of the parent image '%ls' stored in "
     5788                        "the hard disk image file '%s' doesn't match "
     5789                        "UUID {%Vuuid} stored in the registry"),
     5790                    parentId.raw(), mParent->toString().raw(),
     5791                    filePath.raw(), mParent->id().raw());
     5792                break;
     5793            }
     5794        }
     5795        else if (!parentId.isEmpty())
     5796        {
     5797            errMsg = Utf8StrFmt (
     5798                tr ("Hard disk image '%s' is a differencing image that is linked "
     5799                    "to a hard disk with UUID {%Vuuid} and cannot be used "
     5800                    "directly as a base hard disk"),
     5801                filePath.raw(), parentId.raw());
     5802            break;
     5803        }
     5804
     5805        /* get actual file size */
     5806        /// @todo is there a direct method in RT?
     5807        {
     5808            RTFILE file = NIL_RTFILE;
     5809            vrc = RTFileOpen (&file, filePath, RTFILE_O_READ);
     5810            if (VBOX_SUCCESS (vrc))
     5811            {
     5812                uint64_t size = 0;
     5813                vrc = RTFileGetSize (file, &size);
     5814                if (VBOX_SUCCESS (vrc))
     5815                    mActualSize = size;
     5816                RTFileClose (file);
     5817            }
     5818            if (VBOX_FAILURE (vrc))
     5819                break;
     5820        }
     5821
     5822        /* query logical size only for non-differencing images */
     5823        if (!mParent)
     5824        {
     5825            uint64_t size = VDGetSize (mContainer);
     5826            /* convert to MBytes */
     5827            mSize = size / 1024 / 1024;
     5828        }
     5829    }
     5830    while (0);
     5831
     5832    VDCloseAll (mContainer);
     5833
     5834    /* enter the lock again */
     5835    alock.enter();
     5836
     5837    /* remove the reference */
     5838    releaseReader();
     5839
     5840    if (FAILED (rc) || VBOX_FAILURE (vrc) || !errMsg.isNull())
     5841    {
     5842        LogWarningFunc (("'%ls' is not accessible "
     5843                         "(rc=%08X, vrc=%Vrc, errMsg='%ls')\n",
     5844                         mFilePathFull.raw(), rc, vrc, errMsg.raw()));
     5845
     5846        if (aAccessError)
     5847        {
     5848            if (!errMsg.isNull())
     5849                *aAccessError = errMsg;
     5850            else if (!mLastVDError.isNull())
     5851                *aAccessError = mLastVDError;
     5852            else if (VBOX_FAILURE (vrc))
     5853                *aAccessError = Utf8StrFmt (
     5854                    tr ("Could not access hard disk image '%ls' (%Vrc)"),
     5855                        mFilePathFull.raw(), vrc);
     5856        }
     5857
     5858        /* downgrade to not accessible */
     5859        mState = Created;
     5860    }
     5861    else
     5862    {
     5863        if (aAccessError)
     5864            aAccessError->setNull();
     5865
     5866        mState = Accessible;
     5867    }
     5868
     5869    /* inform waiters if there are any */
     5870    if (mStateCheckWaiters > 0)
     5871    {
     5872        RTSemEventMultiSignal (mStateCheckSem);
     5873    }
     5874    else
     5875    {
     5876        /* delete the semaphore ourselves */
     5877        RTSemEventMultiDestroy (mStateCheckSem);
     5878        mStateCheckSem = NIL_RTSEMEVENTMULTI;
     5879    }
     5880
     5881    /* cleanup the last error report from VDError() */
     5882    mLastVDError.setNull();
     5883
     5884    return rc;
     5885}
     5886
     5887/**
     5888 *  Helper to create hard disk images.
     5889 *
     5890 *  @param aSize        size in MB
     5891 *  @param aDynamic     dynamic or fixed image
     5892 *  @param aProgress    address of IProgress pointer to return
     5893 */
     5894HRESULT HVHDImage::createImage (ULONG64 aSize, BOOL aDynamic,
     5895                                 IProgress **aProgress)
     5896{
     5897    ComAssertMsgFailed (("Not implemented"));
     5898    return E_NOTIMPL;
     5899
     5900/// @todo later
     5901//  Use code from HVirtualDiskImage::createImage as an example.
     5902}
     5903
     5904/* static */
     5905DECLCALLBACK(int) HVHDImage::VDITaskThread (RTTHREAD thread, void *pvUser)
     5906{
     5907    AssertMsgFailed (("Not implemented"));
     5908    return VERR_GENERAL_FAILURE;
     5909
     5910/// @todo later
     5911//  Use code from HVirtualDiskImage::VDITaskThread as an example.
     5912}
     5913
     5914/* static */
     5915DECLCALLBACK(void) HVHDImage::VDError (void *pvUser, int rc, RT_SRC_POS_DECL,
     5916                                        const char *pszFormat, va_list va)
     5917{
     5918    HVHDImage *that = static_cast <HVHDImage *> (pvUser);
     5919    AssertReturnVoid (that != NULL);
     5920
     5921    /// @todo pass the error message to the operation initiator
     5922    Utf8Str err = Utf8StrFmt (pszFormat, va);
     5923    if (VBOX_FAILURE (rc))
     5924        err = Utf8StrFmt ("%s (%Vrc)", err.raw(), rc);
     5925
     5926    if (that->mLastVDError.isNull())
     5927        that->mLastVDError = err;
     5928    else
    50455929        that->mLastVDError = Utf8StrFmt
    50465930            ("%s.\n%s", that->mLastVDError.raw(), err.raw());
  • trunk/src/VBox/Main/VirtualBoxImpl.cpp

    r6076 r6173  
    959959            break;
    960960       }
     961       case HardDiskStorageType_VHDImage:
     962       {
     963            ComObjPtr <HVHDImage> vhd;
     964            vhd.createObject();
     965            rc = vhd->init (this, NULL, NULL);
     966            hardDisk = vhd;
     967            break;
     968       }
    961969       default:
    962970           AssertFailed();
     
    30283036
    30293037            if (hd->storageType() == HardDiskStorageType_VirtualDiskImage ||
    3030                 hd->storageType() == HardDiskStorageType_VMDKImage)
     3038                hd->storageType() == HardDiskStorageType_VMDKImage ||
     3039                hd->storageType() == HardDiskStorageType_VHDImage)
    30313040            {
    30323041                /* locations of VDI and VMDK hard disks for now are just
     
    35553564            }
    35563565
     3566            storageNode = (*it).findKey ("VHDImage");
     3567            if (!storageNode.isNull())
     3568            {
     3569                ComObjPtr <HVHDImage> vhd;
     3570                vhd.createObject();
     3571                rc = vhd->init (this, NULL, (*it), storageNode);
     3572                break;
     3573            }
     3574
    35573575            ComAssertMsgFailedBreak (("No valid hard disk storage node!\n"),
    35583576                                     rc = E_FAIL);
     
    37373755            {
    37383756                Key storageNode = hdNode.createKey ("CustomHardDisk");
     3757                rc = hd->saveSettings (hdNode, storageNode);
     3758                break;
     3759            }
     3760
     3761            case HardDiskStorageType_VHDImage:
     3762            {
     3763                Key storageNode = hdNode.createKey ("VHDImage");
    37393764                rc = hd->saveSettings (hdNode, storageNode);
    37403765                break;
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r6168 r6173  
    52945294      </desc>
    52955295    </const>
     5296    <const name="VHDImage" value="4">
     5297      <desc>
     5298        Virtual PC Virtual Machine Disk image (a regular file in the file
     5299        system of the host OS, see <link to="IVHDImage"/>)
     5300      </desc>
     5301    </const>
    52965302  </enum>
    52975303
     
    54105416          when the disk is accessed (represented by the
    54115417          <link to="ICustomHardDisk"/> interface).
     5418        </li>
     5419
     5420        <li>
     5421          <i>Virtual PC VHD Image</i>, a regular file in the file system of the
     5422          host OS (represented by the <link to="IVHDImage"/> interface).
    54125423        </li>
    54135424
     
    64296440          operation is complete, this hard disk object can be
    64306441          <link to="IVirtualBox::registerHardDisk()">registered</link> within
     6442          this VirtualBox installation.
     6443        </note>
     6444
     6445      </desc>
     6446
     6447      <param name="size" type="unsigned long long" dir="in">
     6448        <desc>Maximum logical size of the hard disk in megabytes.</desc>
     6449      </param>
     6450      <param name="progress" type="IProgress" dir="return">
     6451        <desc>Progress object to track the operation completion.</desc>
     6452      </param>
     6453
     6454    </method>
     6455
     6456    <method name="createFixedImage">
     6457      <desc>
     6458
     6459        Starts creating a fixed-size hard disk image in the background.  The
     6460        previous image, if any, must be deleted using
     6461        <link to="#deleteImage"/>, otherwise the operation will fail.
     6462
     6463        <note>
     6464          After the returned progress object reports that the
     6465          operation is complete, this hard disk object can be
     6466          <link to="IVirtualBox::registerHardDisk()">registered</link> within
     6467          this VirtualBox installation.
     6468        </note>
     6469
     6470      </desc>
     6471
     6472      <param name="size" type="unsigned long long" dir="in">
     6473        <desc>Logical size of the hard disk in megabytes.</desc>
     6474      </param>
     6475      <param name="progress" type="IProgress" dir="return">
     6476        <desc>Progress object to track the operation completion.</desc>
     6477      </param>
     6478
     6479    </method>
     6480
     6481    <method name="deleteImage">
     6482      <desc>
     6483
     6484        Deletes the existing hard disk image. The hard disk must not be
     6485        registered within this VirtualBox installation, otherwise the
     6486        operation will fail.
     6487
     6488        <note>
     6489          After this operation succeeds, it will be impossible to register the
     6490          hard disk until the image file is created again.
     6491        </note>
     6492
     6493        <note>
     6494          This operation is valid only for non-differencing hard disks, after
     6495          they are unregistered using
     6496          <link to="IVirtualBox::unregisterHardDisk()"/>.
     6497        </note>
     6498
     6499      </desc>
     6500    </method>
     6501
     6502  </interface>
     6503
     6504  <!--
     6505  // IVHDImage
     6506  /////////////////////////////////////////////////////////////////////////
     6507  -->
     6508
     6509  <interface
     6510     name="IVHDImage" extends="$unknown"
     6511     uuid="163b88c3-7552-424a-8205-daf17a004747"
     6512     wsmap="managed"
     6513     >
     6514    <desc>
     6515
     6516      The IVHDImage interface represents <link to="IHardDisk">virtual hard
     6517      disks</link> that use Virtual PC Virtual Machine Disk image files to store
     6518      hard disk data.
     6519
     6520      Hard disks using VHD images can be either opened using
     6521      <link to="IVirtualBox::openHardDisk()"/> or created from
     6522      scratch using <link to="IVirtualBox::createHardDisk()"/>.
     6523
     6524      Objects that support this interface also support the
     6525      <link to="IHardDisk"/> interface.
     6526
     6527      When a new hard disk object is created from scatch, an image file for it
     6528      is not automatically created. To do it, you need to specify a
     6529      valid <link to="#filePath">file path</link>, and call
     6530      <link to="#createFixedImage()"/> or <link to="#createDynamicImage()"/>.
     6531      When it is done, the hard disk object can be registered by calling
     6532      <link to="IVirtualBox::registerHardDisk()"/> and then
     6533      <link to="IMachine::attachHardDisk()">attached</link> to
     6534      virtual machines.
     6535
     6536      The <link to="IHardDisk::description">description</link>
     6537      of the VHD hard disk is stored in the VirtualBox
     6538      configuration file, so it can be changed (at appropriate
     6539      times) even when
     6540      <link to="IHardDisk::accessible">accessible</link> returns
     6541      <tt>false</tt>.  However, the hard disk must not be
     6542      attached to a running virtual machine.
     6543
     6544      <note>
     6545        In the current imlementation, the type of all VHD hard disks
     6546        is <link to="HardDiskType::WritethroughHardDisk">Writethrough</link>
     6547        and cannot be changed.
     6548      </note>
     6549
     6550    </desc>
     6551
     6552    <attribute name="filePath" type="wstring">
     6553      <desc>
     6554
     6555        Full file name of the VHD image of this hard disk. For
     6556        newly created hard disk objects, this value is <tt>null</tt>.
     6557
     6558        When assigning a new path, it can be absolute (full path) or relative
     6559        to the <link to="IVirtualBox::homeFolder"> VirtualBox home
     6560        directory</link>. If only a file name without any path is given,
     6561        the <link to="ISystemProperties::defaultVDIFolder"> default VDI
     6562        folder</link> will be used as a path to the image file.
     6563
     6564        When reading this propery, a full path is always returned.
     6565
     6566        <note>
     6567          This property cannot be changed when <link to="#created"/>
     6568          returns <tt>true</tt>. In this case, the specified file name can be
     6569          absolute (full path) or relative to
     6570          the <link to="IVirtualBox::homeFolder"> VirtualBox home
     6571          directory</link>.  If only a file name without any path is given,
     6572          the <link to="ISystemProperties::defaultVDIFolder"> default VDI
     6573          folder</link> will be used as a path to the image file.
     6574        </note>
     6575
     6576      </desc>
     6577    </attribute>
     6578
     6579    <attribute name="created" type="boolean" readonly="yes">
     6580      <desc>
     6581
     6582        Whether the virual disk image is created or not. For newly created
     6583        hard disk objects or after a successful invocation of
     6584        <link to="#deleteImage()"/>, this value is <tt>false</tt> until
     6585        <link to="#createFixedImage()"/> or <link to="#createDynamicImage()"/>
     6586        is called.
     6587
     6588      </desc>
     6589    </attribute>
     6590
     6591    <method name="createDynamicImage">
     6592
     6593      <desc>
     6594
     6595        Starts creating a dymically expanding hard disk image in the
     6596        background. The previous image associated with this object, if
     6597        any, must be deleted using <link to="#deleteImage"/>, otherwise
     6598        the operation will fail.
     6599
     6600        <note>
     6601          After the returned progress object reports that the
     6602          operation is complete, this hard disk object can be
     6603         <link to="IVirtualBox::registerHardDisk()">registered</link> within
    64316604          this VirtualBox installation.
    64326605        </note>
  • trunk/src/VBox/Main/include/HardDiskImpl.h

    r6076 r6173  
    652652};
    653653
     654////////////////////////////////////////////////////////////////////////////////
     655 
     656class ATL_NO_VTABLE HVHDImage :
     657    public HardDisk,
     658    public VirtualBoxSupportTranslation <HVHDImage>,
     659    public IVHDImage
     660{
     661
     662public:
     663
     664    VIRTUALBOXSUPPORTTRANSLATION_OVERRIDE(HVHDImage)
     665
     666    DECLARE_NOT_AGGREGATABLE(HVHDImage)
     667
     668    DECLARE_PROTECT_FINAL_CONSTRUCT()
     669
     670    BEGIN_COM_MAP(HVMDKImage)
     671        COM_INTERFACE_ENTRY(ISupportErrorInfo)
     672        COM_INTERFACE_ENTRY(IHardDisk)
     673        COM_INTERFACE_ENTRY(IVHDImage)
     674    END_COM_MAP()
     675
     676    NS_DECL_ISUPPORTS
     677
     678    HRESULT FinalConstruct();
     679    void FinalRelease();
     680
     681    // public initializer/uninitializer for internal purposes only
     682
     683    HRESULT init (VirtualBox *aVirtualBox, HardDisk *aParent,
     684                  const settings::Key &aHDNode, const settings::Key &aVHDNode);
     685    HRESULT init (VirtualBox *aVirtualBox, HardDisk *aParent,
     686                  INPTR BSTR aFilePath, BOOL aRegistered = FALSE);
     687    void uninit();
     688
     689    // IHardDisk properties
     690    STDMETHOD(COMGETTER(Description)) (BSTR *aDescription);
     691    STDMETHOD(COMSETTER(Description)) (INPTR BSTR aDescription);
     692    STDMETHOD(COMGETTER(Size)) (ULONG64 *aSize);
     693    STDMETHOD(COMGETTER(ActualSize)) (ULONG64 *aActualSize);
     694
     695    // IVirtualDiskImage properties
     696    STDMETHOD(COMGETTER(FilePath)) (BSTR *aFilePath);
     697    STDMETHOD(COMSETTER(FilePath)) (INPTR BSTR aFilePath);
     698    STDMETHOD(COMGETTER(Created)) (BOOL *aCreated);
     699
     700    // IVirtualDiskImage methods
     701    STDMETHOD(CreateDynamicImage) (ULONG64 aSize, IProgress **aProgress);
     702    STDMETHOD(CreateFixedImage) (ULONG64 aSize, IProgress **aProgress);
     703    STDMETHOD(DeleteImage)();
     704
     705    // public methods for internal purposes only
     706
     707    const Bstr &filePath() const { return mFilePath; }
     708    const Bstr &filePathFull() const { return mFilePathFull; }
     709
     710    HRESULT trySetRegistered (BOOL aRegistered);
     711    HRESULT getAccessible (Bstr &aAccessError);
     712
     713    HRESULT saveSettings (settings::Key &aHDNode, settings::Key &aStorageNode);
     714
     715    void updatePath (const char *aOldPath, const char *aNewPath);
     716
     717    Bstr toString (bool aShort = false);
     718
     719    HRESULT cloneToImage (const Guid &aId, const Utf8Str &aTargetPath,
     720                          Progress *aProgress, bool &aDeleteTarget);
     721    HRESULT createDiffImage (const Guid &aId, const Utf8Str &aTargetPath,
     722                             Progress *aProgress);
     723
     724    // for VirtualBoxSupportErrorInfoImpl
     725    static const wchar_t *getComponentName() { return L"VHDImage"; }
     726
     727private:
     728
     729    HRESULT setFilePath (const BSTR aFilePath);
     730    HRESULT queryInformation (Bstr *aAccessError);
     731    HRESULT createImage (ULONG64 aSize, BOOL aDynamic, IProgress **aProgress);
     732
     733    /** VDI asynchronous operation thread function */
     734    static DECLCALLBACK(int) VDITaskThread (RTTHREAD thread, void *pvUser);
     735
     736    static DECLCALLBACK(void) VDError (void *pvUser, int rc, RT_SRC_POS_DECL,
     737                                       const char *pszFormat, va_list va);
     738
     739    enum State
     740    {
     741        NotCreated,
     742        Created,
     743        /* the following must be greater than Created */
     744        Accessible,
     745    };
     746
     747    State mState;
     748   
     749    RTSEMEVENTMULTI mStateCheckSem;
     750    ULONG mStateCheckWaiters;
     751
     752    Bstr mDescription;
     753
     754    ULONG64 mSize;
     755    ULONG64 mActualSize;
     756
     757    Bstr mFilePath;
     758    Bstr mFilePathFull;
     759
     760    PVBOXHDD mContainer;
     761
     762    Utf8Str mLastVDError;
     763
     764    friend class HardDisk;
     765};
     766
    654767
    655768COM_DECL_READONLY_ENUM_AND_COLLECTION (HardDisk)
  • trunk/src/VBox/Main/linux/server.cpp

    r5999 r6173  
    122122NS_DECL_CLASSINFO(HCustomHardDisk)
    123123NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HCustomHardDisk, IHardDisk, ICustomHardDisk)
     124NS_DECL_CLASSINFO(HVHDImage)
     125NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HVHDImage, IHardDisk, IVHDImage)
    124126NS_DECL_CLASSINFO(HardDiskAttachment)
    125127NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HardDiskAttachment, IHardDiskAttachment)
  • trunk/src/VBox/Main/xml/VirtualBox-settings-common.xsd

    r6076 r6173  
    268268        </xsd:complexType>
    269269      </xsd:element>
     270      <xsd:element name="VHDImage">
     271        <xsd:complexType>
     272          <xsd:attribute name="filePath" type="TLocalFile" use="required"/>
     273        </xsd:complexType>
     274      </xsd:element>
    270275    </xsd:choice>
    271276    <xsd:element name="DiffHardDisk" type="TDiffHardDisk" minOccurs="0" maxOccurs="unbounded"/>
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