VirtualBox

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


Ignore:
Timestamp:
Jul 29, 2011 10:07:03 AM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
73214
Message:

GuestCtrl: Update.

Location:
trunk/src/VBox/Main
Files:
3 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/Makefile.kmk

    r38192 r38235  
    654654        src-client/ConsoleVRDPServer.cpp \
    655655        src-client/DisplayImpl.cpp \
     656        src-client/GuestImpl.cpp \
    656657        src-client/GuestCtrlImpl.cpp \
    657658        src-client/GuestCtrlIO.cpp \
    658         src-client/GuestImpl.cpp \
     659        src-client/GuestCtrlImplDir.cpp \
     660        src-client/GuestCtrlImplFile.cpp \
    659661        src-client/KeyboardImpl.cpp \
    660662        src-client/MachineDebuggerImpl.cpp \
     
    673675        src-client/win/VBoxC.rc
    674676
     677ifdef VBOX_WITH_GUEST_CONTROL
     678VBoxC_SOURCES += \
     679        src-client/GuestCtrlImplTasks.cpp
     680endif
    675681
    676682ifdef VBOX_WITH_XPCOM
  • trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h

    r38212 r38235  
    11/** @file
    22 *
    3  * VirtualBox guest execution control private data definitions
     3 * VirtualBox Guest Control - Private data definitions / classes.
    44 */
    55
     
    3333#endif
    3434
     35class Guest;
     36class Progress;
     37
    3538/** Structure representing the "value" side of a "key=value" pair. */
    3639typedef struct VBOXGUESTCTRL_STREAM_PAIR
     
    3942} VBOXGUESTCTRL_STREAM_PAIR, *PVBOXGUESTCTRL_STREAM_PAIR;
    4043
    41 /** Map containing "key=value" pairs of a stream object. */
     44/** Map containing "key=value" pairs of a guest process stream. */
    4245typedef std::map< Utf8Str, VBOXGUESTCTRL_STREAM_PAIR > GuestCtrlStreamPairs;
    4346typedef std::map< Utf8Str, VBOXGUESTCTRL_STREAM_PAIR >::iterator GuestCtrlStreamPairsIter;
     
    6770    size_t GetNumPairs();
    6871
    69     uint32_t GetOffsetBuffer();
    70 
    71     uint32_t GetOffsetParser();
     72    uint32_t GetOffset();
    7273
    7374    const char* GetString(const char *pszKey);
     
    7778    uint32_t GetUInt32(const char *pszKey);
    7879
    79     int Parse();
     80    int ParseBlock();
    8081
    8182protected:
     
    8889    uint32_t m_cbSize;
    8990    /** Current offset within the internal stream buffer. */
    90     uint32_t m_cbOffsetBuffer;
    91     /** Current parser offset. */
    92     uint32_t m_cbOffsetParser;
     91    uint32_t m_cbOffset;
    9392    /** Internal stream buffer. */
    9493    BYTE *m_pbBuffer;
    9594};
     95
     96struct GuestTask
     97{
     98    enum TaskType
     99    {
     100        /** Copies a file from host to the guest. */
     101        TaskType_CopyFileToGuest   = 50,
     102        /** Copies a file from guest to the host. */
     103        TaskType_CopyFileFromGuest = 55,
     104        /** Update Guest Additions by directly copying the required installer
     105         *  off the .ISO file, transfer it to the guest and execute the installer
     106         *  with system privileges. */
     107        TaskType_UpdateGuestAdditions = 100
     108    };
     109
     110    GuestTask(TaskType aTaskType, Guest *aThat, Progress *aProgress);
     111
     112    virtual ~GuestTask();
     113
     114    int startThread();
     115
     116    static int taskThread(RTTHREAD aThread, void *pvUser);
     117    static int uploadProgress(unsigned uPercent, void *pvUser);
     118    static HRESULT setProgressErrorInfo(HRESULT hr,
     119                                        ComObjPtr<Progress> pProgress, const char * pszText, ...);
     120    static HRESULT setProgressErrorInfo(HRESULT hr,
     121                                        ComObjPtr<Progress> pProgress, ComObjPtr<Guest> pGuest);
     122
     123    TaskType taskType;
     124    Guest *pGuest;
     125    ComObjPtr<Progress> progress;
     126    HRESULT rc;
     127
     128    /* Task data. */
     129    Utf8Str strSource;
     130    Utf8Str strDest;
     131    Utf8Str strUserName;
     132    Utf8Str strPassword;
     133    ULONG   uFlags;
     134};
    96135#endif // ____H_GUESTIMPLPRIVATE
    97136
  • trunk/src/VBox/Main/include/GuestImpl.h

    r38085 r38235  
    2424
    2525#include "AdditionsFacilityImpl.h"
     26#include "GuestCtrlImplPrivate.h"
     27#include "HGCM.h"
    2628#ifdef VBOX_WITH_GUEST_CONTROL
    2729# include <VBox/HostServices/GuestControlSvc.h>
    28 # include "HGCM.h"
    2930using namespace guestControl;
    3031#endif
     
    115116
    116117    // Public methods that are not in IDL (only called internally).
     118    void setAdditionsInfo(Bstr aInterfaceVersion, VBOXOSTYPE aOsType);
     119    void setAdditionsInfo2(Bstr aAdditionsVersion, Bstr aVersionName, Bstr aRevision);
     120    bool facilityIsActive(VBoxGuestFacilityType enmFacility);
     121    HRESULT facilityUpdate(VBoxGuestFacilityType enmFacility, VBoxGuestFacilityStatus enmStatus);
     122    void setAdditionsStatus(VBoxGuestFacilityType enmFacility, VBoxGuestFacilityStatus enmStatus, ULONG aFlags);
     123    void setSupportedFeatures(uint32_t aCaps);
     124    HRESULT setStatistic(ULONG aCpuId, GUESTSTATTYPE enmType, ULONG aVal);
     125    BOOL isPageFusionEnabled();
     126    static HRESULT setErrorStatic(HRESULT aResultCode,
     127                                  const Utf8Str &aText)
     128    {
     129        return setErrorInternal(aResultCode, getStaticClassIID(), getStaticComponentName(), aText, false, true);
     130    }
     131
     132# ifdef VBOX_WITH_GUEST_CONTROL
    117133    HRESULT directoryCreateInternal(IN_BSTR aDirectory, IN_BSTR aUserName, IN_BSTR aPassword,
    118134                                    ULONG aMode, ULONG aFlags, int *pRC);
     
    127143    HRESULT fileExistsInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists, int *pRC);
    128144    HRESULT fileQuerySizeInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, LONG64 *aSize, int *pRC);
    129     void setAdditionsInfo(Bstr aInterfaceVersion, VBOXOSTYPE aOsType);
    130     void setAdditionsInfo2(Bstr aAdditionsVersion, Bstr aVersionName, Bstr aRevision);
    131     bool facilityIsActive(VBoxGuestFacilityType enmFacility);
    132     HRESULT facilityUpdate(VBoxGuestFacilityType enmFacility, VBoxGuestFacilityStatus enmStatus);
    133     void setAdditionsStatus(VBoxGuestFacilityType enmFacility, VBoxGuestFacilityStatus enmStatus, ULONG aFlags);
    134     void setSupportedFeatures(uint32_t aCaps);
    135     HRESULT setStatistic(ULONG aCpuId, GUESTSTATTYPE enmType, ULONG aVal);
    136     BOOL isPageFusionEnabled();
    137 # ifdef VBOX_WITH_GUEST_CONTROL
     145
     146    // Guest control dispatcher.
    138147    /** Static callback for handling guest notifications. */
    139148    static DECLCALLBACK(int) notifyCtrlDispatcher(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms);
     149
     150    // Internal tasks.
     151    //extern struct GuestTask;
     152    HRESULT taskCopyFileToGuest(GuestTask *aTask);
     153    HRESULT taskCopyFileFromGuest(GuestTask *aTask);
     154    HRESULT taskUpdateGuestAdditions(GuestTask *aTask);
    140155# endif
    141     static HRESULT setErrorStatic(HRESULT aResultCode,
    142                                   const Utf8Str &aText)
    143     {
    144         return setErrorInternal(aResultCode, getStaticClassIID(), getStaticComponentName(), aText, false, true);
    145     }
    146156
    147157private:
     158
    148159#ifdef VBOX_WITH_GUEST_CONTROL
    149     // Internal tasks.
    150     struct TaskGuest; /* Worker thread helper. */
    151     HRESULT taskCopyFileToGuest(TaskGuest *aTask);
    152     HRESULT taskCopyFileFromGuest(TaskGuest *aTask);
    153     HRESULT taskUpdateGuestAdditions(TaskGuest *aTask);
    154 
    155160    // Internal guest callback representation.
    156161    typedef struct VBOXGUESTCTRL_CALLBACK
     
    207212        char    *mpszDirectory;
    208213        char    *mpszFilter;
    209         ULONG    uFlags;
     214        ULONG    mFlags;
    210215        /** Associated PID of started vbox_ls tool. */
    211216        uint32_t mPID;
     
    217222    typedef std::map< uint32_t, VBOXGUESTCTRL_DIRECTORY >::const_iterator GuestDirectoryMapIterConst;
    218223
    219     int directoryCreateHandle(ULONG *puHandle, const char *pszDirectory, const char *pszFilter, ULONG uFlags);
     224    int directoryCreateHandle(ULONG *puHandle, ULONG uPID, const char *pszDirectory, const char *pszFilter, ULONG uFlags);
    220225    void directoryDestroyHandle(uint32_t uHandle);
    221226    uint32_t directoryGetPID(uint32_t uHandle);
  • trunk/src/VBox/Main/src-client/GuestCtrlIO.cpp

    r38212 r38235  
    3232    : m_cbAllocated(0),
    3333      m_cbSize(0),
    34       m_cbOffsetBuffer(0),
    35       m_cbOffsetParser(0),
     34      m_cbOffset(0),
    3635      m_pbBuffer(NULL)
    3736{
     
    4443}
    4544
    46 
     45/**
     46 * Adds data to the internal parser buffer. Useful if there
     47 * are multiple rounds of adding data needed.
     48 *
     49 * @return  IPRT status code.
     50 * @param   pbData              Pointer to data to add.
     51 * @param   cbData              Size (in bytes) of data to add.
     52 */
    4753int GuestProcessStream::AddData(const BYTE *pbData, size_t cbData)
    4854{
     
    5359
    5460    /* Rewind the buffer if it's empty. */
    55     size_t     cbInBuf   = m_cbSize - m_cbOffsetBuffer;
     61    size_t     cbInBuf   = m_cbSize - m_cbOffset;
    5662    bool const fAddToSet = cbInBuf == 0;
    5763    if (fAddToSet)
    58         m_cbSize = m_cbOffsetBuffer = 0;
     64        m_cbSize = m_cbOffset = 0;
    5965
    6066    /* Try and see if we can simply append the data. */
     
    6773    {
    6874        /* Move any buffered data to the front. */
    69         cbInBuf = m_cbSize - m_cbOffsetBuffer;
     75        cbInBuf = m_cbSize - m_cbOffset;
    7076        if (cbInBuf == 0)
    71             m_cbSize = m_cbOffsetBuffer = 0;
    72         else if (m_cbOffsetBuffer) /* Do we have something to move? */
    73         {
    74             memmove(m_pbBuffer, &m_pbBuffer[m_cbOffsetBuffer], cbInBuf);
     77            m_cbSize = m_cbOffset = 0;
     78        else if (m_cbOffset) /* Do we have something to move? */
     79        {
     80            memmove(m_pbBuffer, &m_pbBuffer[m_cbOffset], cbInBuf);
    7581            m_cbSize = cbInBuf;
    76             m_cbOffsetBuffer = 0;
     82            m_cbOffset = 0;
    7783        }
    7884
     
    108114}
    109115
     116/**
     117 * Destroys the currently stored stream pairs.
     118 *
     119 * @return  IPRT status code.
     120 */
    110121void GuestProcessStream::ClearPairs()
    111122{
     
    120131
    121132/**
    122  * Destroys the stored stream pairs.
     133 * Destroys the currently stored stream pairs and the internal
     134 * data buffer.
    123135 */
    124136void GuestProcessStream::Destroy()
     
    127139
    128140    if (m_pbBuffer)
     141    {
    129142        RTMemFree(m_pbBuffer);
    130 }
    131 
     143        m_pbBuffer = NULL;
     144    }
     145
     146    m_cbAllocated = 0;
     147    m_cbSize = 0;
     148    m_cbOffset = 0;
     149}
     150
     151/**
     152 * Returns a 64-bit signed integer of a specified key.
     153 *
     154 * @return  IPRT status code. VERR_NOT_FOUND if key was not found.
     155 * @param  pszKey               Name of key to get the value for.
     156 * @param  piVal                Pointer to value to return.
     157 */
    132158int GuestProcessStream::GetInt64Ex(const char *pszKey, int64_t *piVal)
    133159{
     
    167193}
    168194
    169 uint32_t GuestProcessStream::GetOffsetBuffer()
    170 {
    171     return m_cbOffsetBuffer;
    172 }
    173 
    174 uint32_t GuestProcessStream::GetOffsetParser()
    175 {
    176     return m_cbOffsetParser;
    177 }
    178 
    179 /**
    180  * Returns a 32-bit unsigned integer of a specified key.
    181  *
    182  * @return  uint32_t            Value to return, 0 if not found / on failure.
     195/**
     196 * Returns the current offset of the parser within
     197 * the internal data buffer.
     198 *
     199 * @return  uint32_t            Parser offset.
     200 */
     201uint32_t GuestProcessStream::GetOffset()
     202{
     203    return m_cbOffset;
     204}
     205
     206/**
     207 * Returns a string value of a specified key.
     208 *
     209 * @return  uint32_t            Pointer to string to return, NULL if not found / on failure.
    183210 * @param   pszKey              Name of key to get the value for.
    184211 */
     
    200227}
    201228
     229/**
     230 * Returns a 32-bit unsigned integer of a specified key.
     231 *
     232 * @return  IPRT status code. VERR_NOT_FOUND if key was not found.
     233 * @param  pszKey               Name of key to get the value for.
     234 * @param  puVal                Pointer to value to return.
     235 */
    202236int GuestProcessStream::GetUInt32Ex(const char *pszKey, uint32_t *puVal)
    203237{
     
    227261}
    228262
    229 int GuestProcessStream::Parse()
     263/**
     264 * Try to parse the next upcoming pair block within the internal
     265 * buffer. Old pairs from a previously parsed block will be removed first!
     266 *
     267 * @return  IPRT status code.
     268 */
     269int GuestProcessStream::ParseBlock()
    230270{
    231271    AssertPtrReturn(m_pbBuffer, VINF_SUCCESS);
    232272    AssertReturn(m_cbSize, VINF_SUCCESS);
    233     AssertReturn(m_cbOffsetParser <= m_cbSize, VERR_INVALID_PARAMETER);
     273    AssertReturn(m_cbOffset <= m_cbSize, VERR_INVALID_PARAMETER);
     274
     275    /* Since we want to (try to) parse another block, clear
     276     * all pairs from a previously parsed block. */
     277    ClearPairs();
    234278
    235279    int rc = VINF_SUCCESS;
    236280
    237     size_t uCur = m_cbOffsetParser;
     281    size_t uCur = m_cbOffset;
    238282    for (;uCur < m_cbSize;)
    239283    {
     
    263307                || pszSep == pszEnd)
    264308            {
    265                 m_cbOffsetParser =  uCur - uPairLen - 1;
     309                m_cbOffset =  uCur - uPairLen - 1;
    266310                rc = VERR_MORE_DATA;
    267311            }
     
    304348                RTMemFree(pszKey);
    305349
    306                 m_cbOffsetParser += uCur - m_cbOffsetParser;
     350                m_cbOffset += uCur - m_cbOffset;
    307351            }
    308352        }
     
    313357                if (*pszEnd == '\0')
    314358                {
    315                     m_cbOffsetParser = uCur;
     359                    m_cbOffset = uCur;
    316360                    rc = VERR_MORE_DATA;
    317361                    break;
     
    325369    }
    326370
    327     RT_CLAMP(m_cbOffsetParser, 0, m_cbSize);
     371    RT_CLAMP(m_cbOffset, 0, m_cbSize);
    328372
    329373    return rc;
  • trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp

    r38182 r38235  
    4141
    4242#include <memory>
    43 
    44 struct Guest::TaskGuest
    45 {
    46     enum TaskType
    47     {
    48         /** Copies a file from host to the guest. */
    49         CopyFileToGuest   = 50,
    50         /** Copies a file from guest to the host. */
    51         CopyFileFromGuest = 55,
    52 
    53         /** Update Guest Additions by directly copying the required installer
    54          *  off the .ISO file, transfer it to the guest and execute the installer
    55          *  with system privileges. */
    56         UpdateGuestAdditions = 100
    57     };
    58 
    59     TaskGuest(TaskType aTaskType, Guest *aThat, Progress *aProgress)
    60         : taskType(aTaskType),
    61           pGuest(aThat),
    62           progress(aProgress),
    63           rc(S_OK)
    64     {}
    65     virtual ~TaskGuest() {}
    66 
    67     int startThread();
    68     static int taskThread(RTTHREAD aThread, void *pvUser);
    69     static int uploadProgress(unsigned uPercent, void *pvUser);
    70 
    71     static HRESULT setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, const char * pszText, ...);
    72     static HRESULT setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, ComObjPtr<Guest> pGuest);
    73 
    74     TaskType taskType;
    75     Guest *pGuest;
    76     ComObjPtr<Progress> progress;
    77     HRESULT rc;
    78 
    79     /* Task data. */
    80     Utf8Str strSource;
    81     Utf8Str strDest;
    82     Utf8Str strUserName;
    83     Utf8Str strPassword;
    84     ULONG   uFlags;
    85 };
    86 
    87 int Guest::TaskGuest::startThread()
    88 {
    89     int vrc = RTThreadCreate(NULL, Guest::TaskGuest::taskThread, this,
    90                              0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
    91                              "Guest::Task");
    92 
    93     if (RT_FAILURE(vrc))
    94         return Guest::setErrorStatic(E_FAIL, Utf8StrFmt("Could not create taskThreadGuest (%Rrc)\n", vrc));
    95 
    96     return vrc;
    97 }
    98 
    99 /* static */
    100 DECLCALLBACK(int) Guest::TaskGuest::taskThread(RTTHREAD /* aThread */, void *pvUser)
    101 {
    102     std::auto_ptr<TaskGuest> task(static_cast<TaskGuest*>(pvUser));
    103     AssertReturn(task.get(), VERR_GENERAL_FAILURE);
    104 
    105     Guest *pGuest = task->pGuest;
    106 
    107     LogFlowFuncEnter();
    108     LogFlowFunc(("Guest %p\n", pGuest));
    109 
    110     HRESULT rc = S_OK;
    111 
    112     switch (task->taskType)
    113     {
    114 #ifdef VBOX_WITH_GUEST_CONTROL
    115         case TaskGuest::CopyFileToGuest:
    116         {
    117             rc = pGuest->taskCopyFileToGuest(task.get());
    118             break;
    119         }
    120         case TaskGuest::CopyFileFromGuest:
    121         {
    122             rc = pGuest->taskCopyFileFromGuest(task.get());
    123             break;
    124         }
    125         case TaskGuest::UpdateGuestAdditions:
    126         {
    127             rc = pGuest->taskUpdateGuestAdditions(task.get());
    128             break;
    129         }
    130 #endif
    131         default:
    132             AssertMsgFailed(("Invalid task type %u specified!\n", task->taskType));
    133             break;
    134     }
    135 
    136     LogFlowFunc(("rc=%Rhrc\n", rc));
    137     LogFlowFuncLeave();
    138 
    139     return VINF_SUCCESS;
    140 }
    141 
    142 /* static */
    143 int Guest::TaskGuest::uploadProgress(unsigned uPercent, void *pvUser)
    144 {
    145     Guest::TaskGuest *pTask = *(Guest::TaskGuest**)pvUser;
    146 
    147     if (pTask &&
    148         !pTask->progress.isNull())
    149     {
    150         BOOL fCanceled;
    151         pTask->progress->COMGETTER(Canceled)(&fCanceled);
    152         if (fCanceled)
    153             return -1;
    154         pTask->progress->SetCurrentOperationProgress(uPercent);
    155     }
    156     return VINF_SUCCESS;
    157 }
    158 
    159 /* static */
    160 HRESULT Guest::TaskGuest::setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, const char *pszText, ...)
    161 {
    162     BOOL fCanceled;
    163     BOOL fCompleted;
    164     if (   SUCCEEDED(pProgress->COMGETTER(Canceled(&fCanceled)))
    165         && !fCanceled
    166         && SUCCEEDED(pProgress->COMGETTER(Completed(&fCompleted)))
    167         && !fCompleted)
    168     {
    169         va_list va;
    170         va_start(va, pszText);
    171         HRESULT hr2 = pProgress->notifyCompleteV(hr,
    172                                                  COM_IIDOF(IGuest),
    173                                                  Guest::getStaticComponentName(),
    174                                                  pszText,
    175                                                  va);
    176         va_end(va);
    177         if (hr2 == S_OK) /* If unable to retrieve error, return input error. */
    178             hr2 = hr;
    179         return hr2;
    180     }
    181     return S_OK;
    182 }
    183 
    184 /* static */
    185 HRESULT Guest::TaskGuest::setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, ComObjPtr<Guest> pGuest)
    186 {
    187     return setProgressErrorInfo(hr, pProgress,
    188                                 Utf8Str(com::ErrorInfo((IGuest*)pGuest, COM_IIDOF(IGuest)).getText()).c_str());
    189 }
    190 
    191 #ifdef VBOX_WITH_GUEST_CONTROL
    192 HRESULT Guest::taskCopyFileToGuest(TaskGuest *aTask)
    193 {
    194     LogFlowFuncEnter();
    195 
    196     AutoCaller autoCaller(this);
    197     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    198 
    199     /*
    200      * Do *not* take a write lock here since we don't (and won't)
    201      * touch any class-specific data (of IGuest) here - only the member functions
    202      * which get called here can do that.
    203      */
    204 
    205     HRESULT rc = S_OK;
    206 
    207     try
    208     {
    209         Guest *pGuest = aTask->pGuest;
    210         AssertPtr(pGuest);
    211 
    212         /* Does our source file exist? */
    213         if (!RTFileExists(aTask->strSource.c_str()))
    214         {
    215             rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    216                                                  Guest::tr("Source file \"%s\" does not exist, or is not a file"),
    217                                                  aTask->strSource.c_str());
    218         }
    219         else
    220         {
    221             RTFILE fileSource;
    222             int vrc = RTFileOpen(&fileSource, aTask->strSource.c_str(),
    223                                  RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
    224             if (RT_FAILURE(vrc))
    225             {
    226                 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    227                                                      Guest::tr("Could not open source file \"%s\" for reading (%Rrc)"),
    228                                                      aTask->strSource.c_str(),  vrc);
    229             }
    230             else
    231             {
    232                 uint64_t cbSize;
    233                 vrc = RTFileGetSize(fileSource, &cbSize);
    234                 if (RT_FAILURE(vrc))
    235                 {
    236                     rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    237                                                          Guest::tr("Could not query file size of \"%s\" (%Rrc)"),
    238                                                          aTask->strSource.c_str(), vrc);
    239                 }
    240                 else
    241                 {
    242                     com::SafeArray<IN_BSTR> args;
    243                     com::SafeArray<IN_BSTR> env;
    244 
    245                     /*
    246                      * Prepare tool command line.
    247                      */
    248                     char szOutput[RTPATH_MAX];
    249                     if (RTStrPrintf(szOutput, sizeof(szOutput), "--output=%s", aTask->strDest.c_str()) <= sizeof(szOutput) - 1)
    250                     {
    251                         /*
    252                          * Normalize path slashes, based on the detected guest.
    253                          */
    254                         Utf8Str osType = mData.mOSTypeId;
    255                         if (   osType.contains("Microsoft", Utf8Str::CaseInsensitive)
    256                             || osType.contains("Windows", Utf8Str::CaseInsensitive))
    257                         {
    258                             /* We have a Windows guest. */
    259                             RTPathChangeToDosSlashes(szOutput, true /* Force conversion. */);
    260                         }
    261                         else /* ... or something which isn't from Redmond ... */
    262                         {
    263                             RTPathChangeToUnixSlashes(szOutput, true /* Force conversion. */);
    264                         }
    265 
    266                         args.push_back(Bstr(szOutput).raw());             /* We want to write a file ... */
    267                     }
    268                     else
    269                     {
    270                         rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    271                                                              Guest::tr("Error preparing command line"));
    272                     }
    273 
    274                     ComPtr<IProgress> execProgress;
    275                     ULONG uPID;
    276                     if (SUCCEEDED(rc))
    277                     {
    278                         LogRel(("Copying file \"%s\" to guest \"%s\" (%u bytes) ...\n",
    279                                 aTask->strSource.c_str(), aTask->strDest.c_str(), cbSize));
    280                         /*
    281                          * Okay, since we gathered all stuff we need until now to start the
    282                          * actual copying, start the guest part now.
    283                          */
    284                         rc = pGuest->ExecuteProcess(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
    285                                                       ExecuteProcessFlag_Hidden
    286                                                     | ExecuteProcessFlag_WaitForProcessStartOnly,
    287                                                     ComSafeArrayAsInParam(args),
    288                                                     ComSafeArrayAsInParam(env),
    289                                                     Bstr(aTask->strUserName).raw(),
    290                                                     Bstr(aTask->strPassword).raw(),
    291                                                     5 * 1000 /* Wait 5s for getting the process started. */,
    292                                                     &uPID, execProgress.asOutParam());
    293                         if (FAILED(rc))
    294                             rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
    295                     }
    296 
    297                     if (SUCCEEDED(rc))
    298                     {
    299                         BOOL fCompleted = FALSE;
    300                         BOOL fCanceled = FALSE;
    301 
    302                         size_t cbToRead = cbSize;
    303                         size_t cbTransfered = 0;
    304                         size_t cbRead;
    305                         SafeArray<BYTE> aInputData(_64K);
    306                         while (   SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted)))
    307                                && !fCompleted)
    308                         {
    309                             if (!cbToRead)
    310                                 cbRead = 0;
    311                             else
    312                             {
    313                                 vrc = RTFileRead(fileSource, (uint8_t*)aInputData.raw(),
    314                                                  RT_MIN(cbToRead, _64K), &cbRead);
    315                                 /*
    316                                  * Some other error occured? There might be a chance that RTFileRead
    317                                  * could not resolve/map the native error code to an IPRT code, so just
    318                                  * print a generic error.
    319                                  */
    320                                 if (RT_FAILURE(vrc))
    321                                 {
    322                                     rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    323                                                                          Guest::tr("Could not read from file \"%s\" (%Rrc)"),
    324                                                                          aTask->strSource.c_str(), vrc);
    325                                     break;
    326                                 }
    327                             }
    328 
    329                             /* Resize buffer to reflect amount we just have read.
    330                              * Size 0 is allowed! */
    331                             aInputData.resize(cbRead);
    332 
    333                             ULONG uFlags = ProcessInputFlag_None;
    334                             /* Did we reach the end of the content we want to transfer (last chunk)? */
    335                             if (   (cbRead < _64K)
    336                                 /* Did we reach the last block which is exactly _64K? */
    337                                 || (cbToRead - cbRead == 0)
    338                                 /* ... or does the user want to cancel? */
    339                                 || (   SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled)))
    340                                     && fCanceled)
    341                                )
    342                             {
    343                                 uFlags |= ProcessInputFlag_EndOfFile;
    344                             }
    345 
    346                             /* Transfer the current chunk ... */
    347                             ULONG uBytesWritten;
    348                             rc = pGuest->SetProcessInput(uPID, uFlags,
    349                                                          10 * 1000 /* Wait 10s for getting the input data transfered. */,
    350                                                          ComSafeArrayAsInParam(aInputData), &uBytesWritten);
    351                             if (FAILED(rc))
    352                             {
    353                                 rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
    354                                 break;
    355                             }
    356 
    357                             Assert(cbRead <= cbToRead);
    358                             Assert(cbToRead >= cbRead);
    359                             cbToRead -= cbRead;
    360 
    361                             cbTransfered += uBytesWritten;
    362                             Assert(cbTransfered <= cbSize);
    363                             aTask->progress->SetCurrentOperationProgress(cbTransfered / (cbSize / 100.0));
    364 
    365                             /* End of file reached? */
    366                             if (cbToRead == 0)
    367                                 break;
    368 
    369                             /* Did the user cancel the operation above? */
    370                             if (fCanceled)
    371                                 break;
    372 
    373                             /* Progress canceled by Main API? */
    374                             if (   SUCCEEDED(execProgress->COMGETTER(Canceled(&fCanceled)))
    375                                 && fCanceled)
    376                             {
    377                                 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    378                                                                      Guest::tr("Copy operation of file \"%s\" was canceled on guest side"),
    379                                                                      aTask->strSource.c_str());
    380                                 break;
    381                             }
    382                         }
    383 
    384                         if (SUCCEEDED(rc))
    385                         {
    386                             /*
    387                              * If we got here this means the started process either was completed,
    388                              * canceled or we simply got all stuff transferred.
    389                              */
    390                             ExecuteProcessStatus_T retStatus;
    391                             ULONG uRetExitCode;
    392                             rc = pGuest->waitForProcessStatusChange(uPID, &retStatus, &uRetExitCode, 10 * 1000 /* 10s timeout. */);
    393                             if (FAILED(rc))
    394                             {
    395                                 rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
    396                             }
    397                             else
    398                             {
    399                                 if (   uRetExitCode != 0
    400                                     || retStatus    != ExecuteProcessStatus_TerminatedNormally)
    401                                 {
    402                                     rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    403                                                                          Guest::tr("Guest reported error %u while copying file \"%s\" to \"%s\""),
    404                                                                          uRetExitCode, aTask->strSource.c_str(), aTask->strDest.c_str());
    405                                 }
    406                             }
    407                         }
    408 
    409                         if (SUCCEEDED(rc))
    410                         {
    411                             if (fCanceled)
    412                             {
    413                                 /*
    414                                  * In order to make the progress object to behave nicely, we also have to
    415                                  * notify the object with a complete event when it's canceled.
    416                                  */
    417                                 aTask->progress->notifyComplete(VBOX_E_IPRT_ERROR,
    418                                                                 COM_IIDOF(IGuest),
    419                                                                 Guest::getStaticComponentName(),
    420                                                                 Guest::tr("Copying file \"%s\" canceled"), aTask->strSource.c_str());
    421                             }
    422                             else
    423                             {
    424                                 /*
    425                                  * Even if we succeeded until here make sure to check whether we really transfered
    426                                  * everything.
    427                                  */
    428                                 if (   cbSize > 0
    429                                     && cbTransfered == 0)
    430                                 {
    431                                     /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
    432                                      * to the destination -> access denied. */
    433                                     rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    434                                                                          Guest::tr("Access denied when copying file \"%s\" to \"%s\""),
    435                                                                          aTask->strSource.c_str(), aTask->strDest.c_str());
    436                                 }
    437                                 else if (cbTransfered < cbSize)
    438                                 {
    439                                     /* If we did not copy all let the user know. */
    440                                     rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    441                                                                          Guest::tr("Copying file \"%s\" failed (%u/%u bytes transfered)"),
    442                                                                          aTask->strSource.c_str(), cbTransfered, cbSize);
    443                                 }
    444                                 else /* Yay, all went fine! */
    445                                     aTask->progress->notifyComplete(S_OK);
    446                             }
    447                         }
    448                     }
    449                 }
    450                 RTFileClose(fileSource);
    451             }
    452         }
    453     }
    454     catch (HRESULT aRC)
    455     {
    456         rc = aRC;
    457     }
    458 
    459     /* Clean up */
    460     aTask->rc = rc;
    461 
    462     LogFlowFunc(("rc=%Rhrc\n", rc));
    463     LogFlowFuncLeave();
    464 
    465     return VINF_SUCCESS;
    466 }
    467 
    468 HRESULT Guest::taskCopyFileFromGuest(TaskGuest *aTask)
    469 {
    470     LogFlowFuncEnter();
    471 
    472     AutoCaller autoCaller(this);
    473     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    474 
    475     /*
    476      * Do *not* take a write lock here since we don't (and won't)
    477      * touch any class-specific data (of IGuest) here - only the member functions
    478      * which get called here can do that.
    479      */
    480 
    481     HRESULT rc = S_OK;
    482 
    483     try
    484     {
    485         Guest *pGuest = aTask->pGuest;
    486         AssertPtr(pGuest);
    487 
    488         /* Does our source file exist? */
    489         BOOL fFileExists;
    490         rc = pGuest->FileExists(Bstr(aTask->strSource).raw(),
    491                                 Bstr(aTask->strUserName).raw(), Bstr(aTask->strPassword).raw(),
    492                                 &fFileExists);
    493         if (SUCCEEDED(rc))
    494         {
    495             if (!fFileExists)
    496                 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    497                                                      Guest::tr("Source file \"%s\" does not exist, or is not a file"),
    498                                                      aTask->strSource.c_str());
    499         }
    500 
    501         /* Query file size to make an estimate for our progress object. */
    502         if (SUCCEEDED(rc))
    503         {
    504             LONG64 lFileSize;
    505             rc = pGuest->FileQuerySize(Bstr(aTask->strSource).raw(),
    506                                        Bstr(aTask->strUserName).raw(), Bstr(aTask->strPassword).raw(),
    507                                        &lFileSize);
    508             if (FAILED(rc))
    509                 rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
    510 
    511             com::SafeArray<IN_BSTR> args;
    512             com::SafeArray<IN_BSTR> env;
    513 
    514             if (SUCCEEDED(rc))
    515             {
    516                 /*
    517                  * Prepare tool command line.
    518                  */
    519                 char szSource[RTPATH_MAX];
    520                 if (RTStrPrintf(szSource, sizeof(szSource), "%s", aTask->strSource.c_str()) <= sizeof(szSource) - 1)
    521                 {
    522                     /*
    523                      * Normalize path slashes, based on the detected guest.
    524                      */
    525                     Utf8Str osType = mData.mOSTypeId;
    526                     if (   osType.contains("Microsoft", Utf8Str::CaseInsensitive)
    527                         || osType.contains("Windows", Utf8Str::CaseInsensitive))
    528                     {
    529                         /* We have a Windows guest. */
    530                         RTPathChangeToDosSlashes(szSource, true /* Force conversion. */);
    531                     }
    532                     else /* ... or something which isn't from Redmond ... */
    533                     {
    534                         RTPathChangeToUnixSlashes(szSource, true /* Force conversion. */);
    535                     }
    536 
    537                     args.push_back(Bstr(szSource).raw()); /* Tell our cat tool which file to output. */
    538                 }
    539                 else
    540                     rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    541                                                          Guest::tr("Error preparing command line"));
    542             }
    543 
    544             ComPtr<IProgress> execProgress;
    545             ULONG uPID;
    546             if (SUCCEEDED(rc))
    547             {
    548                 LogRel(("Copying file \"%s\" to host \"%s\" (%u bytes) ...\n",
    549                         aTask->strSource.c_str(), aTask->strDest.c_str(), lFileSize));
    550 
    551                 /*
    552                  * Okay, since we gathered all stuff we need until now to start the
    553                  * actual copying, start the guest part now.
    554                  */
    555                 rc = pGuest->ExecuteProcess(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
    556                                             ExecuteProcessFlag_Hidden,
    557                                             ComSafeArrayAsInParam(args),
    558                                             ComSafeArrayAsInParam(env),
    559                                             Bstr(aTask->strUserName).raw(),
    560                                             Bstr(aTask->strPassword).raw(),
    561                                             5 * 1000 /* Wait 5s for getting the process started. */,
    562                                             &uPID, execProgress.asOutParam());
    563                 if (FAILED(rc))
    564                     rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
    565             }
    566 
    567             if (SUCCEEDED(rc))
    568             {
    569                 BOOL fCompleted = FALSE;
    570                 BOOL fCanceled = FALSE;
    571 
    572                 RTFILE hFileDest;
    573                 int vrc = RTFileOpen(&hFileDest, aTask->strDest.c_str(),
    574                                      RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
    575                 if (RT_FAILURE(vrc))
    576                     rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    577                                                          Guest::tr("Unable to create/open destination file \"%s\", rc=%Rrc"),
    578                                                          aTask->strDest.c_str(), vrc);
    579                 else
    580                 {
    581                     size_t cbToRead = lFileSize;
    582                     size_t cbTransfered = 0;
    583                     SafeArray<BYTE> aOutputData(_64K);
    584                     while (SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted))))
    585                     {
    586                         rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None,
    587                                                     10 * 1000 /* Timeout in ms */,
    588                                                     _64K, ComSafeArrayAsOutParam(aOutputData));
    589                         if (SUCCEEDED(rc))
    590                         {
    591                             if (!aOutputData.size())
    592                             {
    593                                 if (cbToRead)
    594                                     rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    595                                                                          Guest::tr("Unexpected end of file \"%s\" (%u bytes left)"),
    596                                                                          aTask->strSource.c_str(), cbToRead);
    597                                 break;
    598                             }
    599 
    600                             vrc = RTFileWrite(hFileDest, aOutputData.raw(), aOutputData.size(), NULL /* No partial writes */);
    601                             if (RT_FAILURE(vrc))
    602                             {
    603                                 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    604                                                                      Guest::tr("Error writing to file \"%s\" (%u bytes left), rc=%Rrc"),
    605                                                                      aTask->strSource.c_str(), cbToRead, vrc);
    606                                 break;
    607                             }
    608 
    609                             cbToRead -= aOutputData.size();
    610                             cbTransfered += aOutputData.size();
    611 
    612                             aTask->progress->SetCurrentOperationProgress(cbTransfered / (lFileSize / 100.0));
    613                         }
    614                         else
    615                         {
    616                             rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
    617                             break;
    618                         }
    619                     }
    620 
    621                     if (SUCCEEDED(rc))
    622                         aTask->progress->notifyComplete(S_OK);
    623 
    624                     RTFileClose(hFileDest);
    625                 }
    626             }
    627         }
    628     }
    629     catch (HRESULT aRC)
    630     {
    631         rc = aRC;
    632     }
    633 
    634     /* Clean up */
    635     aTask->rc = rc;
    636 
    637     LogFlowFunc(("rc=%Rhrc\n", rc));
    638     LogFlowFuncLeave();
    639 
    640     return VINF_SUCCESS;
    641 }
    642 
    643 HRESULT Guest::taskUpdateGuestAdditions(TaskGuest *aTask)
    644 {
    645     LogFlowFuncEnter();
    646 
    647     AutoCaller autoCaller(this);
    648     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    649 
    650     /*
    651      * Do *not* take a write lock here since we don't (and won't)
    652      * touch any class-specific data (of IGuest) here - only the member functions
    653      * which get called here can do that.
    654      */
    655 
    656     HRESULT rc = S_OK;
    657     BOOL fCompleted;
    658     BOOL fCanceled;
    659 
    660     try
    661     {
    662         Guest *pGuest = aTask->pGuest;
    663         AssertPtr(pGuest);
    664 
    665         aTask->progress->SetCurrentOperationProgress(10);
    666 
    667         /*
    668          * Determine guest OS type and the required installer image.
    669          * At the moment only Windows guests are supported.
    670          */
    671         Utf8Str installerImage;
    672         Bstr osTypeId;
    673         if (   SUCCEEDED(pGuest->COMGETTER(OSTypeId(osTypeId.asOutParam())))
    674             && !osTypeId.isEmpty())
    675         {
    676             Utf8Str osTypeIdUtf8(osTypeId); /* Needed for .contains(). */
    677             if (   osTypeIdUtf8.contains("Microsoft", Utf8Str::CaseInsensitive)
    678                 || osTypeIdUtf8.contains("Windows", Utf8Str::CaseInsensitive))
    679             {
    680                 if (osTypeIdUtf8.contains("64", Utf8Str::CaseInsensitive))
    681                     installerImage = "VBOXWINDOWSADDITIONS_AMD64.EXE";
    682                 else
    683                     installerImage = "VBOXWINDOWSADDITIONS_X86.EXE";
    684                 /* Since the installers are located in the root directory,
    685                  * no further path processing needs to be done (yet). */
    686             }
    687             else /* Everything else is not supported (yet). */
    688                 throw TaskGuest::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->progress,
    689                                                       Guest::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"),
    690                                                       osTypeIdUtf8.c_str());
    691         }
    692         else
    693             throw TaskGuest::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->progress,
    694                                                   Guest::tr("Could not detected guest OS type/version, please update manually"));
    695         Assert(!installerImage.isEmpty());
    696 
    697         /*
    698          * Try to open the .ISO file and locate the specified installer.
    699          */
    700         RTISOFSFILE iso;
    701         int vrc = RTIsoFsOpen(&iso, aTask->strSource.c_str());
    702         if (RT_FAILURE(vrc))
    703         {
    704             rc = TaskGuest::setProgressErrorInfo(VBOX_E_FILE_ERROR, aTask->progress,
    705                                                  Guest::tr("Invalid installation medium detected: \"%s\""),
    706                                                  aTask->strSource.c_str());
    707         }
    708         else
    709         {
    710             uint32_t cbOffset;
    711             size_t cbLength;
    712             vrc = RTIsoFsGetFileInfo(&iso, installerImage.c_str(), &cbOffset, &cbLength);
    713             if (   RT_SUCCESS(vrc)
    714                 && cbOffset
    715                 && cbLength)
    716             {
    717                 vrc = RTFileSeek(iso.file, cbOffset, RTFILE_SEEK_BEGIN, NULL);
    718                 if (RT_FAILURE(vrc))
    719                     rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    720                                                          Guest::tr("Could not seek to setup file on installation medium \"%s\" (%Rrc)"),
    721                                                          aTask->strSource.c_str(), vrc);
    722             }
    723             else
    724             {
    725                 switch (vrc)
    726                 {
    727                     case VERR_FILE_NOT_FOUND:
    728                         rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    729                                                              Guest::tr("Setup file was not found on installation medium \"%s\""),
    730                                                              aTask->strSource.c_str());
    731                         break;
    732 
    733                     default:
    734                         rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    735                                                              Guest::tr("An unknown error (%Rrc) occured while retrieving information of setup file on installation medium \"%s\""),
    736                                                              vrc, aTask->strSource.c_str());
    737                         break;
    738                 }
    739             }
    740 
    741             /* Specify the ouput path on the guest side. */
    742             Utf8Str strInstallerPath = "%TEMP%\\VBoxWindowsAdditions.exe";
    743 
    744             if (RT_SUCCESS(vrc))
    745             {
    746                 /* Okay, we're ready to start our copy routine on the guest! */
    747                 aTask->progress->SetCurrentOperationProgress(15);
    748 
    749                 /* Prepare command line args. */
    750                 com::SafeArray<IN_BSTR> args;
    751                 com::SafeArray<IN_BSTR> env;
    752 
    753                 args.push_back(Bstr("--output").raw());               /* We want to write a file ... */
    754                 args.push_back(Bstr(strInstallerPath.c_str()).raw()); /* ... with this path. */
    755 
    756                 if (SUCCEEDED(rc))
    757                 {
    758                     ComPtr<IProgress> progressCat;
    759                     ULONG uPID;
    760 
    761                     /*
    762                      * Start built-in "vbox_cat" tool (inside VBoxService) to
    763                      * copy over/pipe the data into a file on the guest (with
    764                      * system rights, no username/password specified).
    765                      */
    766                     rc = pGuest->executeProcessInternal(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
    767                                                           ExecuteProcessFlag_Hidden
    768                                                         | ExecuteProcessFlag_WaitForProcessStartOnly,
    769                                                         ComSafeArrayAsInParam(args),
    770                                                         ComSafeArrayAsInParam(env),
    771                                                         Bstr("").raw() /* Username. */,
    772                                                         Bstr("").raw() /* Password */,
    773                                                         5 * 1000 /* Wait 5s for getting the process started. */,
    774                                                         &uPID, progressCat.asOutParam(), &vrc);
    775                     if (FAILED(rc))
    776                     {
    777                         /* Errors which return VBOX_E_NOT_SUPPORTED can be safely skipped by the caller
    778                          * to silently fall back to "normal" (old) .ISO mounting. */
    779 
    780                         /* Due to a very limited COM error range we use vrc for a more detailed error
    781                          * lookup to figure out what went wrong. */
    782                         switch (vrc)
    783                         {
    784                             /* Guest execution service is not (yet) ready. This basically means that either VBoxService
    785                              * is not running (yet) or that the Guest Additions are too old (because VBoxService does not
    786                              * support the guest execution feature in this version). */
    787                             case VERR_NOT_FOUND:
    788                                 LogRel(("Guest Additions seem not to be installed yet\n"));
    789                                 rc = TaskGuest::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->progress,
    790                                                                      Guest::tr("Guest Additions seem not to be installed or are not ready to update yet"));
    791                                 break;
    792 
    793                             /* Getting back a VERR_INVALID_PARAMETER indicates that the installed Guest Additions are supporting the guest
    794                              * execution but not the built-in "vbox_cat" tool of VBoxService (< 4.0). */
    795                             case VERR_INVALID_PARAMETER:
    796                                 LogRel(("Guest Additions are installed but don't supported automatic updating\n"));
    797                                 rc = TaskGuest::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->progress,
    798                                                                      Guest::tr("Installed Guest Additions do not support automatic updating"));
    799                                 break;
    800 
    801                             case VERR_TIMEOUT:
    802                                 LogRel(("Guest was unable to start copying the Guest Additions setup within time\n"));
    803                                 rc = TaskGuest::setProgressErrorInfo(E_FAIL, aTask->progress,
    804                                                                      Guest::tr("Guest was unable to start copying the Guest Additions setup within time"));
    805                                 break;
    806 
    807                             default:
    808                                 rc = TaskGuest::setProgressErrorInfo(E_FAIL, aTask->progress,
    809                                                                      Guest::tr("Error copying Guest Additions setup file to guest path \"%s\" (%Rrc)"),
    810                                                                      strInstallerPath.c_str(), vrc);
    811                                 break;
    812                         }
    813                     }
    814                     else
    815                     {
    816                         LogRel(("Automatic update of Guest Additions started, using \"%s\"\n", aTask->strSource.c_str()));
    817                         LogRel(("Copying Guest Additions installer \"%s\" to \"%s\" on guest ...\n",
    818                                 installerImage.c_str(), strInstallerPath.c_str()));
    819                         aTask->progress->SetCurrentOperationProgress(20);
    820 
    821                         /* Wait for process to exit ... */
    822                         SafeArray<BYTE> aInputData(_64K);
    823                         while (   SUCCEEDED(progressCat->COMGETTER(Completed(&fCompleted)))
    824                                && !fCompleted)
    825                         {
    826                             size_t cbRead;
    827                             /* cbLength contains remaining bytes of our installer file
    828                              * opened above to read. */
    829                             size_t cbToRead = RT_MIN(cbLength, _64K);
    830                             if (cbToRead)
    831                             {
    832                                 vrc = RTFileRead(iso.file, (uint8_t*)aInputData.raw(), cbToRead, &cbRead);
    833                                 if (   cbRead
    834                                     && RT_SUCCESS(vrc))
    835                                 {
    836                                     /* Resize buffer to reflect amount we just have read. */
    837                                     if (cbRead > 0)
    838                                         aInputData.resize(cbRead);
    839 
    840                                     /* Did we reach the end of the content we want to transfer (last chunk)? */
    841                                     ULONG uFlags = ProcessInputFlag_None;
    842                                     if (   (cbRead < _64K)
    843                                         /* Did we reach the last block which is exactly _64K? */
    844                                         || (cbToRead - cbRead == 0)
    845                                         /* ... or does the user want to cancel? */
    846                                         || (   SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled)))
    847                                             && fCanceled)
    848                                        )
    849                                     {
    850                                         uFlags |= ProcessInputFlag_EndOfFile;
    851                                     }
    852 
    853                                     /* Transfer the current chunk ... */
    854                                 #ifdef DEBUG_andy
    855                                     LogRel(("Copying Guest Additions (%u bytes left) ...\n", cbLength));
    856                                 #endif
    857                                     ULONG uBytesWritten;
    858                                     rc = pGuest->SetProcessInput(uPID, uFlags,
    859                                                                  10 * 1000 /* Wait 10s for getting the input data transfered. */,
    860                                                                  ComSafeArrayAsInParam(aInputData), &uBytesWritten);
    861                                     if (FAILED(rc))
    862                                     {
    863                                         rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
    864                                         break;
    865                                     }
    866 
    867                                     /* If task was canceled above also cancel the process execution. */
    868                                     if (fCanceled)
    869                                         progressCat->Cancel();
    870 
    871                                 #ifdef DEBUG_andy
    872                                     LogRel(("Copying Guest Additions (%u bytes written) ...\n", uBytesWritten));
    873                                 #endif
    874                                     Assert(cbLength >= uBytesWritten);
    875                                     cbLength -= uBytesWritten;
    876                                 }
    877                                 else if (RT_FAILURE(vrc))
    878                                 {
    879                                     rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    880                                                                          Guest::tr("Error while reading setup file \"%s\" (To read: %u, Size: %u) from installation medium (%Rrc)"),
    881                                                                          installerImage.c_str(), cbToRead, cbLength, vrc);
    882                                 }
    883                             }
    884 
    885                             /* Internal progress canceled? */
    886                             if (   SUCCEEDED(progressCat->COMGETTER(Canceled(&fCanceled)))
    887                                 && fCanceled)
    888                             {
    889                                 aTask->progress->Cancel();
    890                                 break;
    891                             }
    892                         }
    893                     }
    894                 }
    895             }
    896             RTIsoFsClose(&iso);
    897 
    898             if (   SUCCEEDED(rc)
    899                 && (   SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled)))
    900                     && !fCanceled
    901                    )
    902                )
    903             {
    904                 /*
    905                  * Installer was transferred successfully, so let's start it
    906                  * (with system rights).
    907                  */
    908                 LogRel(("Preparing to execute Guest Additions update ...\n"));
    909                 aTask->progress->SetCurrentOperationProgress(66);
    910 
    911                 /* Prepare command line args for installer. */
    912                 com::SafeArray<IN_BSTR> installerArgs;
    913                 com::SafeArray<IN_BSTR> installerEnv;
    914 
    915                 /** @todo Only Windows! */
    916                 installerArgs.push_back(Bstr(strInstallerPath).raw()); /* The actual (internal) installer image (as argv[0]). */
    917                 /* Note that starting at Windows Vista the lovely session 0 separation applies:
    918                  * This means that if we run an application with the profile/security context
    919                  * of VBoxService (system rights!) we're not able to show any UI. */
    920                 installerArgs.push_back(Bstr("/S").raw());      /* We want to install in silent mode. */
    921                 installerArgs.push_back(Bstr("/l").raw());      /* ... and logging enabled. */
    922                 /* Don't quit VBoxService during upgrade because it still is used for this
    923                  * piece of code we're in right now (that is, here!) ... */
    924                 installerArgs.push_back(Bstr("/no_vboxservice_exit").raw());
    925                 /* Tell the installer to report its current installation status
    926                  * using a running VBoxTray instance via balloon messages in the
    927                  * Windows taskbar. */
    928                 installerArgs.push_back(Bstr("/post_installstatus").raw());
    929 
    930                 /*
    931                  * Start the just copied over installer with system rights
    932                  * in silent mode on the guest. Don't use the hidden flag since there
    933                  * may be pop ups the user has to process.
    934                  */
    935                 ComPtr<IProgress> progressInstaller;
    936                 ULONG uPID;
    937                 rc = pGuest->executeProcessInternal(Bstr(strInstallerPath).raw(),
    938                                                     ExecuteProcessFlag_WaitForProcessStartOnly,
    939                                                     ComSafeArrayAsInParam(installerArgs),
    940                                                     ComSafeArrayAsInParam(installerEnv),
    941                                                     Bstr("").raw() /* Username */,
    942                                                     Bstr("").raw() /* Password */,
    943                                                     10 * 1000 /* Wait 10s for getting the process started */,
    944                                                     &uPID, progressInstaller.asOutParam(), &vrc);
    945                 if (SUCCEEDED(rc))
    946                 {
    947                     LogRel(("Guest Additions update is running ...\n"));
    948 
    949                     /* If the caller does not want to wait for out guest update process to end,
    950                      * complete the progress object now so that the caller can do other work. */
    951                     if (aTask->uFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly)
    952                         aTask->progress->notifyComplete(S_OK);
    953                     else
    954                         aTask->progress->SetCurrentOperationProgress(70);
    955 
    956                     /* Wait until the Guest Additions installer finishes ... */
    957                     while (   SUCCEEDED(progressInstaller->COMGETTER(Completed(&fCompleted)))
    958                            && !fCompleted)
    959                     {
    960                         if (   SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled)))
    961                             && fCanceled)
    962                         {
    963                             progressInstaller->Cancel();
    964                             break;
    965                         }
    966                         /* Progress canceled by Main API? */
    967                         if (   SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled)))
    968                             && fCanceled)
    969                         {
    970                             break;
    971                         }
    972                         RTThreadSleep(100);
    973                     }
    974 
    975                     ExecuteProcessStatus_T retStatus;
    976                     ULONG uRetExitCode, uRetFlags;
    977                     rc = pGuest->GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
    978                     if (SUCCEEDED(rc))
    979                     {
    980                         if (fCompleted)
    981                         {
    982                             if (uRetExitCode == 0)
    983                             {
    984                                 LogRel(("Guest Additions update successful!\n"));
    985                                 if (   SUCCEEDED(aTask->progress->COMGETTER(Completed(&fCompleted)))
    986                                     && !fCompleted)
    987                                     aTask->progress->notifyComplete(S_OK);
    988                             }
    989                             else
    990                             {
    991                                 LogRel(("Guest Additions update failed (Exit code=%u, Status=%u, Flags=%u)\n",
    992                                         uRetExitCode, retStatus, uRetFlags));
    993                                 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    994                                                                      Guest::tr("Guest Additions update failed with exit code=%u (status=%u, flags=%u)"),
    995                                                                      uRetExitCode, retStatus, uRetFlags);
    996                             }
    997                         }
    998                         else if (   SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled)))
    999                                  && fCanceled)
    1000                         {
    1001                             LogRel(("Guest Additions update was canceled\n"));
    1002                             rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress,
    1003                                                                  Guest::tr("Guest Additions update was canceled by the guest with exit code=%u (status=%u, flags=%u)"),
    1004                                                                  uRetExitCode, retStatus, uRetFlags);
    1005                         }
    1006                         else
    1007                         {
    1008                             LogRel(("Guest Additions update was canceled by the user\n"));
    1009                         }
    1010                     }
    1011                     else
    1012                         rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
    1013                 }
    1014                 else
    1015                     rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);
    1016             }
    1017         }
    1018     }
    1019     catch (HRESULT aRC)
    1020     {
    1021         rc = aRC;
    1022     }
    1023 
    1024     /* Clean up */
    1025     aTask->rc = rc;
    1026 
    1027     LogFlowFunc(("rc=%Rhrc\n", rc));
    1028     LogFlowFuncLeave();
    1029 
    1030     return VINF_SUCCESS;
    1031 }
    1032 #endif
    103343
    103444// public methods only for internal purposes
     
    21111121}
    21121122
     1123#ifdef VBOX_WITH_GUEST_CONTROL
    21131124HRESULT Guest::executeProcessInternal(IN_BSTR aCommand, ULONG aFlags,
    21141125                                      ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
     
    21181129/** @todo r=bird: Eventually we should clean up all the timeout parameters
    21191130 *        in the API and have the same way of specifying infinite waits!  */
    2120 #ifndef VBOX_WITH_GUEST_CONTROL
    2121     ReturnComNotImplemented();
    2122 #else  /* VBOX_WITH_GUEST_CONTROL */
    21231131    using namespace guestControl;
    21241132
     
    23541362    }
    23551363    return rc;
     1364}
    23561365#endif /* VBOX_WITH_GUEST_CONTROL */
    2357 }
    23581366
    23591367STDMETHODIMP Guest::SetProcessInput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ComSafeArrayIn(BYTE, aData), ULONG *aBytesWritten)
     
    28121820
    28131821        /* Initialize our worker task. */
    2814         TaskGuest *pTask = new TaskGuest(TaskGuest::CopyFileFromGuest, this, progress);
     1822        GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileFromGuest, this, progress);
    28151823        AssertPtr(pTask);
    2816         std::auto_ptr<TaskGuest> task(pTask);
     1824        std::auto_ptr<GuestTask> task(pTask);
    28171825
    28181826        /* Assign data - aSource is the source file on the host,
     
    28871895
    28881896        /* Initialize our worker task. */
    2889         TaskGuest *pTask = new TaskGuest(TaskGuest::CopyFileToGuest, this, progress);
     1897        GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileToGuest, this, progress);
    28901898        AssertPtr(pTask);
    2891         std::auto_ptr<TaskGuest> task(pTask);
     1899        std::auto_ptr<GuestTask> task(pTask);
    28921900
    28931901        /* Assign data - aSource is the source file on the host,
     
    29191927}
    29201928
    2921 STDMETHODIMP Guest::DirectoryClose(ULONG aHandle)
    2922 {
    2923 #ifndef VBOX_WITH_GUEST_CONTROL
    2924     ReturnComNotImplemented();
    2925 #else /* VBOX_WITH_GUEST_CONTROL */
    2926     using namespace guestControl;
    2927 
    2928     if (directoryHandleExists(aHandle))
    2929     {
    2930         directoryDestroyHandle(aHandle);
    2931         return S_OK;
    2932     }
    2933 
    2934     return setError(VBOX_E_IPRT_ERROR,
    2935                     Guest::tr("Directory handle is invalid"));
    2936 #endif
    2937 }
    2938 
    2939 STDMETHODIMP Guest::DirectoryCreate(IN_BSTR aDirectory,
    2940                                     IN_BSTR aUserName, IN_BSTR aPassword,
    2941                                     ULONG aMode, ULONG aFlags)
    2942 {
    2943 #ifndef VBOX_WITH_GUEST_CONTROL
    2944     ReturnComNotImplemented();
    2945 #else  /* VBOX_WITH_GUEST_CONTROL */
    2946     using namespace guestControl;
    2947 
    2948     CheckComArgStrNotEmptyOrNull(aDirectory);
    2949 
    2950     /* Do not allow anonymous executions (with system rights). */
    2951     if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
    2952         return setError(E_INVALIDARG, tr("No user name specified"));
    2953 
    2954     LogRel(("Creating guest directory \"%s\" as  user \"%s\" ...\n",
    2955             Utf8Str(aDirectory).c_str(), Utf8Str(aUserName).c_str()));
    2956 
    2957     return directoryCreateInternal(aDirectory,
    2958                                    aUserName, aPassword,
    2959                                    aMode, aFlags, NULL /* rc */);
    2960 #endif
    2961 }
    2962 
    2963 HRESULT Guest::directoryCreateInternal(IN_BSTR aDirectory,
    2964                                        IN_BSTR aUserName, IN_BSTR aPassword,
    2965                                        ULONG aMode, ULONG aFlags, int *pRC)
    2966 {
    2967 #ifndef VBOX_WITH_GUEST_CONTROL
    2968     ReturnComNotImplemented();
    2969 #else /* VBOX_WITH_GUEST_CONTROL */
    2970     using namespace guestControl;
    2971 
    2972     CheckComArgStrNotEmptyOrNull(aDirectory);
    2973 
    2974     AutoCaller autoCaller(this);
    2975     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2976 
    2977     /* Validate flags. */
    2978     if (aFlags != DirectoryCreateFlag_None)
    2979     {
    2980         if (!(aFlags & DirectoryCreateFlag_Parents))
    2981         {
    2982             return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
    2983         }
    2984     }
    2985 
    2986     HRESULT rc = S_OK;
    2987     try
    2988     {
    2989         Utf8Str Utf8Directory(aDirectory);
    2990         Utf8Str Utf8UserName(aUserName);
    2991         Utf8Str Utf8Password(aPassword);
    2992 
    2993         com::SafeArray<IN_BSTR> args;
    2994         com::SafeArray<IN_BSTR> env;
    2995 
    2996         /*
    2997          * Prepare tool command line.
    2998          */
    2999         if (aFlags & DirectoryCreateFlag_Parents)
    3000             args.push_back(Bstr("--parents").raw());        /* We also want to create the parent directories. */
    3001         if (aMode > 0)
    3002         {
    3003             args.push_back(Bstr("--mode").raw());           /* Set the creation mode. */
    3004 
    3005             char szMode[16];
    3006             RTStrPrintf(szMode, sizeof(szMode), "%o", aMode);
    3007             args.push_back(Bstr(szMode).raw());
    3008         }
    3009         args.push_back(Bstr(Utf8Directory).raw());  /* The directory we want to create. */
    3010 
    3011         /*
    3012          * Execute guest process.
    3013          */
    3014         ComPtr<IProgress> progressExec;
    3015         ULONG uPID;
    3016         if (SUCCEEDED(rc))
    3017         {
    3018             rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_MKDIR).raw(),
    3019                                 ExecuteProcessFlag_Hidden,
    3020                                 ComSafeArrayAsInParam(args),
    3021                                 ComSafeArrayAsInParam(env),
    3022                                 Bstr(Utf8UserName).raw(),
    3023                                 Bstr(Utf8Password).raw(),
    3024                                 5 * 1000 /* Wait 5s for getting the process started. */,
    3025                                 &uPID, progressExec.asOutParam());
    3026         }
    3027 
    3028         if (SUCCEEDED(rc))
    3029         {
    3030             /* Wait for process to exit ... */
    3031             rc = progressExec->WaitForCompletion(-1);
    3032             if (FAILED(rc)) return rc;
    3033 
    3034             BOOL fCompleted = FALSE;
    3035             BOOL fCanceled = FALSE;
    3036             progressExec->COMGETTER(Completed)(&fCompleted);
    3037             if (!fCompleted)
    3038                 progressExec->COMGETTER(Canceled)(&fCanceled);
    3039 
    3040             if (fCompleted)
    3041             {
    3042                 ExecuteProcessStatus_T retStatus;
    3043                 ULONG uRetExitCode, uRetFlags;
    3044                 if (SUCCEEDED(rc))
    3045                 {
    3046                     rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
    3047                     if (SUCCEEDED(rc) && uRetExitCode != 0)
    3048                     {
    3049                         rc = setError(VBOX_E_IPRT_ERROR,
    3050                                       tr("Error %u while creating guest directory"), uRetExitCode);
    3051                     }
    3052                 }
    3053             }
    3054             else if (fCanceled)
    3055                 rc = setError(VBOX_E_IPRT_ERROR,
    3056                               tr("Guest directory creation was aborted"));
    3057             else
    3058                 AssertReleaseMsgFailed(("Guest directory creation neither completed nor canceled!?\n"));
    3059         }
    3060     }
    3061     catch (std::bad_alloc &)
    3062     {
    3063         rc = E_OUTOFMEMORY;
    3064     }
    3065     return rc;
    3066 #endif /* VBOX_WITH_GUEST_CONTROL */
    3067 }
    3068 
    3069 /**
    3070  * Creates a new directory handle ID and returns it.
    3071  *
    3072  * @return IPRT status code.
    3073  * @param puHandle             Pointer where the handle gets stored to.
    3074  * @param pszDirectory         Directory the handle is assigned to.
    3075  * @param pszFilter            Directory filter.  Optional.
    3076  * @param uFlags               Directory open flags.
    3077  *
    3078  */
    3079 int Guest::directoryCreateHandle(ULONG *puHandle, const char *pszDirectory, const char *pszFilter, ULONG uFlags)
    3080 {
    3081     AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
    3082     AssertPtrReturn(pszDirectory, VERR_INVALID_POINTER);
    3083     /* pszFilter is optional. */
    3084 
    3085     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    3086 
    3087     int rc = VERR_TOO_MUCH_DATA;
    3088     for (uint32_t i = 0; i < UINT32_MAX; i++)
    3089     {
    3090         /* Create a new context ID ... */
    3091         uint32_t uHandleTry = ASMAtomicIncU32(&mNextDirectoryID);
    3092         GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandleTry);
    3093         if (mGuestDirectoryMap.end() == it)
    3094         {
    3095             rc = VINF_SUCCESS;
    3096             if (!RTStrAPrintf(&mGuestDirectoryMap[uHandleTry].mpszDirectory, pszDirectory))
    3097                 rc = VERR_NO_MEMORY;
    3098             else
    3099             {
    3100                 /* Filter is optional. */
    3101                 if (pszFilter)
    3102                 {
    3103                     if (!RTStrAPrintf(&mGuestDirectoryMap[uHandleTry].mpszFilter, pszFilter))
    3104                         rc = VERR_NO_MEMORY;
    3105                 }
    3106 
    3107                 if (RT_SUCCESS(rc))
    3108                 {
    3109                     mGuestDirectoryMap[uHandleTry].uFlags = uFlags;
    3110                     *puHandle = uHandleTry;
    3111 
    3112                     break;
    3113                 }
    3114             }
    3115 
    3116             if (RT_FAILURE(rc))
    3117                 break;
    3118 
    3119             Assert(mGuestDirectoryMap.size());
    3120         }
    3121     }
    3122 
    3123     return rc;
    3124 }
    3125 
    3126 void Guest::directoryDestroyHandle(uint32_t uHandle)
    3127 {
    3128     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    3129 
    3130     GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
    3131     if (it != mGuestDirectoryMap.end())
    3132     {
    3133         RTStrFree(it->second.mpszDirectory);
    3134         RTStrFree(it->second.mpszFilter);
    3135 
    3136         /* Remove callback context (not used anymore). */
    3137         mGuestDirectoryMap.erase(it);
    3138     }
    3139 }
    3140 
    3141 uint32_t Guest::directoryGetPID(uint32_t uHandle)
    3142 {
    3143     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3144 
    3145     GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
    3146     if (it != mGuestDirectoryMap.end())
    3147         return it->second.mPID;
    3148 
    3149     return 0;
    3150 }
    3151 
    3152 bool Guest::directoryHandleExists(uint32_t uHandle)
    3153 {
    3154     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    3155 
    3156     GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
    3157     if (it != mGuestDirectoryMap.end())
    3158         return true;
    3159 
    3160     return false;
    3161 }
    3162 
    3163 STDMETHODIMP Guest::DirectoryOpen(IN_BSTR aDirectory, IN_BSTR aFilter,
    3164                                   ULONG aFlags, IN_BSTR aUserName, IN_BSTR aPassword,
    3165                                   ULONG *aHandle)
    3166 {
    3167 #ifndef VBOX_WITH_GUEST_CONTROL
    3168     ReturnComNotImplemented();
    3169 #else /* VBOX_WITH_GUEST_CONTROL */
    3170     using namespace guestControl;
    3171 
    3172     CheckComArgStrNotEmptyOrNull(aDirectory);
    3173     CheckComArgNotNull(aHandle);
    3174 
    3175     /* Do not allow anonymous executions (with system rights). */
    3176     if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
    3177         return setError(E_INVALIDARG, tr("No user name specified"));
    3178 
    3179     return directoryOpenInternal(aDirectory, aFilter,
    3180                                  aFlags,
    3181                                  aUserName, aPassword,
    3182                                  aHandle, NULL /* rc */);
    3183 #endif
    3184 }
    3185 
    3186 HRESULT Guest::directoryOpenInternal(IN_BSTR aDirectory, IN_BSTR aFilter,
    3187                                      ULONG aFlags,
    3188                                      IN_BSTR aUserName, IN_BSTR aPassword,
    3189                                      ULONG *aHandle, int *pRC)
    3190 {
    3191 #ifndef VBOX_WITH_GUEST_CONTROL
    3192     ReturnComNotImplemented();
    3193 #else /* VBOX_WITH_GUEST_CONTROL */
    3194     using namespace guestControl;
    3195 
    3196     CheckComArgStrNotEmptyOrNull(aDirectory);
    3197     CheckComArgNotNull(aHandle);
    3198 
    3199     AutoCaller autoCaller(this);
    3200     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3201 
    3202     /* Validate flags. No flags supported yet. */
    3203     if (aFlags != DirectoryOpenFlag_None)
    3204         return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
    3205 
    3206     HRESULT rc = S_OK;
    3207     try
    3208     {
    3209         Utf8Str Utf8Directory(aDirectory);
    3210         Utf8Str Utf8Filter(aFilter);
    3211         Utf8Str Utf8UserName(aUserName);
    3212         Utf8Str Utf8Password(aPassword);
    3213 
    3214         com::SafeArray<IN_BSTR> args;
    3215         com::SafeArray<IN_BSTR> env;
    3216 
    3217         /*
    3218          * Prepare tool command line.
    3219          */
    3220 
    3221         /* We need to get output which is machine-readable in form
    3222          * of "key=value\0..key=value\0\0". */
    3223         args.push_back(Bstr("--machinereadable").raw());
    3224 
    3225         /* We want the long output format. Handy for getting a lot of
    3226          * details we could (should?) use (later). */
    3227         args.push_back(Bstr("-l").raw());
    3228 
    3229         /* As we want to keep this stuff simple we don't do recursive (-R)
    3230          * or dereferencing (--dereference) lookups here. This has to be done by
    3231          * the user. */
    3232 
    3233         /* Construct and hand in actual directory name + filter we want to open. */
    3234         char *pszDirectoryFinal;
    3235         int cbRet;
    3236         if (Utf8Filter.isEmpty())
    3237             cbRet = RTStrAPrintf(&pszDirectoryFinal, "%s", Utf8Directory.c_str());
    3238         else
    3239             cbRet = RTStrAPrintf(&pszDirectoryFinal, "%s/%s",
    3240                                  Utf8Directory.c_str(), Utf8Filter.c_str());
    3241         if (!cbRet)
    3242             return setError(E_OUTOFMEMORY, tr("Out of memory while allocating final directory"));
    3243 
    3244         args.push_back(Bstr(pszDirectoryFinal).raw());  /* The directory we want to open. */
    3245 
    3246         /*
    3247          * Execute guest process.
    3248          */
    3249         ComPtr<IProgress> progressExec;
    3250         ULONG uPID;
    3251 
    3252         rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_LS).raw(),
    3253                             ExecuteProcessFlag_Hidden,
    3254                             ComSafeArrayAsInParam(args),
    3255                             ComSafeArrayAsInParam(env),
    3256                             Bstr(Utf8UserName).raw(),
    3257                             Bstr(Utf8Password).raw(),
    3258                             30 * 1000 /* Wait 30s for getting the process started. */,
    3259                             &uPID, progressExec.asOutParam());
    3260 
    3261         RTStrFree(pszDirectoryFinal);
    3262 
    3263         if (SUCCEEDED(rc))
    3264         {
    3265             /* Wait for process to exit ... */
    3266             rc = progressExec->WaitForCompletion(-1);
    3267             if (FAILED(rc)) return rc;
    3268 
    3269             BOOL fCompleted = FALSE;
    3270             BOOL fCanceled = FALSE;
    3271             progressExec->COMGETTER(Completed)(&fCompleted);
    3272             if (!fCompleted)
    3273                 progressExec->COMGETTER(Canceled)(&fCanceled);
    3274 
    3275             if (fCompleted)
    3276             {
    3277                 ExecuteProcessStatus_T retStatus;
    3278                 ULONG uRetExitCode, uRetFlags;
    3279                 if (SUCCEEDED(rc))
    3280                 {
    3281                     rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
    3282                     if (SUCCEEDED(rc) && uRetExitCode != 0)
    3283                     {
    3284                         rc = setError(VBOX_E_IPRT_ERROR,
    3285                                       tr("Error %u while opening guest directory"), uRetExitCode);
    3286                     }
    3287                 }
    3288             }
    3289             else if (fCanceled)
    3290                 rc = setError(VBOX_E_IPRT_ERROR,
    3291                               tr("Guest directory opening was aborted"));
    3292             else
    3293                 AssertReleaseMsgFailed(("Guest directory opening neither completed nor canceled!?\n"));
    3294 
    3295             if (SUCCEEDED(rc))
    3296             {
    3297                 /* Assign new directory handle ID. */
    3298                 int vrc = directoryCreateHandle(aHandle,
    3299                                                 Utf8Directory.c_str(),
    3300                                                 Utf8Filter.isEmpty() ? NULL : Utf8Filter.c_str(),
    3301                                                 aFlags);
    3302                 if (RT_FAILURE(vrc))
    3303                 {
    3304                     rc = setError(VBOX_E_IPRT_ERROR,
    3305                                   tr("Unable to create guest directory handle (%Rrc)"), vrc);
    3306                 }
    3307             }
    3308         }
    3309     }
    3310     catch (std::bad_alloc &)
    3311     {
    3312         rc = E_OUTOFMEMORY;
    3313     }
    3314     return rc;
    3315 #endif /* VBOX_WITH_GUEST_CONTROL */
    3316 }
    3317 
    3318 STDMETHODIMP Guest::DirectoryRead(ULONG aHandle, IGuestDirEntry **aDirEntry)
    3319 {
    3320 #ifndef VBOX_WITH_GUEST_CONTROL
    3321     ReturnComNotImplemented();
    3322 #else /* VBOX_WITH_GUEST_CONTROL */
    3323     using namespace guestControl;
    3324 
    3325     uint32_t uPID = directoryGetPID(aHandle);
    3326     if (uPID)
    3327     {
    3328         SafeArray<BYTE> aOutputData;
    3329         ULONG cbOutputData = 0;
    3330 
    3331         HRESULT rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None,
    3332                                             30 * 1000 /* Timeout in ms */,
    3333                                             _64K, ComSafeArrayAsOutParam(aOutputData));
    3334         if (SUCCEEDED(rc))
    3335         {
    3336 
    3337         }
    3338 
    3339         return rc;
    3340     }
    3341 
    3342     return setError(VBOX_E_IPRT_ERROR,
    3343                     Guest::tr("Directory handle is invalid"));
    3344 #endif
    3345 }
    3346 
    3347 STDMETHODIMP Guest::FileExists(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists)
    3348 {
    3349 #ifndef VBOX_WITH_GUEST_CONTROL
    3350     ReturnComNotImplemented();
    3351 #else /* VBOX_WITH_GUEST_CONTROL */
    3352     using namespace guestControl;
    3353 
    3354     CheckComArgStrNotEmptyOrNull(aFile);
    3355 
    3356     /* Do not allow anonymous executions (with system rights). */
    3357     if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
    3358         return setError(E_INVALIDARG, tr("No user name specified"));
    3359 
    3360     return fileExistsInternal(aFile,
    3361                               aUserName, aPassword, aExists,
    3362                               NULL /* rc */);
    3363 #endif
    3364 }
    3365 
    3366 HRESULT Guest::fileExistsInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists, int *pRC)
    3367 {
    3368 #ifndef VBOX_WITH_GUEST_CONTROL
    3369     ReturnComNotImplemented();
    3370 #else /* VBOX_WITH_GUEST_CONTROL */
    3371     using namespace guestControl;
    3372 
    3373     CheckComArgStrNotEmptyOrNull(aFile);
    3374 
    3375     AutoCaller autoCaller(this);
    3376     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3377 
    3378     HRESULT rc = S_OK;
    3379     try
    3380     {
    3381         Utf8Str Utf8File(aFile);
    3382         Utf8Str Utf8UserName(aUserName);
    3383         Utf8Str Utf8Password(aPassword);
    3384 
    3385         com::SafeArray<IN_BSTR> args;
    3386         com::SafeArray<IN_BSTR> env;
    3387 
    3388         /*
    3389          * Prepare tool command line.
    3390          */
    3391 
    3392         /* We need to get output which is machine-readable in form
    3393          * of "key=value\0..key=value\0\0". */
    3394         args.push_back(Bstr("--machinereadable").raw());
    3395 
    3396         /* Only the actual file name to chekc is needed for now. */
    3397         args.push_back(Bstr(Utf8File).raw());
    3398 
    3399         /*
    3400          * Execute guest process.
    3401          */
    3402         ComPtr<IProgress> progressExec;
    3403         ULONG uPID;
    3404 
    3405         rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_STAT).raw(),
    3406                             ExecuteProcessFlag_Hidden,
    3407                             ComSafeArrayAsInParam(args),
    3408                             ComSafeArrayAsInParam(env),
    3409                             Bstr(Utf8UserName).raw(),
    3410                             Bstr(Utf8Password).raw(),
    3411                             30 * 1000 /* Wait 30s for getting the process started. */,
    3412                             &uPID, progressExec.asOutParam());
    3413 
    3414         if (SUCCEEDED(rc))
    3415         {
    3416             /* Wait for process to exit ... */
    3417             rc = progressExec->WaitForCompletion(-1);
    3418             if (FAILED(rc)) return rc;
    3419 
    3420             BOOL fCompleted = FALSE;
    3421             BOOL fCanceled = FALSE;
    3422             progressExec->COMGETTER(Completed)(&fCompleted);
    3423             if (!fCompleted)
    3424                 progressExec->COMGETTER(Canceled)(&fCanceled);
    3425 
    3426             if (fCompleted)
    3427             {
    3428                 ExecuteProcessStatus_T retStatus;
    3429                 ULONG uRetExitCode, uRetFlags;
    3430                 if (SUCCEEDED(rc))
    3431                 {
    3432                     rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
    3433                     if (SUCCEEDED(rc))
    3434                     {
    3435                         *aExists = uRetExitCode == 0 ? TRUE : FALSE;
    3436                     }
    3437                     else
    3438                         rc = setError(VBOX_E_IPRT_ERROR,
    3439                                       tr("Error %u while checking for existence of file \"%s\""),
    3440                                       uRetExitCode, Utf8File.c_str());
    3441                 }
    3442             }
    3443             else if (fCanceled)
    3444                 rc = setError(VBOX_E_IPRT_ERROR,
    3445                               tr("Checking for file existence was aborted"));
    3446             else
    3447                 AssertReleaseMsgFailed(("Checking for file existence neither completed nor canceled!?\n"));
    3448         }
    3449     }
    3450     catch (std::bad_alloc &)
    3451     {
    3452         rc = E_OUTOFMEMORY;
    3453     }
    3454     return rc;
    3455 #endif
    3456 }
    3457 
    3458 STDMETHODIMP Guest::FileQuerySize(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, LONG64 *aSize)
    3459 {
    3460 #ifndef VBOX_WITH_GUEST_CONTROL
    3461     ReturnComNotImplemented();
    3462 #else /* VBOX_WITH_GUEST_CONTROL */
    3463     using namespace guestControl;
    3464 
    3465     CheckComArgStrNotEmptyOrNull(aFile);
    3466 
    3467     /* Do not allow anonymous executions (with system rights). */
    3468     if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
    3469         return setError(E_INVALIDARG, tr("No user name specified"));
    3470 
    3471     return fileQuerySizeInternal(aFile,
    3472                                  aUserName, aPassword, aSize,
    3473                                  NULL /* rc */);
    3474 #endif
    3475 }
    3476 
    3477 HRESULT Guest::fileQuerySizeInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, LONG64 *aSize, int *pRC)
    3478 {
    3479 #ifndef VBOX_WITH_GUEST_CONTROL
    3480     ReturnComNotImplemented();
    3481 #else /* VBOX_WITH_GUEST_CONTROL */
    3482     using namespace guestControl;
    3483 
    3484     CheckComArgStrNotEmptyOrNull(aFile);
    3485 
    3486     AutoCaller autoCaller(this);
    3487     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    3488 
    3489     HRESULT rc = S_OK;
    3490     try
    3491     {
    3492         Utf8Str Utf8File(aFile);
    3493         Utf8Str Utf8UserName(aUserName);
    3494         Utf8Str Utf8Password(aPassword);
    3495 
    3496         com::SafeArray<IN_BSTR> args;
    3497         com::SafeArray<IN_BSTR> env;
    3498 
    3499         /*
    3500          * Prepare tool command line.
    3501          */
    3502 
    3503         /* We need to get output which is machine-readable in form
    3504          * of "key=value\0..key=value\0\0". */
    3505         args.push_back(Bstr("--machinereadable").raw());
    3506 
    3507         /* Only the actual file name to chekc is needed for now. */
    3508         args.push_back(Bstr(Utf8File).raw());
    3509 
    3510         /*
    3511          * Execute guest process.
    3512          */
    3513         ComPtr<IProgress> progressExec;
    3514         ULONG uPID;
    3515 
    3516         rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_STAT).raw(),
    3517                             ExecuteProcessFlag_Hidden,
    3518                             ComSafeArrayAsInParam(args),
    3519                             ComSafeArrayAsInParam(env),
    3520                             Bstr(Utf8UserName).raw(),
    3521                             Bstr(Utf8Password).raw(),
    3522                             30 * 1000 /* Wait 30s for getting the process started. */,
    3523                             &uPID, progressExec.asOutParam());
    3524 
    3525         if (SUCCEEDED(rc))
    3526         {
    3527             /* Wait for process to exit ... */
    3528             rc = progressExec->WaitForCompletion(-1);
    3529             if (FAILED(rc)) return rc;
    3530 
    3531             BOOL fCompleted = FALSE;
    3532             BOOL fCanceled = FALSE;
    3533             progressExec->COMGETTER(Completed)(&fCompleted);
    3534             if (!fCompleted)
    3535                 progressExec->COMGETTER(Canceled)(&fCanceled);
    3536 
    3537             if (fCompleted)
    3538             {
    3539                 ExecuteProcessStatus_T retStatus;
    3540                 ULONG uRetExitCode, uRetFlags;
    3541                 if (SUCCEEDED(rc))
    3542                 {
    3543                     rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
    3544                     if (SUCCEEDED(rc))
    3545                     {
    3546                         if (uRetExitCode == 0)
    3547                         {
    3548                             /* Get file size from output stream. */
    3549                             SafeArray<BYTE> aOutputData;
    3550                             ULONG cbOutputData = 0;
    3551 
    3552                             GuestProcessStream guestStream;
    3553                             int vrc = VINF_SUCCESS;
    3554                             for (;;)
    3555                             {
    3556                                 rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None,
    3557                                                             10 * 1000 /* Timeout in ms */,
    3558                                                             _64K, ComSafeArrayAsOutParam(aOutputData));
    3559                                 /** @todo Do stream header validation! */
    3560                                 if (   SUCCEEDED(rc)
    3561                                     && aOutputData.size())
    3562                                 {
    3563                                     vrc = guestStream.AddData(aOutputData.raw(), aOutputData.size());
    3564                                     if (RT_UNLIKELY(RT_FAILURE(vrc)))
    3565                                         rc = setError(VBOX_E_IPRT_ERROR,
    3566                                                       tr("Query file size: Error while adding guest output to stream buffer for file \"%s\" (%Rrc)"),
    3567                                                       Utf8File.c_str(), vrc);
    3568                                 }
    3569                                 else /* No more output! */
    3570                                     break;
    3571                             }
    3572 
    3573                             if (SUCCEEDED(rc))
    3574                             {
    3575                                 vrc = guestStream.Parse();
    3576                                 if (   RT_SUCCESS(vrc)
    3577                                     || vrc == VERR_MORE_DATA)
    3578                                 {
    3579                                     int64_t iVal;
    3580                                     vrc = guestStream.GetInt64Ex("st_size", &iVal);
    3581                                     if (RT_SUCCESS(vrc))
    3582                                         *aSize = iVal;
    3583                                     else
    3584                                         rc = setError(VBOX_E_IPRT_ERROR,
    3585                                                       tr("Query file size: Unable to retrieve file size for file \"%s\" (%Rrc)"),
    3586                                                       Utf8File.c_str(), vrc);
    3587                                 }
    3588                                 else
    3589                                     rc = setError(VBOX_E_IPRT_ERROR,
    3590                                                   tr("Query file size: Error while parsing guest output for file \"%s\" (%Rrc)"),
    3591                                                   Utf8File.c_str(), vrc);
    3592                             }
    3593                         }
    3594                         else
    3595                             rc = setError(VBOX_E_IPRT_ERROR,
    3596                                           tr("Query file size: Error querying file size for file \"%s\" (exit code %u)"),
    3597                                           Utf8File.c_str(), uRetExitCode);
    3598                     }
    3599                 }
    3600             }
    3601             else if (fCanceled)
    3602                 rc = setError(VBOX_E_IPRT_ERROR,
    3603                               tr("Query file size: Checking for file size was aborted"));
    3604             else
    3605                 AssertReleaseMsgFailed(("Checking for file size neither completed nor canceled!?\n"));
    3606         }
    3607     }
    3608     catch (std::bad_alloc &)
    3609     {
    3610         rc = E_OUTOFMEMORY;
    3611     }
    3612     return rc;
    3613 #endif
    3614 }
    3615 
    36161929STDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ULONG aFlags, IProgress **aProgress)
    36171930{
     
    36481961
    36491962        /* Initialize our worker task. */
    3650         TaskGuest *pTask = new TaskGuest(TaskGuest::UpdateGuestAdditions, this, progress);
     1963        GuestTask *pTask = new GuestTask(GuestTask::TaskType_UpdateGuestAdditions, this, progress);
    36511964        AssertPtr(pTask);
    3652         std::auto_ptr<TaskGuest> task(pTask);
     1965        std::auto_ptr<GuestTask> task(pTask);
    36531966
    36541967        /* Assign data - in that case aSource is the full path
  • trunk/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp

    r38214 r38235  
    144144        if (RT_SUCCESS(iResult))
    145145        {
    146             iResult = stream.Parse();
     146            iResult = stream.ParseBlock();
    147147            if (iResult != aTests[iTest].iResult)
    148148            {
     
    155155                             stream.GetNumPairs(), aTests[iTest].uMapElements);
    156156            }
    157             else if (stream.GetOffsetParser() != aTests[iTest].uOffsetAfter)
     157            else if (stream.GetOffset() != aTests[iTest].uOffsetAfter)
    158158            {
    159159                RTTestFailed(hTest, "\tOffset %u wrong, expected %u",
    160                              stream.GetOffsetParser(), aTests[iTest].uOffsetAfter);
     160                             stream.GetOffset(), aTests[iTest].uOffsetAfter);
    161161            }
    162162            else if (iResult == VERR_MORE_DATA)
     
    192192            do
    193193            {
    194                 iResult = stream.Parse();
     194                iResult = stream.ParseBlock();
    195195                RTTestIPrintf(RTTESTLVL_DEBUG, "\tReturned with %Rrc\n", iResult);
    196196                if (   iResult == VINF_SUCCESS
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette