diff options
Diffstat (limited to 'src/VBox/Main/src-client/GuestSessionImplTasks.cpp')
-rw-r--r-- | src/VBox/Main/src-client/GuestSessionImplTasks.cpp | 245 |
1 files changed, 180 insertions, 65 deletions
diff --git a/src/VBox/Main/src-client/GuestSessionImplTasks.cpp b/src/VBox/Main/src-client/GuestSessionImplTasks.cpp index 84866b30..759020d9 100644 --- a/src/VBox/Main/src-client/GuestSessionImplTasks.cpp +++ b/src/VBox/Main/src-client/GuestSessionImplTasks.cpp @@ -1,11 +1,10 @@ - /* $Id: GuestSessionImplTasks.cpp $ */ /** @file - * VirtualBox Main - XXX. + * VirtualBox Main - Guest session tasks. */ /* - * Copyright (C) 2012 Oracle Corporation + * Copyright (C) 2012-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -138,6 +137,9 @@ int GuestSessionTask::setProgressSuccess(void) HRESULT GuestSessionTask::setProgressErrorMsg(HRESULT hr, const Utf8Str &strMsg) { + LogFlowFunc(("hr=%Rhrc, strMsg=%s\n", + hr, strMsg.c_str())); + if (mProgress.isNull()) /* Progress is optional. */ return hr; /* Return original rc. */ @@ -158,6 +160,62 @@ HRESULT GuestSessionTask::setProgressErrorMsg(HRESULT hr, const Utf8Str &strMsg) return hr; /* Return original rc. */ } +SessionTaskOpen::SessionTaskOpen(GuestSession *pSession, + uint32_t uFlags, + uint32_t uTimeoutMS) + : GuestSessionTask(pSession), + mFlags(uFlags), + mTimeoutMS(uTimeoutMS) +{ + +} + +SessionTaskOpen::~SessionTaskOpen(void) +{ + +} + +int SessionTaskOpen::Run(int *pGuestRc) +{ + LogFlowThisFuncEnter(); + + ComObjPtr<GuestSession> pSession = mSession; + Assert(!pSession.isNull()); + + AutoCaller autoCaller(pSession); + if (FAILED(autoCaller.rc())) return autoCaller.rc(); + + int vrc = pSession->startSessionInternal(pGuestRc); + /* Nothing to do here anymore. */ + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int SessionTaskOpen::RunAsync(const Utf8Str &strDesc, ComObjPtr<Progress> &pProgress) +{ + LogFlowThisFunc(("strDesc=%s\n", strDesc.c_str())); + + mDesc = strDesc; + mProgress = pProgress; + + int rc = RTThreadCreate(NULL, SessionTaskOpen::taskThread, this, + 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0, + "gctlSesOpen"); + LogFlowFuncLeaveRC(rc); + return rc; +} + +/* static */ +int SessionTaskOpen::taskThread(RTTHREAD Thread, void *pvUser) +{ + std::auto_ptr<SessionTaskOpen> task(static_cast<SessionTaskOpen*>(pvUser)); + AssertReturn(task.get(), VERR_GENERAL_FAILURE); + + LogFlowFunc(("pTask=%p\n", task.get())); + return task->Run(NULL /* guestRc */); +} + SessionTaskCopyTo::SessionTaskCopyTo(GuestSession *pSession, const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags) : GuestSessionTask(pSession), @@ -245,6 +303,7 @@ int SessionTaskCopyTo::Run(void) } else { + rc = VINF_SUCCESS; pFile = mSourceFile; /* Size + offset are optional. */ } @@ -258,14 +317,20 @@ int SessionTaskCopyTo::Run(void) /* Startup process. */ ComObjPtr<GuestProcess> pProcess; int guestRc; - rc = pSession->processCreateExInteral(procInfo, pProcess); if (RT_SUCCESS(rc)) - rc = pProcess->startProcess(&guestRc); + rc = pSession->processCreateExInteral(procInfo, pProcess); + if (RT_SUCCESS(rc)) + { + Assert(!pProcess.isNull()); + rc = pProcess->startProcess(30 * 1000 /* 30s timeout */, + &guestRc); + } + if (RT_FAILURE(rc)) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -301,7 +366,7 @@ int SessionTaskCopyTo::Run(void) /* If the guest does not support waiting for stdin, we now yield in * order to reduce the CPU load due to busy waiting. */ if (waitRes == ProcessWaitResult_WaitFlagNotSupported) - RTThreadSleep(1); /* Optional, don't check rc. */ + RTThreadYield(); /* Optional, don't check rc. */ size_t cbRead = 0; if (mSourceSize) /* If we have nothing to write, take a shortcut. */ @@ -312,7 +377,7 @@ int SessionTaskCopyTo::Run(void) if (RT_SUCCESS(rc)) { rc = RTFileRead(*pFile, (uint8_t*)byBuf, - RT_MIN(cbToRead, sizeof(byBuf)), &cbRead); + RT_MIN((size_t)cbToRead, sizeof(byBuf)), &cbRead); /* * Some other error occured? There might be a chance that RTFileRead * could not resolve/map the native error code to an IPRT code, so just @@ -360,7 +425,7 @@ int SessionTaskCopyTo::Run(void) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -403,7 +468,8 @@ int SessionTaskCopyTo::Run(void) break; } /* for */ - LogFlowThisFunc(("Copy loop ended with rc=%Rrc\n" ,rc)); + LogFlowThisFunc(("Copy loop ended with rc=%Rrc, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n", + rc, cbToRead, cbWrittenTotal, mSourceSize)); if ( !fCanceled || RT_SUCCESS(rc)) @@ -471,9 +537,6 @@ int SessionTaskCopyTo::Run(void) rc = setProgressSuccess(); } } - - if (!pProcess.isNull()) - pProcess->uninit(); } /* processCreateExInteral */ if (!mSourceFile) /* Only close locally opened files. */ @@ -536,7 +599,7 @@ int SessionTaskCopyFrom::Run(void) * Note: There will be races between querying file size + reading the guest file's * content because we currently *do not* lock down the guest file when doing the * actual operations. - ** @todo Implement guest file locking! + ** @todo Use the IGuestFile API for locking down the file on the guest! */ GuestFsObjData objData; int guestRc; int rc = pSession->fileQueryInfoInternal(Utf8Str(mSource), objData, &guestRc); @@ -567,8 +630,8 @@ int SessionTaskCopyFrom::Run(void) else { GuestProcessStartupInfo procInfo; - procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"), - mSource.c_str(), mDest.c_str(), objData.mObjectSize); + procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"), + mSource.c_str(), mDest.c_str(), objData.mObjectSize); procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_CAT); procInfo.mFlags = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut; @@ -579,12 +642,13 @@ int SessionTaskCopyFrom::Run(void) ComObjPtr<GuestProcess> pProcess; rc = pSession->processCreateExInteral(procInfo, pProcess); if (RT_SUCCESS(rc)) - rc = pProcess->startProcess(&guestRc); + rc = pProcess->startProcess(30 * 1000 /* 30s timeout */, + &guestRc); if (RT_FAILURE(rc)) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -613,7 +677,7 @@ int SessionTaskCopyFrom::Run(void) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -634,9 +698,9 @@ int SessionTaskCopyFrom::Run(void) /* If the guest does not support waiting for stdin, we now yield in * order to reduce the CPU load due to busy waiting. */ if (waitRes == ProcessWaitResult_WaitFlagNotSupported) - RTThreadSleep(1); /* Optional, don't check rc. */ + RTThreadYield(); /* Optional, don't check rc. */ - size_t cbRead; + uint32_t cbRead = 0; /* readData can return with VWRN_GSTCTL_OBJECTSTATE_CHANGED. */ rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf), 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf), &cbRead, &guestRc); @@ -644,7 +708,7 @@ int SessionTaskCopyFrom::Run(void) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -711,7 +775,7 @@ int SessionTaskCopyFrom::Run(void) /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write * to the destination -> access denied. */ setProgressErrorMsg(VBOX_E_IPRT_ERROR, - Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""), + Utf8StrFmt(GuestSession::tr("Unable to write \"%s\" to \"%s\": Access denied"), mSource.c_str(), mDest.c_str())); rc = VERR_GENERAL_FAILURE; /* Fudge. */ } @@ -742,9 +806,6 @@ int SessionTaskCopyFrom::Run(void) rc = setProgressSuccess(); } } - - if (!pProcess.isNull()) - pProcess->uninit(); } RTFileClose(fileDest); @@ -781,10 +842,13 @@ int SessionTaskCopyFrom::taskThread(RTTHREAD Thread, void *pvUser) } SessionTaskUpdateAdditions::SessionTaskUpdateAdditions(GuestSession *pSession, - const Utf8Str &strSource, uint32_t uFlags) + const Utf8Str &strSource, + const ProcessArguments &aArguments, + uint32_t uFlags) : GuestSessionTask(pSession) { mSource = strSource; + mArguments = aArguments; mFlags = uFlags; } @@ -793,6 +857,45 @@ SessionTaskUpdateAdditions::~SessionTaskUpdateAdditions(void) } +int SessionTaskUpdateAdditions::addProcessArguments(ProcessArguments &aArgumentsDest, + const ProcessArguments &aArgumentsSource) +{ + int rc = VINF_SUCCESS; + + try + { + /* Filter out arguments which already are in the destination to + * not end up having them specified twice. Not the fastest method on the + * planet but does the job. */ + ProcessArguments::const_iterator itSource = aArgumentsSource.begin(); + while (itSource != aArgumentsSource.end()) + { + bool fFound = false; + ProcessArguments::iterator itDest = aArgumentsDest.begin(); + while (itDest != aArgumentsDest.end()) + { + if ((*itDest).equalsIgnoreCase((*itSource))) + { + fFound = true; + break; + } + itDest++; + } + + if (!fFound) + aArgumentsDest.push_back((*itSource)); + + itSource++; + } + } + catch(std::bad_alloc &) + { + return VERR_NO_MEMORY; + } + + return rc; +} + int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFSFILE pISO, Utf8Str const &strFileSource, const Utf8Str &strFileDest, bool fOptional, uint32_t *pcbSize) @@ -820,8 +923,8 @@ int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFS /* Copy over the Guest Additions file to the guest. */ if (RT_SUCCESS(rc)) { - LogFlowThisFunc(("Copying Guest Additions installer file \"%s\" to \"%s\" on guest ...\n", - strFileSource.c_str(), strFileDest.c_str())); + LogRel(("Copying Guest Additions installer file \"%s\" to \"%s\" on guest ...\n", + strFileSource.c_str(), strFileDest.c_str())); if (RT_SUCCESS(rc)) { @@ -858,8 +961,8 @@ int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFS /* Determine where the installer image ended up and if it has the correct size. */ if (RT_SUCCESS(rc)) { - LogFlowThisFunc(("Verifying Guest Additions installer file \"%s\" ...\n", - strFileDest.c_str())); + LogRel(("Verifying Guest Additions installer file \"%s\" ...\n", + strFileDest.c_str())); GuestFsObjData objData; int64_t cbSizeOnGuest; int guestRc; @@ -874,15 +977,15 @@ int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFS { if (RT_SUCCESS(rc)) /* Size does not match. */ { - LogFlowThisFunc(("Size of Guest Additions installer file \"%s\" does not match: %RI64bytes copied, %RU64bytes expected\n", - strFileDest.c_str(), cbSizeOnGuest, cbSize)); + LogRel(("Size of Guest Additions installer file \"%s\" does not match: %RI64 bytes copied, %RU64 bytes expected\n", + strFileDest.c_str(), cbSizeOnGuest, cbSize)); rc = VERR_BROKEN_PIPE; /** @todo Find a better error. */ } else { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -899,7 +1002,7 @@ int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFS if (RT_SUCCESS(rc)) { if (pcbSize) - *pcbSize = cbSizeOnGuest; + *pcbSize = (uint32_t)cbSizeOnGuest; } } @@ -933,7 +1036,7 @@ int SessionTaskUpdateAdditions::runFileOnGuest(GuestSession *pSession, GuestProc procInfo.mCommand.c_str(), exitCode)); break; - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc)); break; @@ -1036,7 +1139,7 @@ int SessionTaskUpdateAdditions::Run(void) } Utf8Str strOSVer; - eOSType osType; + eOSType osType = eOSType_Unknown; if (RT_SUCCESS(rc)) { /* @@ -1066,21 +1169,30 @@ int SessionTaskUpdateAdditions::Run(void) * can't do automated updates here. */ /* Windows XP 64-bit (5.2) is a Windows 2003 Server actually, so skip this here. */ if ( RT_SUCCESS(rc) - && ( strOSVer.startsWith("5.0") /* Exclude the build number. */ - || strOSVer.startsWith("5.1")) /* Exclude the build number. */ - ) + && RTStrVersionCompare(strOSVer.c_str(), "5.0") >= 0) { - /* If we don't have AdditionsUpdateFlag_WaitForUpdateStartOnly set we can't continue - * because the Windows Guest Additions installer will fail because of WHQL popups. If the - * flag is set this update routine ends successfully as soon as the installer was started - * (and the user has to deal with it in the guest). */ - if (!(mFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly)) + if ( strOSVer.startsWith("5.0") /* Exclude the build number. */ + || strOSVer.startsWith("5.1") /* Exclude the build number. */) { - hr = setProgressErrorMsg(VBOX_E_NOT_SUPPORTED, - Utf8StrFmt(GuestSession::tr("Windows 2000 and XP are not supported for automatic updating due to WHQL interaction, please update manually"))); - rc = VERR_NOT_SUPPORTED; + /* If we don't have AdditionsUpdateFlag_WaitForUpdateStartOnly set we can't continue + * because the Windows Guest Additions installer will fail because of WHQL popups. If the + * flag is set this update routine ends successfully as soon as the installer was started + * (and the user has to deal with it in the guest). */ + if (!(mFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly)) + { + hr = setProgressErrorMsg(VBOX_E_NOT_SUPPORTED, + Utf8StrFmt(GuestSession::tr("Windows 2000 and XP are not supported for automatic updating due to WHQL interaction, please update manually"))); + rc = VERR_NOT_SUPPORTED; + } } } + else + { + hr = setProgressErrorMsg(VBOX_E_NOT_SUPPORTED, + Utf8StrFmt(GuestSession::tr("%s (%s) not supported for automatic updating, please update manually"), + strOSType.c_str(), strOSVer.c_str())); + rc = VERR_NOT_SUPPORTED; + } } else if (strOSType.contains("Solaris", Utf8Str::CaseInsensitive)) { @@ -1090,7 +1202,8 @@ int SessionTaskUpdateAdditions::Run(void) osType = eOSType_Linux; #if 1 /* Only Windows is supported (and tested) at the moment. */ - if (osType != eOSType_Windows) + if ( RT_SUCCESS(rc) + && osType != eOSType_Windows) { hr = setProgressErrorMsg(VBOX_E_NOT_SUPPORTED, Utf8StrFmt(GuestSession::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"), @@ -1172,15 +1285,15 @@ int SessionTaskUpdateAdditions::Run(void) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ - setProgressErrorMsg(VBOX_E_IPRT_ERROR, - GuestProcess::guestErrorToString(guestRc)); + case VERR_GSTCTL_GUEST_ERROR: + hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR, + GuestProcess::guestErrorToString(guestRc)); break; default: - setProgressErrorMsg(VBOX_E_IPRT_ERROR, - Utf8StrFmt(GuestSession::tr("Error creating installation directory \"%s\" on the guest: %Rrc"), - strUpdateDir.c_str(), rc)); + hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR, + Utf8StrFmt(GuestSession::tr("Error creating installation directory \"%s\" on the guest: %Rrc"), + strUpdateDir.c_str(), rc)); break; } } @@ -1262,6 +1375,10 @@ int SessionTaskUpdateAdditions::Run(void) * using a running VBoxTray instance via balloon messages in the * Windows taskbar. */ siInstaller.mArguments.push_back(Utf8Str("/post_installstatus")); + /* Add optional installer command line arguments from the API to the + * installer's startup info. */ + rc = addProcessArguments(siInstaller.mArguments, mArguments); + AssertRC(rc); /* If the caller does not want to wait for out guest update process to end, * complete the progress object now so that the caller can do other work. */ if (mFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly) @@ -1373,25 +1490,23 @@ int SessionTaskUpdateAdditions::Run(void) Utf8Str strError = Utf8StrFmt("No further error information available (%Rrc)", rc); if (!mProgress.isNull()) /* Progress object is optional. */ { - ComPtr<IVirtualBoxErrorInfo> pError; - hr = mProgress->COMGETTER(ErrorInfo)(pError.asOutParam()); - Assert(!pError.isNull()); - if (SUCCEEDED(hr)) + com::ProgressErrorInfo errorInfo(mProgress); + if ( errorInfo.isFullAvailable() + || errorInfo.isBasicAvailable()) { - Bstr strVal; - hr = pError->COMGETTER(Text)(strVal.asOutParam()); - if ( SUCCEEDED(hr) - && strVal.isNotEmpty()) - strError = strVal; + strError = errorInfo.getText(); } } - LogRel(("Automatic update of Guest Additions failed: %s\n", strError.c_str())); + LogRel(("Automatic update of Guest Additions failed: %s (%Rhrc)\n", + strError.c_str(), hr)); } LogRel(("Please install Guest Additions manually\n")); } + /** @todo Clean up copied / left over installation files. */ + LogFlowFuncLeaveRC(rc); return rc; } |