Changeset 6173 in vbox for trunk/src/VBox/Main
- Timestamp:
- Dec 21, 2007 6:57:02 PM (17 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/ConsoleImpl2.cpp
r6140 r6173 776 776 STR_CONV(); 777 777 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(); 778 791 STR_FREE(); 779 792 } -
trunk/src/VBox/Main/HardDiskImpl.cpp
r6076 r6173 1070 1070 { HardDiskStorageType_VMDKImage, ".vmdk" }, 1071 1071 { HardDiskStorageType_VirtualDiskImage, ".vdi" }, 1072 { HardDiskStorageType_VHDImage, ".vhd" }, 1072 1073 }; 1073 1074 … … 1138 1139 break; 1139 1140 } 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 } 1140 1154 default: 1141 1155 { … … 5043 5057 that->mLastVDError = err; 5044 5058 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 5070 HRESULT 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 5091 void 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 */ 5113 HRESULT 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 */ 5184 HRESULT 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 */ 5256 void 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 5270 STDMETHODIMP 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 5282 STDMETHODIMP 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 5307 STDMETHODIMP 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 5325 STDMETHODIMP 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 5340 STDMETHODIMP 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 5352 STDMETHODIMP 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 5382 STDMETHODIMP 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 5397 STDMETHODIMP 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 5408 STDMETHODIMP 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 5419 STDMETHODIMP 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 */ 5462 HRESULT 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 */ 5496 HRESULT 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 */ 5549 HRESULT 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 */ 5573 void 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 */ 5609 Bstr 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 */ 5635 HRESULT 5636 HVHDImage::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 */ 5655 HRESULT 5656 HVHDImage::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 */ 5676 HRESULT 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 */ 5708 HRESULT 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 */ 5894 HRESULT 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 */ 5905 DECLCALLBACK(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 */ 5915 DECLCALLBACK(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 5045 5929 that->mLastVDError = Utf8StrFmt 5046 5930 ("%s.\n%s", that->mLastVDError.raw(), err.raw()); -
trunk/src/VBox/Main/VirtualBoxImpl.cpp
r6076 r6173 959 959 break; 960 960 } 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 } 961 969 default: 962 970 AssertFailed(); … … 3028 3036 3029 3037 if (hd->storageType() == HardDiskStorageType_VirtualDiskImage || 3030 hd->storageType() == HardDiskStorageType_VMDKImage) 3038 hd->storageType() == HardDiskStorageType_VMDKImage || 3039 hd->storageType() == HardDiskStorageType_VHDImage) 3031 3040 { 3032 3041 /* locations of VDI and VMDK hard disks for now are just … … 3555 3564 } 3556 3565 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 3557 3575 ComAssertMsgFailedBreak (("No valid hard disk storage node!\n"), 3558 3576 rc = E_FAIL); … … 3737 3755 { 3738 3756 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"); 3739 3764 rc = hd->saveSettings (hdNode, storageNode); 3740 3765 break; -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r6168 r6173 5294 5294 </desc> 5295 5295 </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> 5296 5302 </enum> 5297 5303 … … 5410 5416 when the disk is accessed (represented by the 5411 5417 <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). 5412 5423 </li> 5413 5424 … … 6429 6440 operation is complete, this hard disk object can be 6430 6441 <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 6431 6604 this VirtualBox installation. 6432 6605 </note> -
trunk/src/VBox/Main/include/HardDiskImpl.h
r6076 r6173 652 652 }; 653 653 654 //////////////////////////////////////////////////////////////////////////////// 655 656 class ATL_NO_VTABLE HVHDImage : 657 public HardDisk, 658 public VirtualBoxSupportTranslation <HVHDImage>, 659 public IVHDImage 660 { 661 662 public: 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 727 private: 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 654 767 655 768 COM_DECL_READONLY_ENUM_AND_COLLECTION (HardDisk) -
trunk/src/VBox/Main/linux/server.cpp
r5999 r6173 122 122 NS_DECL_CLASSINFO(HCustomHardDisk) 123 123 NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HCustomHardDisk, IHardDisk, ICustomHardDisk) 124 NS_DECL_CLASSINFO(HVHDImage) 125 NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HVHDImage, IHardDisk, IVHDImage) 124 126 NS_DECL_CLASSINFO(HardDiskAttachment) 125 127 NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HardDiskAttachment, IHardDiskAttachment) -
trunk/src/VBox/Main/xml/VirtualBox-settings-common.xsd
r6076 r6173 268 268 </xsd:complexType> 269 269 </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> 270 275 </xsd:choice> 271 276 <xsd:element name="DiffHardDisk" type="TDiffHardDisk" minOccurs="0" maxOccurs="unbounded"/>
Note:
See TracChangeset
for help on using the changeset viewer.