Changeset 38235 in vbox for trunk/src/VBox/Main
- Timestamp:
- Jul 29, 2011 10:07:03 AM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 73214
- Location:
- trunk/src/VBox/Main
- Files:
-
- 3 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/Makefile.kmk
r38192 r38235 654 654 src-client/ConsoleVRDPServer.cpp \ 655 655 src-client/DisplayImpl.cpp \ 656 src-client/GuestImpl.cpp \ 656 657 src-client/GuestCtrlImpl.cpp \ 657 658 src-client/GuestCtrlIO.cpp \ 658 src-client/GuestImpl.cpp \ 659 src-client/GuestCtrlImplDir.cpp \ 660 src-client/GuestCtrlImplFile.cpp \ 659 661 src-client/KeyboardImpl.cpp \ 660 662 src-client/MachineDebuggerImpl.cpp \ … … 673 675 src-client/win/VBoxC.rc 674 676 677 ifdef VBOX_WITH_GUEST_CONTROL 678 VBoxC_SOURCES += \ 679 src-client/GuestCtrlImplTasks.cpp 680 endif 675 681 676 682 ifdef VBOX_WITH_XPCOM -
trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
r38212 r38235 1 1 /** @file 2 2 * 3 * VirtualBox guest execution control private data definitions3 * VirtualBox Guest Control - Private data definitions / classes. 4 4 */ 5 5 … … 33 33 #endif 34 34 35 class Guest; 36 class Progress; 37 35 38 /** Structure representing the "value" side of a "key=value" pair. */ 36 39 typedef struct VBOXGUESTCTRL_STREAM_PAIR … … 39 42 } VBOXGUESTCTRL_STREAM_PAIR, *PVBOXGUESTCTRL_STREAM_PAIR; 40 43 41 /** Map containing "key=value" pairs of a stream object. */44 /** Map containing "key=value" pairs of a guest process stream. */ 42 45 typedef std::map< Utf8Str, VBOXGUESTCTRL_STREAM_PAIR > GuestCtrlStreamPairs; 43 46 typedef std::map< Utf8Str, VBOXGUESTCTRL_STREAM_PAIR >::iterator GuestCtrlStreamPairsIter; … … 67 70 size_t GetNumPairs(); 68 71 69 uint32_t GetOffsetBuffer(); 70 71 uint32_t GetOffsetParser(); 72 uint32_t GetOffset(); 72 73 73 74 const char* GetString(const char *pszKey); … … 77 78 uint32_t GetUInt32(const char *pszKey); 78 79 79 int Parse ();80 int ParseBlock(); 80 81 81 82 protected: … … 88 89 uint32_t m_cbSize; 89 90 /** 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; 93 92 /** Internal stream buffer. */ 94 93 BYTE *m_pbBuffer; 95 94 }; 95 96 struct 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 }; 96 135 #endif // ____H_GUESTIMPLPRIVATE 97 136 -
trunk/src/VBox/Main/include/GuestImpl.h
r38085 r38235 24 24 25 25 #include "AdditionsFacilityImpl.h" 26 #include "GuestCtrlImplPrivate.h" 27 #include "HGCM.h" 26 28 #ifdef VBOX_WITH_GUEST_CONTROL 27 29 # include <VBox/HostServices/GuestControlSvc.h> 28 # include "HGCM.h"29 30 using namespace guestControl; 30 31 #endif … … 115 116 116 117 // 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 117 133 HRESULT directoryCreateInternal(IN_BSTR aDirectory, IN_BSTR aUserName, IN_BSTR aPassword, 118 134 ULONG aMode, ULONG aFlags, int *pRC); … … 127 143 HRESULT fileExistsInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists, int *pRC); 128 144 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. 138 147 /** Static callback for handling guest notifications. */ 139 148 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); 140 155 # endif 141 static HRESULT setErrorStatic(HRESULT aResultCode,142 const Utf8Str &aText)143 {144 return setErrorInternal(aResultCode, getStaticClassIID(), getStaticComponentName(), aText, false, true);145 }146 156 147 157 private: 158 148 159 #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 155 160 // Internal guest callback representation. 156 161 typedef struct VBOXGUESTCTRL_CALLBACK … … 207 212 char *mpszDirectory; 208 213 char *mpszFilter; 209 ULONG uFlags;214 ULONG mFlags; 210 215 /** Associated PID of started vbox_ls tool. */ 211 216 uint32_t mPID; … … 217 222 typedef std::map< uint32_t, VBOXGUESTCTRL_DIRECTORY >::const_iterator GuestDirectoryMapIterConst; 218 223 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); 220 225 void directoryDestroyHandle(uint32_t uHandle); 221 226 uint32_t directoryGetPID(uint32_t uHandle); -
trunk/src/VBox/Main/src-client/GuestCtrlIO.cpp
r38212 r38235 32 32 : m_cbAllocated(0), 33 33 m_cbSize(0), 34 m_cbOffsetBuffer(0), 35 m_cbOffsetParser(0), 34 m_cbOffset(0), 36 35 m_pbBuffer(NULL) 37 36 { … … 44 43 } 45 44 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 */ 47 53 int GuestProcessStream::AddData(const BYTE *pbData, size_t cbData) 48 54 { … … 53 59 54 60 /* Rewind the buffer if it's empty. */ 55 size_t cbInBuf = m_cbSize - m_cbOffset Buffer;61 size_t cbInBuf = m_cbSize - m_cbOffset; 56 62 bool const fAddToSet = cbInBuf == 0; 57 63 if (fAddToSet) 58 m_cbSize = m_cbOffset Buffer= 0;64 m_cbSize = m_cbOffset = 0; 59 65 60 66 /* Try and see if we can simply append the data. */ … … 67 73 { 68 74 /* Move any buffered data to the front. */ 69 cbInBuf = m_cbSize - m_cbOffset Buffer;75 cbInBuf = m_cbSize - m_cbOffset; 70 76 if (cbInBuf == 0) 71 m_cbSize = m_cbOffset Buffer= 0;72 else if (m_cbOffset Buffer) /* Do we have something to move? */73 { 74 memmove(m_pbBuffer, &m_pbBuffer[m_cbOffset Buffer], 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); 75 81 m_cbSize = cbInBuf; 76 m_cbOffset Buffer= 0;82 m_cbOffset = 0; 77 83 } 78 84 … … 108 114 } 109 115 116 /** 117 * Destroys the currently stored stream pairs. 118 * 119 * @return IPRT status code. 120 */ 110 121 void GuestProcessStream::ClearPairs() 111 122 { … … 120 131 121 132 /** 122 * Destroys the stored stream pairs. 133 * Destroys the currently stored stream pairs and the internal 134 * data buffer. 123 135 */ 124 136 void GuestProcessStream::Destroy() … … 127 139 128 140 if (m_pbBuffer) 141 { 129 142 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 */ 132 158 int GuestProcessStream::GetInt64Ex(const char *pszKey, int64_t *piVal) 133 159 { … … 167 193 } 168 194 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 */ 201 uint32_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. 183 210 * @param pszKey Name of key to get the value for. 184 211 */ … … 200 227 } 201 228 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 */ 202 236 int GuestProcessStream::GetUInt32Ex(const char *pszKey, uint32_t *puVal) 203 237 { … … 227 261 } 228 262 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 */ 269 int GuestProcessStream::ParseBlock() 230 270 { 231 271 AssertPtrReturn(m_pbBuffer, VINF_SUCCESS); 232 272 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(); 234 278 235 279 int rc = VINF_SUCCESS; 236 280 237 size_t uCur = m_cbOffset Parser;281 size_t uCur = m_cbOffset; 238 282 for (;uCur < m_cbSize;) 239 283 { … … 263 307 || pszSep == pszEnd) 264 308 { 265 m_cbOffset Parser= uCur - uPairLen - 1;309 m_cbOffset = uCur - uPairLen - 1; 266 310 rc = VERR_MORE_DATA; 267 311 } … … 304 348 RTMemFree(pszKey); 305 349 306 m_cbOffset Parser += uCur - m_cbOffsetParser;350 m_cbOffset += uCur - m_cbOffset; 307 351 } 308 352 } … … 313 357 if (*pszEnd == '\0') 314 358 { 315 m_cbOffset Parser= uCur;359 m_cbOffset = uCur; 316 360 rc = VERR_MORE_DATA; 317 361 break; … … 325 369 } 326 370 327 RT_CLAMP(m_cbOffset Parser, 0, m_cbSize);371 RT_CLAMP(m_cbOffset, 0, m_cbSize); 328 372 329 373 return rc; -
trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
r38182 r38235 41 41 42 42 #include <memory> 43 44 struct Guest::TaskGuest45 {46 enum TaskType47 {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 installer54 * off the .ISO file, transfer it to the guest and execute the installer55 * with system privileges. */56 UpdateGuestAdditions = 10057 };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_CONTROL115 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 #endif131 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 && !fCanceled166 && 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_CONTROL192 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 functions202 * which get called here can do that.203 */204 205 HRESULT rc = S_OK;206 207 try208 {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 else220 {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 else231 {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 else241 {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 else269 {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 the282 * actual copying, start the guest part now.283 */284 rc = pGuest->ExecuteProcess(Bstr(VBOXSERVICE_TOOL_CAT).raw(),285 ExecuteProcessFlag_Hidden286 | 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 else312 {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 RTFileRead317 * could not resolve/map the native error code to an IPRT code, so just318 * 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 else398 {399 if ( uRetExitCode != 0400 || 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 to415 * 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 else423 {424 /*425 * Even if we succeeded until here make sure to check whether we really transfered426 * everything.427 */428 if ( cbSize > 0429 && cbTransfered == 0)430 {431 /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write432 * 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 functions478 * which get called here can do that.479 */480 481 HRESULT rc = S_OK;482 483 try484 {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 else540 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 the553 * 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 else580 {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 else615 {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 functions653 * which get called here can do that.654 */655 656 HRESULT rc = S_OK;657 BOOL fCompleted;658 BOOL fCanceled;659 660 try661 {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 else683 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 else693 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 else709 {710 uint32_t cbOffset;711 size_t cbLength;712 vrc = RTIsoFsGetFileInfo(&iso, installerImage.c_str(), &cbOffset, &cbLength);713 if ( RT_SUCCESS(vrc)714 && cbOffset715 && 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 else724 {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) to763 * copy over/pipe the data into a file on the guest (with764 * system rights, no username/password specified).765 */766 rc = pGuest->executeProcessInternal(Bstr(VBOXSERVICE_TOOL_CAT).raw(),767 ExecuteProcessFlag_Hidden768 | 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 caller778 * 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 error781 * lookup to figure out what went wrong. */782 switch (vrc)783 {784 /* Guest execution service is not (yet) ready. This basically means that either VBoxService785 * is not running (yet) or that the Guest Additions are too old (because VBoxService does not786 * 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 guest794 * 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 else815 {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 file828 * 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 ( cbRead834 && 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_andy855 LogRel(("Copying Guest Additions (%u bytes left) ...\n", cbLength));856 #endif857 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_andy872 LogRel(("Copying Guest Additions (%u bytes written) ...\n", uBytesWritten));873 #endif874 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 && !fCanceled901 )902 )903 {904 /*905 * Installer was transferred successfully, so let's start it906 * (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 context919 * 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 this923 * 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 status926 * using a running VBoxTray instance via balloon messages in the927 * Windows taskbar. */928 installerArgs.push_back(Bstr("/post_installstatus").raw());929 930 /*931 * Start the just copied over installer with system rights932 * in silent mode on the guest. Don't use the hidden flag since there933 * 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 else954 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 else990 {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 else1007 {1008 LogRel(("Guest Additions update was canceled by the user\n"));1009 }1010 }1011 else1012 rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest);1013 }1014 else1015 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 #endif1033 43 1034 44 // public methods only for internal purposes … … 2111 1121 } 2112 1122 1123 #ifdef VBOX_WITH_GUEST_CONTROL 2113 1124 HRESULT Guest::executeProcessInternal(IN_BSTR aCommand, ULONG aFlags, 2114 1125 ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment), … … 2118 1129 /** @todo r=bird: Eventually we should clean up all the timeout parameters 2119 1130 * in the API and have the same way of specifying infinite waits! */ 2120 #ifndef VBOX_WITH_GUEST_CONTROL2121 ReturnComNotImplemented();2122 #else /* VBOX_WITH_GUEST_CONTROL */2123 1131 using namespace guestControl; 2124 1132 … … 2354 1362 } 2355 1363 return rc; 1364 } 2356 1365 #endif /* VBOX_WITH_GUEST_CONTROL */ 2357 }2358 1366 2359 1367 STDMETHODIMP Guest::SetProcessInput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ComSafeArrayIn(BYTE, aData), ULONG *aBytesWritten) … … 2812 1820 2813 1821 /* Initialize our worker task. */ 2814 TaskGuest *pTask = new TaskGuest(TaskGuest::CopyFileFromGuest, this, progress);1822 GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileFromGuest, this, progress); 2815 1823 AssertPtr(pTask); 2816 std::auto_ptr< TaskGuest> task(pTask);1824 std::auto_ptr<GuestTask> task(pTask); 2817 1825 2818 1826 /* Assign data - aSource is the source file on the host, … … 2887 1895 2888 1896 /* Initialize our worker task. */ 2889 TaskGuest *pTask = new TaskGuest(TaskGuest::CopyFileToGuest, this, progress);1897 GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileToGuest, this, progress); 2890 1898 AssertPtr(pTask); 2891 std::auto_ptr< TaskGuest> task(pTask);1899 std::auto_ptr<GuestTask> task(pTask); 2892 1900 2893 1901 /* Assign data - aSource is the source file on the host, … … 2919 1927 } 2920 1928 2921 STDMETHODIMP Guest::DirectoryClose(ULONG aHandle)2922 {2923 #ifndef VBOX_WITH_GUEST_CONTROL2924 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 #endif2937 }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_CONTROL2944 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 #endif2961 }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_CONTROL2968 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 try2988 {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 else3058 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 else3099 {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_CONTROL3168 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 #endif3184 }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_CONTROL3192 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 try3208 {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 form3222 * 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 of3226 * 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 by3231 * 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 else3239 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 else3293 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_CONTROL3321 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 #endif3345 }3346 3347 STDMETHODIMP Guest::FileExists(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists)3348 {3349 #ifndef VBOX_WITH_GUEST_CONTROL3350 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 #endif3364 }3365 3366 HRESULT Guest::fileExistsInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, BOOL *aExists, int *pRC)3367 {3368 #ifndef VBOX_WITH_GUEST_CONTROL3369 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 try3380 {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 form3393 * 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 else3438 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 else3447 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 #endif3456 }3457 3458 STDMETHODIMP Guest::FileQuerySize(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, LONG64 *aSize)3459 {3460 #ifndef VBOX_WITH_GUEST_CONTROL3461 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 #endif3475 }3476 3477 HRESULT Guest::fileQuerySizeInternal(IN_BSTR aFile, IN_BSTR aUserName, IN_BSTR aPassword, LONG64 *aSize, int *pRC)3478 {3479 #ifndef VBOX_WITH_GUEST_CONTROL3480 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 try3491 {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 form3504 * 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 else3584 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 else3589 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 else3595 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 else3605 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 #endif3614 }3615 3616 1929 STDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ULONG aFlags, IProgress **aProgress) 3617 1930 { … … 3648 1961 3649 1962 /* Initialize our worker task. */ 3650 TaskGuest *pTask = new TaskGuest(TaskGuest::UpdateGuestAdditions, this, progress);1963 GuestTask *pTask = new GuestTask(GuestTask::TaskType_UpdateGuestAdditions, this, progress); 3651 1964 AssertPtr(pTask); 3652 std::auto_ptr< TaskGuest> task(pTask);1965 std::auto_ptr<GuestTask> task(pTask); 3653 1966 3654 1967 /* Assign data - in that case aSource is the full path -
trunk/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp
r38214 r38235 144 144 if (RT_SUCCESS(iResult)) 145 145 { 146 iResult = stream.Parse ();146 iResult = stream.ParseBlock(); 147 147 if (iResult != aTests[iTest].iResult) 148 148 { … … 155 155 stream.GetNumPairs(), aTests[iTest].uMapElements); 156 156 } 157 else if (stream.GetOffset Parser() != aTests[iTest].uOffsetAfter)157 else if (stream.GetOffset() != aTests[iTest].uOffsetAfter) 158 158 { 159 159 RTTestFailed(hTest, "\tOffset %u wrong, expected %u", 160 stream.GetOffset Parser(), aTests[iTest].uOffsetAfter);160 stream.GetOffset(), aTests[iTest].uOffsetAfter); 161 161 } 162 162 else if (iResult == VERR_MORE_DATA) … … 192 192 do 193 193 { 194 iResult = stream.Parse ();194 iResult = stream.ParseBlock(); 195 195 RTTestIPrintf(RTTESTLVL_DEBUG, "\tReturned with %Rrc\n", iResult); 196 196 if ( iResult == VINF_SUCCESS
Note:
See TracChangeset
for help on using the changeset viewer.