- Timestamp:
- Oct 13, 2010 2:00:08 PM (14 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/MediumImpl.cpp
r33082 r33107 611 611 }; 612 612 613 class Medium::ImportTask : public Medium::Task 614 { 615 public: 616 ImportTask(Medium *aMedium, 617 Progress *aProgress, 618 const char *aFilename, 619 MediumFormat *aFormat, 620 MediumVariant_T aVariant, 621 void *aVDImageIOCallbacks, 622 void *aVDImageIOUser, 623 Medium *aParent, 624 MediumLockList *aTargetMediumLockList, 625 bool fKeepTargetMediumLockList = false) 626 : Medium::Task(aMedium, aProgress), 627 mFilename(aFilename), 628 mFormat(aFormat), 629 mVariant(aVariant), 630 mParent(aParent), 631 mpTargetMediumLockList(aTargetMediumLockList), 632 mParentCaller(aParent), 633 mfKeepTargetMediumLockList(fKeepTargetMediumLockList) 634 { 635 AssertReturnVoidStmt(aTargetMediumLockList != NULL, mRC = E_FAIL); 636 /* aParent may be NULL */ 637 mRC = mParentCaller.rc(); 638 if (FAILED(mRC)) 639 return; 640 641 mVDImageIfaces = aMedium->m->vdImageIfaces; 642 if (aVDImageIOCallbacks) 643 { 644 int vrc = VDInterfaceAdd(&mVDInterfaceIO, "Medium::vdInterfaceIO", 645 VDINTERFACETYPE_IO, aVDImageIOCallbacks, 646 aVDImageIOUser, &mVDImageIfaces); 647 AssertRCReturnVoidStmt(vrc, mRC = E_FAIL); 648 } 649 } 650 651 ~ImportTask() 652 { 653 if (!mfKeepTargetMediumLockList && mpTargetMediumLockList) 654 delete mpTargetMediumLockList; 655 } 656 657 Utf8Str mFilename; 658 ComObjPtr<MediumFormat> mFormat; 659 MediumVariant_T mVariant; 660 const ComObjPtr<Medium> mParent; 661 MediumLockList *mpTargetMediumLockList; 662 PVDINTERFACE mVDImageIfaces; 663 664 private: 665 virtual HRESULT handler(); 666 667 AutoCaller mParentCaller; 668 bool mfKeepTargetMediumLockList; 669 VDINTERFACE mVDInterfaceIO; 670 }; 671 613 672 /** 614 673 * Thread function for time-consuming medium tasks. … … 742 801 { 743 802 return mMedium->taskExportHandler(*this); 803 } 804 805 /** 806 * Implementation code for the "import" task. 807 */ 808 HRESULT Medium::ImportTask::handler() 809 { 810 return mMedium->taskImportHandler(*this); 744 811 } 745 812 … … 5169 5236 5170 5237 HRESULT Medium::exportFile(const char *aFilename, 5171 ComObjPtr<MediumFormat>aFormat,5238 const ComObjPtr<MediumFormat> &aFormat, 5172 5239 MediumVariant_T aVariant, 5173 5240 void *aVDImageIOCallbacks, void *aVDImageIOUser, 5174 ComObjPtr<Progress>aProgress)5241 const ComObjPtr<Progress> &aProgress) 5175 5242 { 5176 5243 AssertPtrReturn(aFilename, E_INVALIDARG); … … 5220 5287 if (FAILED(rc)) 5221 5288 throw rc; 5289 } 5290 catch (HRESULT aRC) { rc = aRC; } 5291 5292 if (SUCCEEDED(rc)) 5293 rc = startThread(pTask); 5294 else if (pTask != NULL) 5295 delete pTask; 5296 5297 return rc; 5298 } 5299 5300 HRESULT Medium::importFile(const char *aFilename, 5301 const ComObjPtr<MediumFormat> &aFormat, 5302 MediumVariant_T aVariant, 5303 void *aVDImageIOCallbacks, void *aVDImageIOUser, 5304 const ComObjPtr<Medium> &aParent, 5305 const ComObjPtr<Progress> &aProgress) 5306 { 5307 AssertPtrReturn(aFilename, E_INVALIDARG); 5308 AssertReturn(!aFormat.isNull(), E_INVALIDARG); 5309 AssertReturn(!aProgress.isNull(), E_INVALIDARG); 5310 5311 AutoCaller autoCaller(this); 5312 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 5313 5314 HRESULT rc = S_OK; 5315 Medium::Task *pTask = NULL; 5316 5317 try 5318 { 5319 // locking: we need the tree lock first because we access parent pointers 5320 AutoReadLock treeLock(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 5321 // and we need to write-lock the media involved 5322 AutoMultiWriteLock2 alock(this, aParent COMMA_LOCKVAL_SRC_POS); 5323 5324 if ( m->state != MediumState_NotCreated 5325 && m->state != MediumState_Created) 5326 throw setStateError(); 5327 5328 /* Build the target lock list. */ 5329 MediumLockList *pTargetMediumLockList(new MediumLockList()); 5330 rc = createMediumLockList(true /* fFailIfInaccessible */, 5331 true /* fMediumLockWrite */, 5332 aParent, 5333 *pTargetMediumLockList); 5334 if (FAILED(rc)) 5335 { 5336 delete pTargetMediumLockList; 5337 throw rc; 5338 } 5339 5340 rc = pTargetMediumLockList->Lock(); 5341 if (FAILED(rc)) 5342 { 5343 delete pTargetMediumLockList; 5344 throw setError(rc, 5345 tr("Failed to lock target media '%s'"), 5346 getLocationFull().c_str()); 5347 } 5348 5349 /* setup task object to carry out the operation asynchronously */ 5350 pTask = new Medium::ImportTask(this, aProgress, aFilename, aFormat, 5351 aVariant, aVDImageIOCallbacks, 5352 aVDImageIOUser, aParent, 5353 pTargetMediumLockList); 5354 rc = pTask->rc(); 5355 AssertComRC(rc); 5356 if (FAILED(rc)) 5357 throw rc; 5358 5359 if (m->state == MediumState_NotCreated) 5360 m->state = MediumState_Creating; 5222 5361 } 5223 5362 catch (HRESULT aRC) { rc = aRC; } … … 6447 6586 Utf8Str targetLocation(pTarget->m->strLocationFull); 6448 6587 6449 Assert( 6450 6588 Assert( pTarget->m->state == MediumState_Creating 6589 || pTarget->m->state == MediumState_LockedWrite); 6451 6590 Assert(m->state == MediumState_LockedRead); 6452 Assert(pParent.isNull() || pParent->m->state == MediumState_LockedRead); 6591 Assert( pParent.isNull() 6592 || pParent->m->state == MediumState_LockedRead); 6453 6593 6454 6594 /* unlock before the potentially lengthy operation */ … … 7067 7207 Assert(pMedium->m->state == MediumState_LockedRead); 7068 7208 7069 /* *Open all media in read-only mode. */7209 /* Open all media in read-only mode. */ 7070 7210 vrc = VDOpen(hdd, 7071 7211 pMedium->m->strFormat.c_str(), … … 7137 7277 } 7138 7278 7279 /** 7280 * Implementation code for the "import" task. 7281 * 7282 * This only gets started from Medium::importFile() and always runs 7283 * asynchronously. It potentially touches the media registry, so we 7284 * always save the VirtualBox.xml file when we're done here. 7285 * 7286 * @param task 7287 * @return 7288 */ 7289 HRESULT Medium::taskImportHandler(Medium::ImportTask &task) 7290 { 7291 HRESULT rc = S_OK; 7292 7293 const ComObjPtr<Medium> &pParent = task.mParent; 7294 7295 bool fCreatingTarget = false; 7296 7297 uint64_t size = 0, logicalSize = 0; 7298 MediumVariant_T variant = MediumVariant_Standard; 7299 bool fGenerateUuid = false; 7300 7301 try 7302 { 7303 /* Lock all in {parent,child} order. The lock is also used as a 7304 * signal from the task initiator (which releases it only after 7305 * RTThreadCreate()) that we can start the job. */ 7306 AutoMultiWriteLock2 thisLock(this, pParent COMMA_LOCKVAL_SRC_POS); 7307 7308 fCreatingTarget = m->state == MediumState_Creating; 7309 7310 /* The object may request a specific UUID (through a special form of 7311 * the setLocation() argument). Otherwise we have to generate it */ 7312 Guid targetId = m->id; 7313 fGenerateUuid = targetId.isEmpty(); 7314 if (fGenerateUuid) 7315 { 7316 targetId.create(); 7317 /* VirtualBox::registerHardDisk() will need UUID */ 7318 unconst(m->id) = targetId; 7319 } 7320 7321 7322 PVBOXHDD hdd; 7323 int vrc = VDCreate(m->vdDiskIfaces, &hdd); 7324 ComAssertRCThrow(vrc, E_FAIL); 7325 7326 try 7327 { 7328 /* Open source medium. */ 7329 rc = VDOpen(hdd, 7330 task.mFormat->getId().c_str(), 7331 task.mFilename.c_str(), 7332 VD_OPEN_FLAGS_READONLY, 7333 task.mVDImageIfaces); 7334 if (RT_FAILURE(vrc)) 7335 throw setError(VBOX_E_FILE_ERROR, 7336 tr("Could not open the medium storage unit '%s'%s"), 7337 task.mFilename.c_str(), 7338 vdError(vrc).c_str()); 7339 7340 Utf8Str targetFormat(m->strFormat); 7341 Utf8Str targetLocation(m->strLocationFull); 7342 7343 Assert( m->state == MediumState_Creating 7344 || m->state == MediumState_LockedWrite); 7345 Assert( pParent.isNull() 7346 || pParent->m->state == MediumState_LockedRead); 7347 7348 /* unlock before the potentially lengthy operation */ 7349 thisLock.release(); 7350 7351 /* ensure the target directory exists */ 7352 rc = VirtualBox::ensureFilePathExists(targetLocation); 7353 if (FAILED(rc)) 7354 throw rc; 7355 7356 PVBOXHDD targetHdd; 7357 vrc = VDCreate(m->vdDiskIfaces, &targetHdd); 7358 ComAssertRCThrow(vrc, E_FAIL); 7359 7360 try 7361 { 7362 /* Open all media in the target chain. */ 7363 MediumLockList::Base::const_iterator targetListBegin = 7364 task.mpTargetMediumLockList->GetBegin(); 7365 MediumLockList::Base::const_iterator targetListEnd = 7366 task.mpTargetMediumLockList->GetEnd(); 7367 for (MediumLockList::Base::const_iterator it = targetListBegin; 7368 it != targetListEnd; 7369 ++it) 7370 { 7371 const MediumLock &mediumLock = *it; 7372 const ComObjPtr<Medium> &pMedium = mediumLock.GetMedium(); 7373 7374 /* If the target medium is not created yet there's no 7375 * reason to open it. */ 7376 if (pMedium == this && fCreatingTarget) 7377 continue; 7378 7379 AutoReadLock alock(pMedium COMMA_LOCKVAL_SRC_POS); 7380 7381 /* sanity check */ 7382 Assert( pMedium->m->state == MediumState_LockedRead 7383 || pMedium->m->state == MediumState_LockedWrite); 7384 7385 unsigned uOpenFlags = VD_OPEN_FLAGS_NORMAL; 7386 if (pMedium->m->state != MediumState_LockedWrite) 7387 uOpenFlags = VD_OPEN_FLAGS_READONLY; 7388 if (pMedium->m->type == MediumType_Shareable) 7389 uOpenFlags |= VD_OPEN_FLAGS_SHAREABLE; 7390 7391 /* Open all media in appropriate mode. */ 7392 vrc = VDOpen(targetHdd, 7393 pMedium->m->strFormat.c_str(), 7394 pMedium->m->strLocationFull.c_str(), 7395 uOpenFlags, 7396 pMedium->m->vdImageIfaces); 7397 if (RT_FAILURE(vrc)) 7398 throw setError(VBOX_E_FILE_ERROR, 7399 tr("Could not open the medium storage unit '%s'%s"), 7400 pMedium->m->strLocationFull.c_str(), 7401 vdError(vrc).c_str()); 7402 } 7403 7404 /** @todo r=klaus target isn't locked, race getting the state */ 7405 vrc = VDCopy(hdd, 7406 VD_LAST_IMAGE, 7407 targetHdd, 7408 targetFormat.c_str(), 7409 (fCreatingTarget) ? targetLocation.c_str() : (char *)NULL, 7410 false /* fMoveByRename */, 7411 0 /* cbSize */, 7412 task.mVariant, 7413 targetId.raw(), 7414 VD_OPEN_FLAGS_NORMAL, 7415 NULL /* pVDIfsOperation */, 7416 task.mVDImageIfaces, 7417 task.mVDOperationIfaces); 7418 if (RT_FAILURE(vrc)) 7419 throw setError(VBOX_E_FILE_ERROR, 7420 tr("Could not create the clone medium '%s'%s"), 7421 targetLocation.c_str(), vdError(vrc).c_str()); 7422 7423 size = VDGetFileSize(targetHdd, VD_LAST_IMAGE); 7424 logicalSize = VDGetSize(targetHdd, VD_LAST_IMAGE); 7425 unsigned uImageFlags; 7426 vrc = VDGetImageFlags(targetHdd, 0, &uImageFlags); 7427 if (RT_SUCCESS(vrc)) 7428 variant = (MediumVariant_T)uImageFlags; 7429 } 7430 catch (HRESULT aRC) { rc = aRC; } 7431 7432 VDDestroy(targetHdd); 7433 } 7434 catch (HRESULT aRC) { rc = aRC; } 7435 7436 VDDestroy(hdd); 7437 } 7438 catch (HRESULT aRC) { rc = aRC; } 7439 7440 /* Only do the parent changes for newly created media. */ 7441 if (SUCCEEDED(rc) && fCreatingTarget) 7442 { 7443 /* we set mParent & children() */ 7444 AutoWriteLock alock2(m->pVirtualBox->getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS); 7445 7446 Assert(m->pParent.isNull()); 7447 7448 if (pParent) 7449 { 7450 /* associate the clone with the parent and deassociate 7451 * from VirtualBox */ 7452 m->pParent = pParent; 7453 pParent->m->llChildren.push_back(this); 7454 7455 /* register with mVirtualBox as the last step and move to 7456 * Created state only on success (leaving an orphan file is 7457 * better than breaking media registry consistency) */ 7458 rc = pParent->m->pVirtualBox->registerHardDisk(this, NULL /* pfNeedsGlobalSaveSettings */); 7459 7460 if (FAILED(rc)) 7461 /* break parent association on failure to register */ 7462 this->deparent(); // removes target from parent 7463 } 7464 else 7465 { 7466 /* just register */ 7467 rc = m->pVirtualBox->registerHardDisk(this, NULL /* pfNeedsGlobalSaveSettings */); 7468 } 7469 } 7470 7471 if (fCreatingTarget) 7472 { 7473 AutoWriteLock mLock(this COMMA_LOCKVAL_SRC_POS); 7474 7475 if (SUCCEEDED(rc)) 7476 { 7477 m->state = MediumState_Created; 7478 7479 m->size = size; 7480 m->logicalSize = logicalSize; 7481 m->variant = variant; 7482 } 7483 else 7484 { 7485 /* back to NotCreated on failure */ 7486 m->state = MediumState_NotCreated; 7487 7488 /* reset UUID to prevent it from being reused next time */ 7489 if (fGenerateUuid) 7490 unconst(m->id).clear(); 7491 } 7492 } 7493 7494 // now, at the end of this task (always asynchronous), save the settings 7495 { 7496 AutoWriteLock vboxlock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS); 7497 m->pVirtualBox->saveSettings(); 7498 } 7499 7500 /* Everything is explicitly unlocked when the task exits, 7501 * as the task destruction also destroys the target chain. */ 7502 7503 /* Make sure the target chain is released early, otherwise it can 7504 * lead to deadlocks with concurrent IAppliance activities. */ 7505 task.mpTargetMediumLockList->Clear(); 7506 7507 return rc; 7508 } 7509 7139 7510 /* vi: set tabstop=4 shiftwidth=4 expandtab: */ -
trunk/src/VBox/Main/include/MediumImpl.h
r33078 r33107 246 246 * 247 247 * @param aFilename Filename to create (UTF8). 248 * @param aFormat Which medium format to use .248 * @param aFormat Which medium format to use for export. 249 249 * @param aVariant Which exact image format variant to use. 250 250 * @param aVDImageIOCallbacks Pointer to the callback table for a … … 255 255 */ 256 256 HRESULT exportFile(const char *aFilename, 257 ComObjPtr<MediumFormat>aFormat,257 const ComObjPtr<MediumFormat> &aFormat, 258 258 MediumVariant_T aVariant, 259 259 void *aVDImageIOCallbacks, void *aVDImageIOUser, 260 ComObjPtr<Progress> aProgress); 260 const ComObjPtr<Progress> &aProgress); 261 /** 262 * Used by IAppliance to import disk images. 263 * 264 * @param aFilename Filename to read (UTF8). 265 * @param aFormat Which medium format to use for import. 266 * @param aVariant Which exact image format variant to use. 267 * @param aVDImageIOCallbacks Pointer to the callback table for a 268 * VDINTERFACEIO interface. May be NULL. 269 * @param aVDImageIOUser Opaque data for the callbacks. 270 * @param aParent Parent medium. May be NULL. 271 * @param aProgress Progress object to use. 272 * @return 273 */ 274 HRESULT importFile(const char *aFilename, 275 const ComObjPtr<MediumFormat> &aFormat, 276 MediumVariant_T aVariant, 277 void *aVDImageIOCallbacks, void *aVDImageIOUser, 278 const ComObjPtr<Medium> &aParent, 279 const ComObjPtr<Progress> &aProgress); 261 280 262 281 /** Returns a preferred format for a differencing hard disk. */ … … 311 330 class MergeTask; 312 331 class ExportTask; 332 class ImportTask; 313 333 friend class Task; 314 334 friend class CreateBaseTask; … … 321 341 friend class MergeTask; 322 342 friend class ExportTask; 343 friend class ImportTask; 323 344 324 345 HRESULT startThread(Medium::Task *pTask); … … 334 355 HRESULT taskResizeHandler(Medium::ResizeTask &task); 335 356 HRESULT taskExportHandler(Medium::ExportTask &task); 357 HRESULT taskImportHandler(Medium::ImportTask &task); 336 358 337 359 struct Data; // opaque data struct, defined in MediumImpl.cpp
Note:
See TracChangeset
for help on using the changeset viewer.