From 660ade42bb13c959f3a63b68a2e0d5b752360550 Mon Sep 17 00:00:00 2001 From: Rom Walton Date: Wed, 19 Nov 2014 12:58:43 -0500 Subject: [PATCH] VBOX: When deregistering a VM, organize the medium list by most recent child first and then release as needed. --- samples/vboxwrapper/vbox_mscom_impl.cpp | 182 ++++++++++++++---------- 1 file changed, 107 insertions(+), 75 deletions(-) diff --git a/samples/vboxwrapper/vbox_mscom_impl.cpp b/samples/vboxwrapper/vbox_mscom_impl.cpp index 91a823cccc..934ea4703b 100644 --- a/samples/vboxwrapper/vbox_mscom_impl.cpp +++ b/samples/vboxwrapper/vbox_mscom_impl.cpp @@ -17,40 +17,6 @@ #ifdef _VIRTUALBOX_IMPORT_FUNCTIONS_ -// Helper function to print MSCOM exception information set on the current -// thread after a failed MSCOM method call. This function will also print -// extended VirtualBox error info if it is available. -// -void virtualbox_dump_error() { - HRESULT rc; - char buf[256]; - IErrorInfo* pErrorInfo = NULL; - BSTR strDescription; - - rc = GetErrorInfo(0, &pErrorInfo); - if (FAILED(rc)) { - fprintf( - stderr, - "%s Error: getting error info! rc = 0x%x\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - rc - ); - } else { - rc = pErrorInfo->GetDescription(&strDescription); - if (SUCCEEDED(rc) && strDescription) { - fprintf( - stderr, - "%s Error description: %S\n", - vboxwrapper_msg_prefix(buf, sizeof(buf)), - strDescription - ); - SysFreeString(strDescription); - } - pErrorInfo->Release(); - } -} - - const char *MachineStateToName(MachineState State) { switch (State) @@ -102,6 +68,104 @@ const char *MachineStateToName(MachineState State) } +// Helper function to print MSCOM exception information set on the current +// thread after a failed MSCOM method call. This function will also print +// extended VirtualBox error info if it is available. +// +void virtualbox_dump_error() { + HRESULT rc; + char buf[256]; + IErrorInfo* pErrorInfo = NULL; + BSTR strDescription; + + rc = GetErrorInfo(0, &pErrorInfo); + if (FAILED(rc)) { + fprintf( + stderr, + "%s Error: getting error info! rc = 0x%x\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + rc + ); + } else { + rc = pErrorInfo->GetDescription(&strDescription); + if (SUCCEEDED(rc) && strDescription) { + fprintf( + stderr, + "%s Error description: %S\n", + vboxwrapper_msg_prefix(buf, sizeof(buf)), + strDescription + ); + SysFreeString(strDescription); + } + pErrorInfo->Release(); + } +} + + +// We want to recurisively walk the snapshot tree so that we can get the most recent children first. +// We also want to skip whatever the most current snapshot is. +// +void TraverseSnapshots(std::string& current_snapshot_id, std::vector& snapshots, ISnapshot* pSnapshot) { + HRESULT rc; + SAFEARRAY* pSnapshots = NULL; + CComSafeArray aSnapshots; + CComBSTR tmp; + ULONG lCount; + std::string snapshot_id; + + // Check to see if we have any children + // + rc = pSnapshot->GetChildrenCount(&lCount); + if (SUCCEEDED(rc) && lCount) { + rc = pSnapshot->get_Children(&pSnapshots); + if (SUCCEEDED(rc)) { + aSnapshots.Attach(pSnapshots); + if (aSnapshots.GetCount() > 0) { + for (int i = 0; i < (int)aSnapshots.GetCount(); i++) { + TraverseSnapshots(current_snapshot_id, snapshots, (ISnapshot*)(LPDISPATCH)aSnapshots[i]); + } + } + } + } + + // Check to see if we are the most recent snapshot. + // if not, add the snapshot id to the list of snapshots to be deleted. + // + pSnapshot->get_Id(&tmp); + if (SUCCEEDED(rc)) { + snapshot_id = CW2A(tmp); + if (current_snapshot_id == snapshot_id) { + return; + } else { + snapshots.push_back(snapshot_id); + } + } +} + + +// We want to recurisively walk the medium tree so that we can get the most recent children first. +// +void TraverseMediums(std::vector>& mediums, IMedium* pMedium) { + HRESULT rc; + SAFEARRAY* pMediums = NULL; + CComSafeArray aMediums; + + // Check to see if we have any children + // + rc = pMedium->get_Children(&pMediums); + if (SUCCEEDED(rc)) { + aMediums.Attach(pMediums); + if (aMediums.GetCount() > 0) { + for (int i = 0; i < (int)aMediums.GetCount(); i++) { + TraverseMediums(mediums, (IMedium*)(LPDISPATCH)aMediums[i]); + } + } + } + + mediums.push_back(CComPtr(pMedium)); +} + + VBOX_VM::VBOX_VM() { VBOX_BASE::VBOX_BASE(); @@ -1450,6 +1514,8 @@ int VBOX_VM::deregister_vm(bool delete_media) { LONG lDevice; LONG lPort; string virtual_machine_slot_directory; + std::vector> mediums; + get_slot_directory(virtual_machine_slot_directory); @@ -1603,11 +1669,16 @@ int VBOX_VM::deregister_vm(bool delete_media) { if (SUCCEEDED(rc)) { // We only want to close(remove from media registry) the hard disks - // instead of deleting them + // instead of deleting them, order them by most recent image first + // and then walk back to the root. // aHardDisks.Attach(pHardDisks); for (int i = 0; i < (int)aHardDisks.GetCount(); i++) { CComPtr pMedium((IMedium*)(LPDISPATCH)aHardDisks[i]); + TraverseMediums(mediums, pMedium); + } + for (int i = 0; i < (int)mediums.size(); i++) { + CComPtr pMedium(mediums[i]); pMedium->Close(); } @@ -1639,6 +1710,7 @@ int VBOX_VM::deregister_vm(bool delete_media) { virtualbox_dump_error(); } #endif + } else { fprintf( stderr, @@ -2355,46 +2427,6 @@ CLEANUP: return retval; } -// We want to recurisively walk the snapshot tree so that we can delete the most recent children first. -// We also want to skip whatever the most current snapshot is. -// -void TraverseSnapshots(std::string& current_snapshot_id, std::vector& snapshots, ISnapshot* pSnapshot) { - HRESULT rc; - SAFEARRAY* pSnapshots = NULL; - CComSafeArray aSnapshots; - CComBSTR tmp; - ULONG lCount; - std::string snapshot_id; - - // Check to see if we have any children - // - rc = pSnapshot->GetChildrenCount(&lCount); - if (SUCCEEDED(rc) && lCount) { - rc = pSnapshot->get_Children(&pSnapshots); - if (SUCCEEDED(rc)) { - aSnapshots.Attach(pSnapshots); - if (aSnapshots.GetCount() > 0) { - for (int i = 0; i < (int)aSnapshots.GetCount(); i++) { - TraverseSnapshots(current_snapshot_id, snapshots, (ISnapshot*)(LPDISPATCH)aSnapshots[i]); - } - } - } - } - - // Check to see if we are the most recent snapshot. - // if not, add the snapshot id to the list of snapshots to be deleted. - // - pSnapshot->get_Id(&tmp); - if (SUCCEEDED(rc)) { - snapshot_id = CW2A(tmp); - if (current_snapshot_id == snapshot_id) { - return; - } else { - snapshots.push_back(snapshot_id); - } - } -} - int VBOX_VM::cleanup_snapshots(bool delete_active) { int retval = ERR_EXEC; char buf[256];