GuestSessionImpl.cpp revision ca3db470494a8b6eaec69ea37468a5cda65e2da8
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * VirtualBox Main - XXX.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * Copyright (C) 2012 Oracle Corporation
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * available from http://www.virtualbox.org. This file is free software;
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * you can redistribute it and/or modify it under the terms of the GNU
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * General Public License (GPL) as published by the Free Software
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/*******************************************************************************
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync* Header Files *
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync*******************************************************************************/
6b9d50a0f466bd5a61458ed53925480ab28a3c17vboxsync// constructor / destructor
0fd108a555ae02f2fb557d5f2c40281999b60d15vboxsync/////////////////////////////////////////////////////////////////////////////
0fd108a555ae02f2fb557d5f2c40281999b60d15vboxsync// session task classes
6b9d50a0f466bd5a61458ed53925480ab28a3c17vboxsync/////////////////////////////////////////////////////////////////////////////
6b9d50a0f466bd5a61458ed53925480ab28a3c17vboxsyncGuestSessionTask::GuestSessionTask(GuestSession *pSession)
6b9d50a0f466bd5a61458ed53925480ab28a3c17vboxsync if (mProgress.isNull()) /* Progress is optional. */
c740281e4f5e61397e892447aeef2a7bdbbaaf8dvboxsync if ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
0fd108a555ae02f2fb557d5f2c40281999b60d15vboxsync if ( SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))
0fd108a555ae02f2fb557d5f2c40281999b60d15vboxsync HRESULT hr = mProgress->SetCurrentOperationProgress(uPercent);
3d33b6a3faf40871bae75119c2569cdc4acb2d46vboxsync if (mProgress.isNull()) /* Progress is optional. */
0fd108a555ae02f2fb557d5f2c40281999b60d15vboxsync if ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
0fd108a555ae02f2fb557d5f2c40281999b60d15vboxsync && SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))
6b9d50a0f466bd5a61458ed53925480ab28a3c17vboxsync return VERR_COM_UNEXPECTED; /** @todo Find a better rc. */
0fd108a555ae02f2fb557d5f2c40281999b60d15vboxsyncHRESULT GuestSessionTask::setProgressErrorMsg(HRESULT hr, const Utf8Str &strMsg)
6b9d50a0f466bd5a61458ed53925480ab28a3c17vboxsync if (mProgress.isNull()) /* Progress is optional. */
0fd108a555ae02f2fb557d5f2c40281999b60d15vboxsync if ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
0fd108a555ae02f2fb557d5f2c40281999b60d15vboxsync && SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsyncSessionTaskCopyTo::SessionTaskCopyTo(GuestSession *pSession,
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags)
cd059a6642b11828bd0ad8b3108f5f7f611d144fvboxsync/** @todo Merge this and the above call and let the above call do the open/close file handling so that the
cd059a6642b11828bd0ad8b3108f5f7f611d144fvboxsync * inner code only has to deal with file handles. No time now ... */
cd059a6642b11828bd0ad8b3108f5f7f611d144fvboxsyncSessionTaskCopyTo::SessionTaskCopyTo(GuestSession *pSession,
cd059a6642b11828bd0ad8b3108f5f7f611d144fvboxsync PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize,
7c3bf57b1f6df237b1075e7cae6b188db6fc636avboxsync if (FAILED(autoCaller.rc())) return autoCaller.rc();
3c6306a66deef467e3c13483dd6529e1e1c6b822vboxsync Utf8StrFmt(GuestSession::tr("Copy flags (%#x) not implemented yet"),
cd059a6642b11828bd0ad8b3108f5f7f611d144fvboxsync /* Does our source file exist? */
c4b821bf03ae7641a0791e3fd161247e66433b68vboxsync Utf8StrFmt(GuestSession::tr("Source file \"%s\" does not exist or is not a file"),
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
cd059a6642b11828bd0ad8b3108f5f7f611d144fvboxsync Utf8StrFmt(GuestSession::tr("Could not open source file \"%s\" for reading: %Rrc"),
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync Utf8StrFmt(GuestSession::tr("Could not query file size of \"%s\": %Rrc"),
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync /* Size + offset are optional. */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to the guest to \"%s\" (%RU64 bytes)"),
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync /* Set arguments.*/
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync procInfo.mArguments.push_back(Utf8StrFmt("--output=%s", mDest.c_str())); /** @todo Do we need path conversion? */
06ea6bcf23874b662d499b3f130024c98b2dd7a6vboxsync /* Startup process. */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync rc = pSession->processCreateExInteral(procInfo, pProcess);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync Utf8StrFmt(GuestSession::tr("Unable to start guest process: %Rrc"), rc));
92e624e40b06b4dc6d0a8222e1de33bd3e879a63vboxsync if (mSourceSize) /* If we have nothing to write, take a shortcut. */
36f3c24e4ad9c6b813767db1faeabbe7e2ecc057vboxsync /** @todo Not very efficient, but works for now. */
9523921c89c66f4bececdbd5ac95aed0039eda1bvboxsync rc = RTFileSeek(*pFile, mSourceOffset + cbWrittenTotal,
9523921c89c66f4bececdbd5ac95aed0039eda1bvboxsync * Some other error occured? There might be a chance that RTFileRead
06ea6bcf23874b662d499b3f130024c98b2dd7a6vboxsync * could not resolve/map the native error code to an IPRT code, so just
06ea6bcf23874b662d499b3f130024c98b2dd7a6vboxsync * print a generic error.
06ea6bcf23874b662d499b3f130024c98b2dd7a6vboxsync Utf8StrFmt(GuestSession::tr("Could not read from file \"%s\" (%Rrc)"),
7862f4bd000f1eb6c86289f5ac2849e9cf943ca9vboxsync Utf8StrFmt(GuestSession::tr("Seeking file \"%s\" offset %RU64 failed: %Rrc"),
04f6f18325971f796623469adcf39ba2b2939ed3vboxsync /* Did we reach the end of the content we want to transfer (last chunk)? */
ca3db470494a8b6eaec69ea37468a5cda65e2da8vboxsync /* Did we reach the last block which is exactly _64K? */
ca3db470494a8b6eaec69ea37468a5cda65e2da8vboxsync /* ... or does the user want to cancel? */
ca3db470494a8b6eaec69ea37468a5cda65e2da8vboxsync || ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
04f6f18325971f796623469adcf39ba2b2939ed3vboxsync Utf8StrFmt(GuestSession::tr("Writing to file \"%s\" (offset %RU64) failed: %Rrc"),
24ef2ade0f53030e73f5b4e43f52892b03f7915dvboxsync LogFlowThisFunc(("cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n",
687794577e2e35c3cae67e692a7f2130d1262a82vboxsync cbWritten, cbToRead - cbWritten, cbWrittenTotal + cbWritten, mSourceSize));
f9ce005e61f0fbb51a2cabc53d58c3485151faa9vboxsync /* Only subtract bytes reported written by the guest. */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync /* Update total bytes written to the guest. */
02f7c106d33c45f99ec412a5fe0adde868f700fcvboxsync /* Did the user cancel the operation above? */
d4a9d525e6f2111d462d2d96462dced6b9ec00efvboxsync /* Update the progress.
d4a9d525e6f2111d462d2d96462dced6b9ec00efvboxsync * Watch out for division by zero. */
d4a9d525e6f2111d462d2d96462dced6b9ec00efvboxsync ? rc = setProgress((ULONG)(cbWrittenTotal * 100 / mSourceSize))
d4a9d525e6f2111d462d2d96462dced6b9ec00efvboxsync /* End of file reached? */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync } /* for */
02f7c106d33c45f99ec412a5fe0adde868f700fcvboxsync * Even if we succeeded until here make sure to check whether we really transfered
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * everything.
04f6f18325971f796623469adcf39ba2b2939ed3vboxsync /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * to the destination -> access denied. */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""),
Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed with wait result %ld"),
&& exitCode != 0)
return rc;
return rc;
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)
#ifdef VBOX_SERVICE_ENVARG_BUG
Utf8Str strFileDestBug = "C:\\Windows\\system32\\EMP" + strFileDest.substr(sizeof("%TEMP%\\") - sizeof(char));
if (pcbSize)
return rc;
#ifdef VBOX_SERVICE_ENVARG_BUG
procInfo.mCommand = "C:\\Windows\\system32\\EMP" + procInfo.mCommand.substr(sizeof("%TEMP%\\") - sizeof(char));
&& exitCode != 0)
return rc;
return rc;
Utf8StrFmt(GuestSession::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"),
bool fInstallCertificates = false;
fInstallCertificates = true;
Utf8StrFmt(GuestSession::tr("Error while copying certificate installation tool to the guest: %Rrc"), rc));
#ifdef VBOX_SERVICE_ENVARG_BUG
#ifdef VBOX_SERVICE_ENVARG_BUG
return rc;
return rc;
// public initializer/uninitializer for internal purposes only
return VINF_SUCCESS;
#ifdef VBOX_WITH_GUEST_CONTROL
#ifndef VBOX_WITH_GUEST_CONTROL
return S_OK;
#ifndef VBOX_WITH_GUEST_CONTROL
return S_OK;
#ifndef VBOX_WITH_GUEST_CONTROL
return S_OK;
#ifndef VBOX_WITH_GUEST_CONTROL
return S_OK;
#ifndef VBOX_WITH_GUEST_CONTROL
return S_OK;
#ifndef VBOX_WITH_GUEST_CONTROL
return S_OK;
#ifndef VBOX_WITH_GUEST_CONTROL
return S_OK;
#ifndef VBOX_WITH_GUEST_CONTROL
return hr;
#ifndef VBOX_WITH_GUEST_CONTROL
return S_OK;
#ifndef VBOX_WITH_GUEST_CONTROL
return S_OK;
#ifndef VBOX_WITH_GUEST_CONTROL
return S_OK;
return VINF_SUCCESS;
return VERR_NOT_FOUND;
int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags, ComObjPtr<GuestDirectory> &pDirectory)
procInfo.mArguments.push_back(Utf8Str("--parents")); /* We also want to create the parent directories. */
if (uMode)
if (lExitCode != 0)
return VERR_CANT_CREATE;
return rc;
return VERR_COM_UNEXPECTED;
return rc;
return rc;
bool fDirectory,
if (fDirectory)
if (fDirectory)
&cbRead);
if (cbRead)
const char *pcszName;
if (pcszName)
return rc;
return VERR_COM_UNEXPECTED;
return rc;
return rc;
int GuestSession::dispatchToProcess(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData)
#ifdef DEBUG
int rc;
return rc;
return VINF_SUCCESS;
return VERR_NOT_FOUND;
&cbRead);
if (cbRead)
return rc;
int GuestSession::fileOpenInternal(const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition,
LogFlowThisFunc(("strPath=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%x, iOffset=%RI64\n",
return VERR_COM_UNEXPECTED;
return rc;
return rc;
&cbRead);
if (cbRead)
return rc;
return rc;
LogFlowFunc(("Removing process (Session: %RU32) with process ID=%RU32, guest PID=%RU32 (now total %ld processes)\n",
mData.mId, itProcs->second->getProcessID(), itProcs->second->getPID(), mData.mProcesses.size() - 1));
return VINF_SUCCESS;
return VERR_NOT_FOUND;
int GuestSession::processCreateExInteral(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
#ifdef DEBUG
it++;
return VERR_INVALID_PARAMETER;
return rc;
uNewProcessID = 0;
return rc;
return VERR_COM_UNEXPECTED;
return rc;
LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes)\n",
return rc;
if (pProcess)
return VERR_COM_INVALID_OBJECT_STATE;
if (pProcess)
return VINF_SUCCESS;
return VERR_NOT_FOUND;
return VERR_COM_UNEXPECTED;
return VERR_COM_UNEXPECTED;
return rc;
return rc;
static short s_gctrlLegacyWarning = 0;
LogRel((tr("Warning: Guest Additions are older (%ld.%ld) than host capabilities for guest control, please upgrade them. Using protocol version %ld now\n"),
VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions), VBOX_FULL_VERSION_GET_MINOR(uVerAdditions), mData.mProtocolVersion));
return VINF_SUCCESS;
#ifndef VBOX_WITH_GUEST_CONTROL
uninit();
return S_OK;
STDMETHODIMP GuestSession::CopyFrom(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
#ifndef VBOX_WITH_GUEST_CONTROL
if (aFlags)
int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from guest to \"%ls\" on the host"), aSource, aDest),
return hr;
STDMETHODIMP GuestSession::CopyTo(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
#ifndef VBOX_WITH_GUEST_CONTROL
if (aFlags)
int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from host to \"%ls\" on the guest"), aSource, aDest),
return hr;
#ifndef VBOX_WITH_GUEST_CONTROL
if (aFlags)
if (fFlags)
if (aDirectory)
switch (rc)
case VERR_INVALID_PARAMETER:
case VERR_BROKEN_PIPE:
case VERR_CANT_CREATE:
return hr;
STDMETHODIMP GuestSession::DirectoryCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, BSTR *aDirectory)
#ifndef VBOX_WITH_GUEST_CONTROL
return E_FAIL;
: S_OK;
rc);
return S_OK;
return E_OUTOFMEMORY;
#ifndef VBOX_WITH_GUEST_CONTROL
switch (rc)
return hr;
STDMETHODIMP GuestSession::DirectoryOpen(IN_BSTR aPath, IN_BSTR aFilter, ComSafeArrayIn(DirectoryOpenFlag_T, aFlags), IGuestDirectory **aDirectory)
#ifndef VBOX_WITH_GUEST_CONTROL
if (aFlags)
if (fFlags)
if (aDirectory)
switch (rc)
case VERR_INVALID_PARAMETER:
case VERR_BROKEN_PIPE:
return hr;
#ifndef VBOX_WITH_GUEST_CONTROL
#ifndef VBOX_WITH_GUEST_CONTROL
STDMETHODIMP GuestSession::DirectoryRemoveRecursive(IN_BSTR aPath, ComSafeArrayIn(DirectoryRemoveRecFlag_T, aFlags), IProgress **aProgress)
#ifndef VBOX_WITH_GUEST_CONTROL
STDMETHODIMP GuestSession::DirectoryRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
#ifndef VBOX_WITH_GUEST_CONTROL
#ifndef VBOX_WITH_GUEST_CONTROL
#ifndef VBOX_WITH_GUEST_CONTROL
return S_OK;
#ifndef VBOX_WITH_GUEST_CONTROL
return S_OK;
#ifndef VBOX_WITH_GUEST_CONTROL
return hr;
#ifndef VBOX_WITH_GUEST_CONTROL
return S_OK;
STDMETHODIMP GuestSession::FileCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, IGuestFile **aFile)
#ifndef VBOX_WITH_GUEST_CONTROL
#ifndef VBOX_WITH_GUEST_CONTROL
switch (rc)
return hr;
#ifndef VBOX_WITH_GUEST_CONTROL
int rc2;
return E_OUTOFMEMORY;
return S_OK;
STDMETHODIMP GuestSession::FileOpen(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, ULONG aCreationMode, LONG64 aOffset, IGuestFile **aFile)
#ifndef VBOX_WITH_GUEST_CONTROL
switch (rc)
return hr;
#ifndef VBOX_WITH_GUEST_CONTROL
#ifndef VBOX_WITH_GUEST_CONTROL
switch (rc)
return hr;
STDMETHODIMP GuestSession::FileRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
#ifndef VBOX_WITH_GUEST_CONTROL
#ifndef VBOX_WITH_GUEST_CONTROL
STDMETHODIMP GuestSession::ProcessCreate(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
#ifndef VBOX_WITH_GUEST_CONTROL
HRESULT hr = ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),
ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess);
return hr;
STDMETHODIMP GuestSession::ProcessCreateEx(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
#ifndef VBOX_WITH_GUEST_CONTROL
if (aArguments)
* have the chance of overwriting/deleting session entries.
if (aEnvironment)
if (aFlags)
if (aAffinity)
switch (rc)
case VERR_MAX_PROCS_REACHED:
return hr;
#ifndef VBOX_WITH_GUEST_CONTROL
if (aPID == 0)
return hr;
#ifndef VBOX_WITH_GUEST_CONTROL
#ifndef VBOX_WITH_GUEST_CONTROL
STDMETHODIMP GuestSession::SymlinkRead(IN_BSTR aSymlink, ComSafeArrayIn(SymlinkReadFlag_T, aFlags), BSTR *aTarget)
#ifndef VBOX_WITH_GUEST_CONTROL
#ifndef VBOX_WITH_GUEST_CONTROL
#ifndef VBOX_WITH_GUEST_CONTROL