VirtualBox

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


Ignore:
Timestamp:
Jan 28, 2022 4:09:52 PM (3 years ago)
Author:
vboxsync
Message:

Main/Appliance: Allow users to specify a different storage controller
and/or controller port for hard disks when importing a VM. bugref:5027

'VBoxManage import foo.ova -n' has always presented a --controller
option for hard disks but the code to implement this had never been
implemented. This changeset adds the --controller functionality and
also includes a --port option for changing the controller port as well.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/ApplianceImpl.h

    r93115 r93480  
    220220                             ImportStack &stack);
    221221    void i_importMachines(ImportStack &stack);
     222    HRESULT i_verifyStorageControllerPortValid(const StorageControllerType_T aStorageControllerType,
     223                                               const uint32_t aControllerPort,
     224                                               ULONG *ulMaxPorts);
    222225
    223226    HRESULT i_preCheckImageAvailability(ImportStack &stack);
     
    310313    std::list<VirtualSystemDescriptionEntry*> i_findByType(VirtualSystemDescriptionType_T aType);
    311314    const VirtualSystemDescriptionEntry* i_findControllerFromID(const Utf8Str &id);
     315    const VirtualSystemDescriptionEntry* i_findByIndex(const uint32_t aIndex);
    312316
    313317    void i_importVBoxMachineXML(const xml::ElementNode &elmMachine);
  • trunk/src/VBox/Main/include/Global.h

    r93410 r93480  
    168168    static const char *stringifySessionState(SessionState_T aState);
    169169
     170    /**
     171     * Stringify a device type.
     172     *
     173     * Drop the Global:: prefix and include StringifyEnums.h for an untranslated
     174     * version of this method.
     175     *
     176     * @returns Pointer to a read only string.
     177     * @param   aType       The device type.
     178     */
     179    static const char *stringifyDeviceType(DeviceType_T aType);
     180
     181    /**
     182     * Stringify a storage controller type.
     183     *
     184     * Drop the Global:: prefix and include StringifyEnums.h for an untranslated
     185     * version of this method.
     186     *
     187     * @returns Pointer to a read only string.
     188     * @param   aType       The storage controller type.
     189     */
     190    static const char *stringifyStorageControllerType(StorageControllerType_T aType);
     191
    170192#if 0 /* unused */
    171193    /**
     
    179201     */
    180202    static const char *stringifyStorageBus(StorageBus_T aBus);
    181 
    182     /**
    183      * Stringify a device type.
    184      *
    185      * Drop the Global:: prefix and include StringifyEnums.h for an untranslated
    186      * version of this method.
    187      *
    188      * @returns Pointer to a read only string.
    189      * @param   aType       The device type.
    190      */
    191     static const char *stringifyDeviceType(DeviceType_T aType);
    192203
    193204    /**
  • trunk/src/VBox/Main/src-all/Global.cpp

    r93410 r93480  
    635635}
    636636
     637/*static*/ const char *
     638Global::stringifyStorageControllerType(StorageControllerType_T aType)
     639{
     640    switch (aType)
     641    {
     642        case StorageControllerType_Null:        return GlobalCtx::tr("Null");
     643        case StorageControllerType_LsiLogic:    return GlobalCtx::tr("LsiLogic");
     644        case StorageControllerType_BusLogic:    return GlobalCtx::tr("BusLogic");
     645        case StorageControllerType_IntelAhci:   return GlobalCtx::tr("AHCI");
     646        case StorageControllerType_PIIX3:       return GlobalCtx::tr("PIIX3");
     647        case StorageControllerType_PIIX4 :      return GlobalCtx::tr("PIIX4");
     648        case StorageControllerType_ICH6:        return GlobalCtx::tr("ICH6");
     649        case StorageControllerType_I82078:      return GlobalCtx::tr("I82078");
     650        case StorageControllerType_LsiLogicSas: return GlobalCtx::tr("LsiLogicSas");
     651        case StorageControllerType_USB:         return GlobalCtx::tr("USB");
     652        case StorageControllerType_NVMe:        return GlobalCtx::tr("NVMe");
     653        case StorageControllerType_VirtioSCSI:  return GlobalCtx::tr("VirtioSCSI");
     654        default:
     655            AssertMsgFailedReturn(("%d (%#x)\n", aType, aType), ::stringifyStorageControllerType(aType));
     656    }
     657}
     658
     659/*static*/ const char *
     660Global::stringifyDeviceType(DeviceType_T aType)
     661{
     662    switch (aType)
     663    {
     664        case DeviceType_Null:         return GlobalCtx::tr("Null");
     665        case DeviceType_Floppy:       return GlobalCtx::tr("Floppy");
     666        case DeviceType_DVD:          return GlobalCtx::tr("DVD");
     667        case DeviceType_HardDisk:     return GlobalCtx::tr("HardDisk");
     668        case DeviceType_Network:      return GlobalCtx::tr("Network");
     669        case DeviceType_USB:          return GlobalCtx::tr("USB");
     670        case DeviceType_SharedFolder: return GlobalCtx::tr("ShardFolder");
     671        default:
     672            AssertMsgFailedReturn(("%d (%#x)\n", aType, aType), ::stringifyDeviceType(aType));
     673    }
     674}
     675
    637676#if 0 /* unused */
    638677
     
    656695
    657696/*static*/ const char *
    658 Global::stringifyDeviceType(DeviceType_T aType)
    659 {
    660     switch (aType)
    661     {
    662         case DeviceType_Null:         return GlobalCtx::tr("Null");
    663         case DeviceType_Floppy:       return GlobalCtx::tr("Floppy");
    664         case DeviceType_DVD:          return GlobalCtx::tr("DVD");
    665         case DeviceType_HardDisk:     return GlobalCtx::tr("HardDisk");
    666         case DeviceType_Network:      return GlobalCtx::tr("Network");
    667         case DeviceType_USB:          return GlobalCtx::tr("USB");
    668         case DeviceType_SharedFolder: return GlobalCtx::tr("ShardFolder");
    669         default:
    670             AssertMsgFailedReturn(("%d (%#x)\n", aType, aType), ::stringifyDeviceType(aType));
    671     }
    672 }
    673 
    674 /*static*/ const char *
    675697Global::stringifyReason(Reason_T aReason)
    676698{
  • trunk/src/VBox/Main/src-server/ApplianceImpl.cpp

    r93115 r93480  
    18281828}
    18291829
     1830/**
     1831 * Private method; walks through the array of VirtualSystemDescriptionEntry entries
     1832 * and returns the one matching the given index.
     1833 */
     1834const VirtualSystemDescriptionEntry* VirtualSystemDescription::i_findByIndex(const uint32_t aIndex)
     1835{
     1836    vector<VirtualSystemDescriptionEntry>::const_iterator it;
     1837    for (it = m->maDescriptions.begin();
     1838         it != m->maDescriptions.end();
     1839         ++it)
     1840    {
     1841        const VirtualSystemDescriptionEntry &d = *it;
     1842        if (d.ulIndex == aIndex)
     1843            return &d;
     1844    }
     1845
     1846    return NULL;
     1847}
     1848
  • trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp

    r93115 r93480  
    43054305
    43064306/**
     4307 * Helper routine to parse the ExtraData Utf8Str for a storage controller's
     4308 * value or channel value.
     4309 *
     4310 * @param   aExtraData    The ExtraData string with a format of
     4311 *                        'controller=13;channel=3'.
     4312 * @param   pszKey        The string being looked up, either 'controller' or
     4313 *                        'channel'.
     4314 * @param   puVal         The integer value of the 'controller=' or 'channel='
     4315 *                        key in the ExtraData string.
     4316 * @returns COM status code.
     4317 * @throws  Nothing.
     4318 */
     4319static int getStorageControllerDetailsFromStr(const com::Utf8Str &aExtraData, const char *pszKey, uint32_t *puVal)
     4320{
     4321    size_t posKey = aExtraData.find(pszKey);
     4322    if (posKey == Utf8Str::npos)
     4323        return VERR_INVALID_PARAMETER;
     4324
     4325    int vrc = RTStrToUInt32Ex(aExtraData.c_str() + posKey + strlen(pszKey), NULL, 0, puVal);
     4326    if (vrc == VWRN_NUMBER_TOO_BIG || vrc == VWRN_NEGATIVE_UNSIGNED)
     4327        return VERR_INVALID_PARAMETER;
     4328
     4329    return vrc;
     4330}
     4331
     4332/**
     4333 * Verifies the validity of a storage controller's channel (aka controller port).
     4334 *
     4335 * @param   aStorageControllerType     The type of storage controller as idenfitied
     4336 *                                     by the enum of type StorageControllerType_T.
     4337 * @param   uControllerPort            The controller port value.
     4338 * @param   aMaxPortCount              The maximum number of ports allowed for this
     4339 *                                     storage controller type.
     4340 * @returns COM status code.
     4341 * @throws  Nothing.
     4342 */
     4343HRESULT Appliance::i_verifyStorageControllerPortValid(const StorageControllerType_T aStorageControllerType,
     4344                                                      const uint32_t uControllerPort,
     4345                                                      ULONG *aMaxPortCount)
     4346{
     4347    SystemProperties *pSysProps;
     4348    pSysProps = mVirtualBox->i_getSystemProperties();
     4349    if (pSysProps == NULL)
     4350        return VBOX_E_OBJECT_NOT_FOUND;
     4351
     4352    StorageBus_T enmStorageBus = StorageBus_Null;
     4353    HRESULT vrc = pSysProps->GetStorageBusForStorageControllerType(aStorageControllerType, &enmStorageBus);
     4354    if (FAILED(vrc))
     4355        return vrc;
     4356
     4357    vrc = pSysProps->GetMaxPortCountForStorageBus(enmStorageBus, aMaxPortCount);
     4358    if (FAILED(vrc))
     4359        return vrc;
     4360
     4361    if (uControllerPort >= *aMaxPortCount)
     4362        return E_INVALIDARG;
     4363
     4364    return S_OK;
     4365}
     4366
     4367/**
    43074368 * Imports one OVF virtual system (described by the given ovf::VirtualSystem and VirtualSystemDescription)
    43084369 * into VirtualBox by creating an IMachine instance, which is returned.
     
    50145075                    throw rc;
    50155076
    5016                 // find the hard disk controller to which we should attach
    5017                 ovf::HardDiskController hdc = (*vsysThis.mapControllers.find(ovfVdisk.strIdController)).second;
    5018 
    50195077                // this is for rollback later
    50205078                MyHardDiskAttachment mhda;
    50215079                mhda.pMachine = pNewMachine;
     5080
     5081                // find the hard disk controller to which we should attach
     5082                ovf::HardDiskController hdc;
     5083
     5084                /*
     5085                 * Before importing the virtual hard disk found above (diCurrent/vsdeTargetHD) first
     5086                 * check if the user requested to change either the controller it is to be attached
     5087                 * to and/or the controller port (aka 'channel') on the controller.
     5088                 */
     5089                if (   !vsdeTargetHD->strExtraConfigCurrent.isEmpty()
     5090                    && vsdeTargetHD->strExtraConfigSuggested != vsdeTargetHD->strExtraConfigCurrent)
     5091                {
     5092                    int vrc;
     5093                    uint32_t uTargetControllerIndex;
     5094                    vrc = getStorageControllerDetailsFromStr(vsdeTargetHD->strExtraConfigCurrent, "controller=",
     5095                        &uTargetControllerIndex);
     5096                    if (RT_FAILURE(vrc))
     5097                        throw setError(E_FAIL,
     5098                                       tr("Target controller value invalid or missing: '%s'"),
     5099                                       vsdeTargetHD->strExtraConfigCurrent.c_str());
     5100
     5101                    uint32_t uNewControllerPortValue;
     5102                    vrc = getStorageControllerDetailsFromStr(vsdeTargetHD->strExtraConfigCurrent, "channel=",
     5103                        &uNewControllerPortValue);
     5104                    if (RT_FAILURE(vrc))
     5105                        throw setError(E_FAIL,
     5106                                       tr("Target controller port ('channel=') invalid or missing: '%s'"),
     5107                                       vsdeTargetHD->strExtraConfigCurrent.c_str());
     5108
     5109                    const VirtualSystemDescriptionEntry *vsdeTargetController;
     5110                    vsdeTargetController = vsdescThis->i_findByIndex(uTargetControllerIndex);
     5111                    if (!vsdeTargetController)
     5112                        throw setError(E_FAIL,
     5113                                       tr("Failed to find storage controller '%u' in the System Description list"),
     5114                                       uTargetControllerIndex);
     5115
     5116                    hdc = (*vsysThis.mapControllers.find(vsdeTargetController->strRef.c_str())).second;
     5117
     5118                    StorageControllerType_T hdStorageControllerType = StorageControllerType_Null;
     5119                    switch (hdc.system)
     5120                    {
     5121                        case ovf::HardDiskController::IDE:
     5122                            hdStorageControllerType = StorageControllerType_PIIX3;
     5123                            break;
     5124                        case ovf::HardDiskController::SATA:
     5125                            hdStorageControllerType = StorageControllerType_IntelAhci;
     5126                            break;
     5127                        case ovf::HardDiskController::SCSI:
     5128                        {
     5129                            if (hdc.strControllerType.compare("lsilogicsas")==0)
     5130                                hdStorageControllerType = StorageControllerType_LsiLogicSas;
     5131                            else
     5132                                hdStorageControllerType = StorageControllerType_LsiLogic;
     5133                            break;
     5134                        }
     5135                        case ovf::HardDiskController::VIRTIOSCSI:
     5136                            hdStorageControllerType = StorageControllerType_VirtioSCSI;
     5137                            break;
     5138                        default:
     5139                            throw setError(E_FAIL,
     5140                                           tr("Invalid hard disk contoller type: '%d'"),
     5141                                           hdc.system);
     5142                            break;
     5143                    }
     5144
     5145                    ULONG ulMaxPorts;
     5146                    rc = i_verifyStorageControllerPortValid(hdStorageControllerType,
     5147                                                            uNewControllerPortValue,
     5148                                                            &ulMaxPorts);
     5149                    if (FAILED(rc))
     5150                    {
     5151                        if (rc == E_INVALIDARG)
     5152                        {
     5153                            const char *pcszSCType = Global::stringifyStorageControllerType(hdStorageControllerType);
     5154                            throw setError(E_INVALIDARG,
     5155                                           tr("Illegal channel: '%u'.  For %s controllers the valid values are "
     5156                                           "0 to %lu (inclusive).\n"), uNewControllerPortValue, pcszSCType, ulMaxPorts-1);
     5157                        }
     5158                        else
     5159                            throw rc;
     5160                    }
     5161
     5162                    unconst(ovfVdisk.ulAddressOnParent) = uNewControllerPortValue;
     5163                }
     5164                else
     5165                    hdc = (*vsysThis.mapControllers.find(ovfVdisk.strIdController)).second;
     5166
    50225167
    50235168                i_convertDiskAttachmentValues(hdc,
     
    52625407     * failures. A long fixed bug, however the OVF files are long lived. */
    52635408    settings::StorageControllersList &llControllers = config.hardwareMachine.storage.llStorageControllers;
    5264     Guid hdUuid;
    52655409    uint32_t cDisks = 0;
    52665410    bool fInconsistent = false;
     
    52715415         ++it3)
    52725416    {
     5417        Guid hdUuid;
    52735418        settings::AttachedDevicesList &llAttachments = it3->llAttachedDevices;
    52745419        settings::AttachedDevicesList::iterator it4 = llAttachments.begin();
     
    53645509            continue;
    53655510        }
    5366 
    5367 
    5368 
    5369 
    5370 
    5371 
    5372 
    5373 
    53745511
    53755512        /*
     
    54445581                                       tr("Internal inconsistency looking up disk image '%s'"),
    54455582                                       diCurrent.strHref.c_str());
    5446 
    5447 
    5448 
    5449 
    5450 
    54515583                }
    54525584                else
     
    54735605        bool fFound = false;
    54745606        Utf8Str strUuid;
     5607
     5608        /*
     5609         * Before importing the virtual hard disk found above (diCurrent/vsdeTargetHD) first
     5610         * check if the user requested to change either the controller it is to be attached
     5611         * to and/or the controller port (aka 'channel') on the controller.
     5612         */
     5613        if (   !vsdeTargetHD->strExtraConfigCurrent.isEmpty()
     5614            && vsdeTargetHD->strExtraConfigSuggested != vsdeTargetHD->strExtraConfigCurrent)
     5615        {
     5616            /*
     5617             * First, we examine the extra configuration values for this vdisk:
     5618             *   vsdeTargetHD->strExtraConfigSuggested
     5619             *   vsdeTargetHD->strExtraConfigCurrent
     5620             * in order to extract both the "before" and "after" storage controller and port
     5621             * details. The strExtraConfigSuggested string contains the current controller
     5622             * and port the vdisk is attached to and is populated by Appliance::interpret()
     5623             * when processing the OVF data; it is in the following format:
     5624             * 'controller=12;channel=0' (the 'channel=' label for the controller port is
     5625             * historical and is documented as such in the SDK so can't be changed). The
     5626             * strExtraConfigSuggested string contains the target controller and port specified
     5627             * by the user and it has the same format. The 'controller=' value is not a
     5628             * controller-ID but rather it is the index for the corresponding storage controller
     5629             * in the array of VirtualSystemDescriptionEntry entries.
     5630             */
     5631            int vrc;
     5632            uint32_t uOrigControllerIndex;
     5633            vrc = getStorageControllerDetailsFromStr(vsdeTargetHD->strExtraConfigSuggested, "controller=", &uOrigControllerIndex);
     5634            if (RT_FAILURE(vrc))
     5635                throw setError(E_FAIL,
     5636                               tr("Original controller value invalid or missing: '%s'"),
     5637                               vsdeTargetHD->strExtraConfigSuggested.c_str());
     5638
     5639            uint32_t uTargetControllerIndex;
     5640            vrc = getStorageControllerDetailsFromStr(vsdeTargetHD->strExtraConfigCurrent, "controller=", &uTargetControllerIndex);
     5641            if (RT_FAILURE(vrc))
     5642                throw setError(E_FAIL,
     5643                               tr("Target controller value invalid or missing: '%s'"),
     5644                               vsdeTargetHD->strExtraConfigCurrent.c_str());
     5645
     5646            uint32_t uOrigControllerPortValue;
     5647            vrc = getStorageControllerDetailsFromStr(vsdeTargetHD->strExtraConfigSuggested, "channel=",
     5648                &uOrigControllerPortValue);
     5649            if (RT_FAILURE(vrc))
     5650                throw setError(E_FAIL,
     5651                               tr("Original controller port ('channel=') invalid or missing: '%s'"),
     5652                               vsdeTargetHD->strExtraConfigSuggested.c_str());
     5653
     5654            uint32_t uNewControllerPortValue;
     5655            vrc = getStorageControllerDetailsFromStr(vsdeTargetHD->strExtraConfigCurrent, "channel=", &uNewControllerPortValue);
     5656            if (RT_FAILURE(vrc))
     5657                throw setError(E_FAIL,
     5658                               tr("Target controller port ('channel=') invalid or missing: '%s'"),
     5659                               vsdeTargetHD->strExtraConfigCurrent.c_str());
     5660
     5661            /*
     5662             * Second, now that we have the storage controller indexes we locate the corresponding
     5663             * VirtualSystemDescriptionEntry (VSDE) for both storage controllers which contain
     5664             * identifying details which will be needed later when walking the list of storage
     5665             * controllers.
     5666             */
     5667            const VirtualSystemDescriptionEntry *vsdeOrigController;
     5668            vsdeOrigController = vsdescThis->i_findByIndex(uOrigControllerIndex);
     5669            if (!vsdeOrigController)
     5670                throw setError(E_FAIL,
     5671                               tr("Failed to find storage controller '%u' in the System Description list"),
     5672                               uOrigControllerIndex);
     5673
     5674            const VirtualSystemDescriptionEntry *vsdeTargetController;
     5675            vsdeTargetController = vsdescThis->i_findByIndex(uTargetControllerIndex);
     5676            if (!vsdeTargetController)
     5677                throw setError(E_FAIL,
     5678                               tr("Failed to find storage controller '%u' in the System Description list"),
     5679                               uTargetControllerIndex);
     5680
     5681            /*
     5682             * Third, grab the UUID of the current vdisk so we can identify which device
     5683             * attached to the original storage controller needs to be updated (channel) and/or
     5684             * removed.
     5685             */
     5686            ovf::DiskImagesMap::const_iterator itDiskImageMap = stack.mapDisks.find(vsdeTargetHD->strRef);
     5687            if (itDiskImageMap == stack.mapDisks.end())
     5688                throw setError(E_FAIL,
     5689                               tr("Failed to find virtual disk '%s' in DiskImagesMap"),
     5690                               vsdeTargetHD->strVBoxCurrent.c_str());
     5691            const ovf::DiskImage &targetDiskImage = itDiskImageMap->second;
     5692            Utf8Str strTargetDiskUuid = targetDiskImage.uuidVBox;;
     5693
     5694            /*
     5695             * Fourth, walk the attached devices of the original storage controller to find the
     5696             * current vdisk and update the controller port (aka channel) value if necessary and
     5697             * also remove the vdisk from this controller if needed.
     5698             *
     5699             * A short note on the choice of which items to compare when determining the type of
     5700             * storage controller here and below in the vdisk addition scenario:
     5701             *  + The VirtualSystemDescriptionEntry 'strOvf' field is populated from the OVF
     5702             *    data which can contain a value like 'vmware.sata.ahci' if created by VMWare so
     5703             *    it isn't a reliable choice.
     5704             *  + The settings::StorageController 'strName' field can have varying content based
     5705             *    on the version of the settings file, e.g. 'IDE Controller' vs. 'IDE' so it
     5706             *    isn't a reliable choice.  Further, this field can contain 'SATA' whereas
     5707             *    'AHCI' is used in 'strOvf' and 'strVBoxSuggested'.
     5708             *  + The VirtualSystemDescriptionEntry 'strVBoxSuggested' field is populated by
     5709             *    Appliance::interpret()->VirtualSystemDescription::i_addEntry() and is thus
     5710             *    under VBox's control and has a fixed format and predictable content.
     5711             */
     5712            bool fDiskRemoved = false;
     5713            settings::AttachedDevice originalAttachedDevice;
     5714            settings::StorageControllersList::iterator itSCL;
     5715            for (itSCL = config.hardwareMachine.storage.llStorageControllers.begin();
     5716                 itSCL != config.hardwareMachine.storage.llStorageControllers.end();
     5717                 ++itSCL)
     5718            {
     5719                settings::StorageController &SC = *itSCL;
     5720                const char *pcszSCType = Global::stringifyStorageControllerType(SC.controllerType);
     5721
     5722                /* There can only be one storage controller of each type in the OVF data. */
     5723                if (!vsdeOrigController->strVBoxSuggested.compare(pcszSCType, Utf8Str::CaseInsensitive))
     5724                {
     5725                    settings::AttachedDevicesList::iterator itAD;
     5726                    for (itAD = SC.llAttachedDevices.begin();
     5727                         itAD != SC.llAttachedDevices.end();
     5728                         ++itAD)
     5729                    {
     5730                        settings::AttachedDevice &AD = *itAD;
     5731
     5732                        if (AD.uuid.toString() == strTargetDiskUuid)
     5733                        {
     5734                            ULONG ulMaxPorts;
     5735                            rc = i_verifyStorageControllerPortValid(SC.controllerType,
     5736                                                                    uNewControllerPortValue,
     5737                                                                    &ulMaxPorts);
     5738                            if (FAILED(rc))
     5739                            {
     5740                                if (rc == E_INVALIDARG)
     5741                                    throw setError(E_INVALIDARG,
     5742                                                   tr("Illegal channel: '%u'.  For %s controllers the valid values are "
     5743                                                   "0 to %lu (inclusive).\n"), uNewControllerPortValue, pcszSCType, ulMaxPorts-1);
     5744                                else
     5745                                    throw rc;
     5746                            }
     5747
     5748                            if (uOrigControllerPortValue != uNewControllerPortValue)
     5749                            {
     5750                                AD.lPort = uNewControllerPortValue;
     5751                            }
     5752                            if (uOrigControllerIndex != uTargetControllerIndex)
     5753                            {
     5754                                LogFunc(("Removing vdisk '%s' (uuid = %RTuuid) from the %s storage controller.\n",
     5755                                         vsdeTargetHD->strVBoxCurrent.c_str(),
     5756                                         itAD->uuid.raw(),
     5757                                         SC.strName.c_str()));
     5758                                originalAttachedDevice = AD;
     5759                                SC.llAttachedDevices.erase(itAD);
     5760                                fDiskRemoved = true;
     5761                            }
     5762                        }
     5763                    }
     5764                }
     5765            }
     5766
     5767            /*
     5768             * Fifth, if we are moving the vdisk to a different controller and not just changing
     5769             * the channel then we walk the attached devices of the target controller and check
     5770             * for conflicts before adding the vdisk detached/removed above.
     5771             */
     5772            bool fDiskAdded = false;
     5773            if (fDiskRemoved)
     5774            {
     5775                for (itSCL = config.hardwareMachine.storage.llStorageControllers.begin();
     5776                     itSCL != config.hardwareMachine.storage.llStorageControllers.end();
     5777                     ++itSCL)
     5778                {
     5779                    settings::StorageController &SC = *itSCL;
     5780                    const char *pcszSCType = Global::stringifyStorageControllerType(SC.controllerType);
     5781
     5782                    /* There can only be one storage controller of each type in the OVF data. */
     5783                    if (!vsdeTargetController->strVBoxSuggested.compare(pcszSCType, Utf8Str::CaseInsensitive))
     5784                    {
     5785                        settings::AttachedDevicesList::iterator itAD;
     5786                        for (itAD = SC.llAttachedDevices.begin();
     5787                             itAD != SC.llAttachedDevices.end();
     5788                             ++itAD)
     5789                        {
     5790                            settings::AttachedDevice &AD = *itAD;
     5791                            if (   AD.lDevice == originalAttachedDevice.lDevice
     5792                                && AD.lPort == originalAttachedDevice.lPort)
     5793                                    throw setError(E_FAIL,
     5794                                                   tr("Device of type '%s' already attached to the %s controller at this "
     5795                                                   "port/channel (%d)."),
     5796                                                   Global::stringifyDeviceType(AD.deviceType), pcszSCType, AD.lPort);
     5797                        }
     5798
     5799                        LogFunc(("Adding vdisk '%s' (uuid = %RTuuid) to the %s storage controller\n",
     5800                                 vsdeTargetHD->strVBoxCurrent.c_str(),
     5801                                 originalAttachedDevice.uuid.raw(),
     5802                                 SC.strName.c_str()));
     5803                        SC.llAttachedDevices.push_back(originalAttachedDevice);
     5804                        fDiskAdded = true;
     5805                    }
     5806                }
     5807
     5808                if (!fDiskAdded)
     5809                    throw setError(E_FAIL,
     5810                                   tr("Failed to add disk '%s' (uuid=%RTuuid) to the %s storage controller."),
     5811                                   vsdeTargetHD->strVBoxCurrent.c_str(),
     5812                                   originalAttachedDevice.uuid.raw(),
     5813                                   vsdeTargetController->strVBoxSuggested.c_str());
     5814            }
     5815
     5816            /*
     5817             * Sixth, update the machine settings since we've changed the storage controller
     5818             * and/or controller port for this vdisk.
     5819             */
     5820            AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
     5821            mVirtualBox->i_saveSettings();
     5822            vboxLock.release();
     5823        }
    54755824
    54765825        // for each storage controller...
     
    56566005            VirtualSystemDescriptionEntry *vsdeSF1 = vsdeSettingsFile.front();
    56576006            if (vsdeSF1->strVBoxCurrent != vsdeSF1->strVBoxSuggested)
    5658             stack.strSettingsFilename = vsdeSF1->strVBoxCurrent;
     6007                stack.strSettingsFilename = vsdeSF1->strVBoxCurrent;
    56596008        }
    56606009        if (stack.strSettingsFilename.isEmpty())
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