GuestSessionImplTasks.cpp revision 965c5f95cd56476f8dfa452efc19dd7eb10a4a56
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * VirtualBox Main - XXX.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Copyright (C) 2012 Oracle Corporation
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * available from http://www.virtualbox.org. This file is free software;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * you can redistribute it and/or modify it under the terms of the GNU
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * General Public License (GPL) as published by the Free Software
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync/*******************************************************************************
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync* Header Files *
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync*******************************************************************************/
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/*******************************************************************************
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync*******************************************************************************/
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Update file flags.
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync/** File is optional, does not have to be
c2046db2cc346cc299f0cd9b2d1e160179159cfcvboxsync * existent on the .ISO. */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/** Execute file on the guest after it has
c2046db2cc346cc299f0cd9b2d1e160179159cfcvboxsync * been successfully transfered. */
c2046db2cc346cc299f0cd9b2d1e160179159cfcvboxsync// session task classes
c2046db2cc346cc299f0cd9b2d1e160179159cfcvboxsync/////////////////////////////////////////////////////////////////////////////
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsyncGuestSessionTask::GuestSessionTask(GuestSession *pSession)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsyncint GuestSessionTask::getGuestProperty(const ComObjPtr<Guest> &pGuest,
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync ComObjPtr<Console> pConsole = pGuest->getConsole();
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync const ComPtr<IMachine> pMachine = pConsole->machine();
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync HRESULT hr = pMachine->GetGuestProperty(Bstr(strPath).raw(),
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if (mProgress.isNull()) /* Progress is optional. */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if ( SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync HRESULT hr = mProgress->SetCurrentOperationProgress(uPercent);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if (mProgress.isNull()) /* Progress is optional. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync && SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync return VERR_COM_UNEXPECTED; /** @todo Find a better rc. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsyncHRESULT GuestSessionTask::setProgressErrorMsg(HRESULT hr, const Utf8Str &strMsg)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (mProgress.isNull()) /* Progress is optional. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync && SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsyncSessionTaskCopyTo::SessionTaskCopyTo(GuestSession *pSession,
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags)
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync/** @todo Merge this and the above call and let the above call do the open/close file handling so that the
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * inner code only has to deal with file handles. No time now ... */
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsyncSessionTaskCopyTo::SessionTaskCopyTo(GuestSession *pSession,
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize,
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync if (FAILED(autoCaller.rc())) return autoCaller.rc();
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Utf8StrFmt(GuestSession::tr("Copy flags (%#x) not implemented yet"),
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Does our source file exist? */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Utf8StrFmt(GuestSession::tr("Source file \"%s\" does not exist or is not a file"),
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Utf8StrFmt(GuestSession::tr("Could not open source file \"%s\" for reading: %Rrc"),
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Utf8StrFmt(GuestSession::tr("Could not query file size of \"%s\": %Rrc"),
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync /* Size + offset are optional. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to the guest to \"%s\" (%RU64 bytes)"),
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Set arguments.*/
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync procInfo.mArguments.push_back(Utf8StrFmt("--output=%s", mDest.c_str())); /** @todo Do we need path conversion? */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Startup process. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = pSession->processCreateExInteral(procInfo, pProcess);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Utf8StrFmt(GuestSession::tr("Unable to start guest process: %Rrc"), rc));
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync && waitRes.mResult != ProcessWaitResult_WaitFlagNotSupported))
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* If the guest does not support waiting for stdin, we now yield in
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * order to reduce the CPU load due to busy waiting. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (mSourceSize) /* If we have nothing to write, take a shortcut. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /** @todo Not very efficient, but works for now. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = RTFileSeek(*pFile, mSourceOffset + cbWrittenTotal,
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Some other error occured? There might be a chance that RTFileRead
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * could not resolve/map the native error code to an IPRT code, so just
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * print a generic error.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Utf8StrFmt(GuestSession::tr("Could not read from file \"%s\" (%Rrc)"),
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Utf8StrFmt(GuestSession::tr("Seeking file \"%s\" offset %RU64 failed: %Rrc"),
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Did we reach the end of the content we want to transfer (last chunk)? */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Did we reach the last block which is exactly _64K? */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* ... or does the user want to cancel? */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync || ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Utf8StrFmt(GuestSession::tr("Writing to file \"%s\" (offset %RU64) failed: %Rrc"),
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync LogFlowThisFunc(("cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n",
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync cbWritten, cbToRead - cbWritten, cbWrittenTotal + cbWritten, mSourceSize));
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Only subtract bytes reported written by the guest. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Update total bytes written to the guest. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Did the user cancel the operation above? */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Update the progress.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Watch out for division by zero. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync ? rc = setProgress((ULONG)(cbWrittenTotal * 100 / mSourceSize))
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* End of file reached? */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync } /* for */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Even if we succeeded until here make sure to check whether we really transfered
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * everything.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * to the destination -> access denied. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""),
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* If we did not copy all let the user know. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed (%RU64/%RU64 bytes transfered)"),
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = pProcess->waitFor(ProcessWaitForFlag_Terminate,
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed: %Rrc"),
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed with wait result %ld"),
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if ( ( SUCCEEDED(pProcess->COMGETTER(Status(&procStatus)))
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync || ( SUCCEEDED(pProcess->COMGETTER(ExitCode(&exitCode)))
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed with status %ld, exit code %ld"),
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync mSource.c_str(), procStatus, exitCode)); /**@todo Add stringify methods! */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync } /* processCreateExInteral */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if (!mSourceFile) /* Only close locally opened files. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsyncint SessionTaskCopyTo::RunAsync(const Utf8Str &strDesc, ComObjPtr<Progress> &pProgress)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync LogFlowThisFunc(("strDesc=%s, strSource=%s, strDest=%s, mCopyFileFlags=%x\n",
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync strDesc.c_str(), mSource.c_str(), mDest.c_str(), mCopyFileFlags));
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync int rc = RTThreadCreate(NULL, SessionTaskCopyTo::taskThread, this,
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync "gctlCpyTo");
611e5e148a74d4b54cf76c97e4d36acaa816d8c0vboxsync/* static */
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsyncint SessionTaskCopyTo::taskThread(RTTHREAD Thread, void *pvUser)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync std::auto_ptr<SessionTaskCopyTo> task(static_cast<SessionTaskCopyTo*>(pvUser));
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsyncSessionTaskCopyFrom::SessionTaskCopyFrom(GuestSession *pSession,
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags)
RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); /** @todo Use the correct open modes! */
procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"),
Utf8StrFmt(GuestSession::tr("Unable to start guest process for copying data from guest to host: %Rrc"), rc));
&cbRead);
if (cbRead)
&& fCanceled)
if ( !fCanceled
&& cbWrittenTotal == 0)
&& exitCode != 0)
return rc;
return rc;
if (fOptional)
return VINF_SUCCESS;
return rc;
rc = pSession->startTaskAsync(Utf8StrFmt(GuestSession::tr("Copying Guest Additions installer file \"%s\" to \"%s\" on guest"),
&& fCanceled)
LogRel(("Size of Guest Additions installer file \"%s\" does not match: %RI64bytes copied, %RU64bytes expected\n",
if (pcbSize)
return rc;
&& exitCode != 0)
return rc;
return rc;
Utf8StrFmt(GuestSession::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"),
switch (eOSType)
case eOSType_Windows:
case eOSType_Linux:
case eOSType_Solaris:
itFiles++;
itFiles++;
return rc;
return rc;