Changeset 43162 in vbox
- Timestamp:
- Sep 4, 2012 1:53:59 PM (12 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/idl/VirtualBox.xidl
r43065 r43162 9031 9031 <desc> 9032 9032 The waiting operation timed out. This also will happen 9033 when no event has been occured matching the specified the9034 current waiting flags in the<link to="IProcess::waitFor"/> call.9033 when no event has been occured matching the 9034 current waiting flags in a <link to="IProcess::waitFor"/> call. 9035 9035 </desc> 9036 9036 </const> -
trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
r43061 r43162 71 71 72 72 /** 73 * Genericclass for a all guest control callbacks/events.73 * Base class for a all guest control callbacks/events. 74 74 */ 75 75 class GuestCtrlEvent … … 121 121 { 122 122 public: 123 123 124 GuestCtrlCallback(void); 124 125 … … 165 166 typedef std::map < uint32_t, GuestCtrlCallback* > GuestCtrlCallbacks; 166 167 167 struct GuestProcessWaitResult 168 { 169 GuestProcessWaitResult(void) 170 : mResult(ProcessWaitResult_None), 171 mRC(VINF_SUCCESS) { } 172 173 /** The wait result when returning from the wait call. */ 168 169 /* 170 * Class representing a guest control process waiting 171 * event. 172 */ 173 class GuestProcessWaitEvent : public GuestCtrlEvent 174 { 175 public: 176 177 GuestProcessWaitEvent(void); 178 179 GuestProcessWaitEvent(uint32_t uWaitFlags); 180 181 virtual ~GuestProcessWaitEvent(void); 182 183 public: 184 185 void Destroy(void); 186 187 int Init(uint32_t uWaitFlags); 188 189 uint32_t GetWaitFlags(void) { return ASMAtomicReadU32(&mFlags); } 190 191 ProcessWaitResult_T GetWaitResult(void) { return mResult; } 192 193 int GetWaitRc(void) { return mRC; } 194 195 int Signal(ProcessWaitResult_T enmResult, int rc = VINF_SUCCESS); 196 197 protected: 198 199 /** The waiting flag(s). The specifies what to 200 * wait for. See ProcessWaitFlag_T. */ 201 uint32_t mFlags; 202 /** Structure containing the overall result. */ 174 203 ProcessWaitResult_T mResult; 175 /** Optional rc to this result. */176 int mRC;177 };178 179 180 /*181 * Class representing a guest control process event.182 */183 class GuestProcessEvent : public GuestCtrlEvent184 {185 public:186 GuestProcessEvent(void);187 188 GuestProcessEvent(uint32_t uWaitFlags);189 190 virtual ~GuestProcessEvent(void);191 192 public:193 194 void Destroy(void);195 196 int Init(uint32_t uWaitFlags);197 198 uint32_t GetWaitFlags(void) { return ASMAtomicReadU32(&mWaitFlags); }199 200 GuestProcessWaitResult GetResult(void) { return mWaitResult; }201 202 int Signal(ProcessWaitResult_T enmResult, int rc = VINF_SUCCESS);203 204 protected:205 206 /** The waiting flag(s). The specifies what to207 * wait for. */208 uint32_t mWaitFlags;209 /** Structure containing the overall result. */210 GuestProcessWaitResult mWaitResult;211 204 }; 212 205 -
trunk/src/VBox/Main/include/GuestDirectoryImpl.h
r42897 r43162 21 21 22 22 #include "VirtualBoxBase.h" 23 #include "Guest CtrlImplPrivate.h"23 #include "GuestProcessImpl.h" 24 24 25 class GuestProcess;26 25 class GuestSession; 27 26 … … 45 44 DECLARE_EMPTY_CTOR_DTOR(GuestDirectory) 46 45 47 int init(GuestSession *aSession, const Utf8Str &strPath, const Utf8Str &strFilter = "", uint32_t uFlags = 0);46 int init(GuestSession *aSession, const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags); 48 47 void uninit(void); 49 48 HRESULT FinalConstruct(void); … … 68 67 /** @name Private internal methods. 69 68 * @{ */ 70 int parseData(GuestProcessStreamBlock &streamBlock);71 69 /** @} */ 72 70 … … 77 75 Utf8Str mFilter; 78 76 uint32_t mFlags; 79 /** The stdout stream object which contains all 80 * read out data for parsing. Must be persisent 81 * between several read() calls. */ 82 GuestProcessStream mStream; 83 /** The guest process which is responsible for 84 * getting the stdout stream. */ 85 GuestProcess *mProcess; 77 GuestProcessTool mProcessTool; 86 78 } mData; 87 79 }; -
trunk/src/VBox/Main/include/GuestFileImpl.h
r42897 r43162 46 46 DECLARE_EMPTY_CTOR_DTOR(GuestFile) 47 47 48 int init(GuestSession *pSession, const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition, uint32_t uCreationMode, int64_t iOffset );48 int init(GuestSession *pSession, const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition, uint32_t uCreationMode, int64_t iOffset, int *pGuestRc); 49 49 void uninit(void); 50 50 HRESULT FinalConstruct(void); -
trunk/src/VBox/Main/include/GuestProcessImpl.h
r42897 r43162 75 75 inline bool callbackExists(uint32_t uContextID); 76 76 inline int checkPID(uint32_t uPID); 77 Utf8Str errorMsg(void) { return mData.mErrorMsg; }77 static Utf8Str guestErrorToString(int guestRc); 78 78 bool isReady(void); 79 79 ULONG getProcessID(void) { return mData.mProcessID; } 80 int r c(void) { return mData.mRC; }81 int readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead);82 int startProcess( void);80 int readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc); 81 static HRESULT setErrorExternal(VirtualBoxBase *pInterface, int guestRc); 82 int startProcess(int *pGuestRc); 83 83 int startProcessAsync(void); 84 84 int terminateProcess(void); 85 int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestProcessWaitResult &guestResult); 86 int waitForStart(uint32_t uTimeoutMS); 87 int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten); 85 int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc); 86 int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc); 88 87 /** @} */ 89 88 … … 101 100 int prepareExecuteEnv(const char *pszEnv, void **ppvList, ULONG *pcbList, ULONG *pcEnvVars); 102 101 int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms); 103 int setErrorInternal(int rc, const Utf8Str &strMessage); 104 HRESULT setErrorExternal(void); 105 int signalWaiters(ProcessWaitResult_T enmWaitResult); 102 int setProcessStatus(ProcessStatus_T procStatus, int procRc); 103 int signalWaiters(ProcessWaitResult_T enmWaitResult, int rc = VINF_SUCCESS); 106 104 static DECLCALLBACK(int) startProcessThread(RTTHREAD Thread, void *pvUser); 107 105 /** @} */ … … 130 128 /** The current process status. */ 131 129 ProcessStatus_T mStatus; 132 /** The overall rc of the process execution. */133 130 int mRC; 134 /** The overall error message of the135 * process execution. */136 Utf8Str mErrorMsg;137 131 /** The next upcoming context ID. */ 138 132 ULONG mNextContextID; … … 144 138 /** The actual process event for doing the waits. 145 139 * At the moment we only support one wait a time. */ 146 GuestProcess Event*mWaitEvent;140 GuestProcessWaitEvent *mWaitEvent; 147 141 } mData; 142 }; 143 144 /** 145 * Guest process tool flags. 146 */ 147 /** No flags specified. */ 148 #define GUESTPROCESSTOOL_FLAG_NONE 0 149 /** Run until next stream block from stdout has been 150 * read in completely, then return. 151 */ 152 #define GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK RT_BIT(0) 153 154 /** 155 * Internal class for handling a VBoxService tool ("vbox_ls", vbox_stat", ...). 156 */ 157 class GuestProcessTool 158 { 159 public: 160 161 GuestProcessTool(void); 162 163 virtual ~GuestProcessTool(void); 164 165 public: 166 167 int Init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo, bool fAsync, int *pGuestRc); 168 169 GuestProcessStream &GetStdOut(void) { return mStdOut; } 170 171 GuestProcessStream &GetStdErr(void) { return mStdErr; } 172 173 int Wait(uint32_t fFlags, int *pGuestRc); 174 175 int WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBlock, int *pGuestRc); 176 177 int GetCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock &strmBlock); 178 179 bool IsRunning(void); 180 181 int TerminatedOk(LONG *pExitCode); 182 183 void Terminate(void); 184 185 protected: 186 187 GuestSession *pSession; 188 ComObjPtr<GuestProcess> pProcess; 189 GuestProcessStartupInfo mStartupInfo; 190 GuestProcessStream mStdOut; 191 GuestProcessStream mStdErr; 148 192 }; 149 193 -
trunk/src/VBox/Main/include/GuestSessionImpl.h
r43002 r43162 297 297 * @{ */ 298 298 int directoryRemoveFromList(GuestDirectory *pDirectory); 299 int directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags); 300 int objectCreateTempInternal(Utf8Str strTemplate, 301 Utf8Str strPath, 302 bool fDirectory, 303 Utf8Str &strName, 304 int *prc); 299 int directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags, int *pGuestRc); 300 int objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath, bool fDirectory, const Utf8Str &strName, int *pGuestRc); 305 301 int directoryOpenInternal(const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags, ComObjPtr<GuestDirectory> &pDirectory); 306 int directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData );302 int directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc); 307 303 int dispatchToProcess(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData); 308 304 int fileRemoveFromList(GuestFile *pFile); 309 int fileRemoveInternal( Utf8Str strPath, int *prc);305 int fileRemoveInternal(const Utf8Str &strPath, int *pGuestRc); 310 306 int fileOpenInternal(const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition, 311 uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile );312 int fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData );313 int fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize );314 int fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData );307 uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile, int *pGuestRc); 308 int fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc); 309 int fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize, int *pGuestRc); 310 int fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc); 315 311 const GuestCredentials &getCredentials(void); 316 312 const GuestEnvironment &getEnvironment(void); -
trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
r42897 r43162 102 102 int GuestCtrlEvent::Wait(ULONG uTimeoutMS) 103 103 { 104 LogFlow FuncEnter();104 LogFlowThisFuncEnter(); 105 105 106 106 AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED); … … 304 304 /////////////////////////////////////////////////////////////////////////////// 305 305 306 GuestProcessEvent::GuestProcessEvent(void) 307 : mWaitFlags(0) 308 { 309 } 310 311 GuestProcessEvent::GuestProcessEvent(uint32_t uWaitFlags) 312 : mWaitFlags(uWaitFlags) 306 GuestProcessWaitEvent::GuestProcessWaitEvent(void) 307 : mFlags(0), 308 mResult(ProcessWaitResult_None) 309 { 310 } 311 312 GuestProcessWaitEvent::GuestProcessWaitEvent(uint32_t uWaitFlags) 313 : mFlags(uWaitFlags) 313 314 { 314 315 int rc = GuestCtrlEvent::Init(); … … 316 317 } 317 318 318 GuestProcess Event::~GuestProcessEvent(void)319 GuestProcessWaitEvent::~GuestProcessWaitEvent(void) 319 320 { 320 321 Destroy(); 321 322 } 322 323 323 void GuestProcess Event::Destroy(void)324 void GuestProcessWaitEvent::Destroy(void) 324 325 { 325 326 GuestCtrlEvent::Destroy(); 326 327 327 mWaitFlags = ProcessWaitForFlag_None; 328 } 329 330 int GuestProcessEvent::Signal(ProcessWaitResult_T enmResult, int rc /*= VINF_SUCCESS*/) 331 { 332 mWaitResult.mRC = rc; 333 mWaitResult.mResult = enmResult; 328 mFlags = ProcessWaitForFlag_None; 329 } 330 331 int GuestProcessWaitEvent::Signal(ProcessWaitResult_T enmResult, int rc /*= VINF_SUCCESS*/) 332 { 333 mResult = enmResult; 334 334 335 335 return GuestCtrlEvent::Signal(rc); -
trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp
r42897 r43162 60 60 61 61 int GuestDirectory::init(GuestSession *aSession, 62 const Utf8Str &strPath, const Utf8Str &strFilter /*= ""*/, uint32_t uFlags /*= 0*/)62 const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags) 63 63 { 64 64 LogFlowThisFunc(("strPath=%s, strFilter=%s, uFlags=%x\n", … … 78 78 procInfo.mName = Utf8StrFmt(tr("Reading directory \"%s\"", strPath.c_str())); 79 79 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_LS); 80 procInfo.mTimeoutMS = 0; /* Notimeout. */81 procInfo.mFlags = ProcessCreateFlag_ Hidden | ProcessCreateFlag_WaitForStdOut;80 procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */ 81 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; 82 82 83 83 procInfo.mArguments.push_back(Utf8Str("--machinereadable")); … … 94 94 * Start the process asynchronously and keep it around so that we can use 95 95 * it later in subsequent read() calls. 96 * Note: No guest rc available because operation is asynchronous. 96 97 */ 97 ComObjPtr<GuestProcess> pProcess;98 int rc = mData.mSession->processCreateExInteral(procInfo, pProcess);98 int rc = mData.mProcessTool.Init(mData.mSession, procInfo, 99 true /* Async */, NULL /* Guest rc */); 99 100 if (RT_SUCCESS(rc)) 100 rc = pProcess->startProcessAsync(); 101 102 LogFlowThisFunc(("rc=%Rrc\n", rc)); 103 104 if (RT_SUCCESS(rc)) 105 { 106 mData.mProcess = pProcess; 107 101 { 108 102 /* Confirm a successful initialization when it's the case. */ 109 103 autoInitSpan.setSucceeded(); … … 169 163 ///////////////////////////////////////////////////////////////////////////// 170 164 171 int GuestDirectory::parseData(GuestProcessStreamBlock &streamBlock)172 {173 LogFlowThisFunc(("cbStream=%RU32\n", mData.mStream.GetSize()));174 175 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);176 177 int rc;178 do179 {180 /* Try parsing the data to see if the current block is complete. */181 rc = mData.mStream.ParseBlock(streamBlock);182 if (streamBlock.GetCount())183 break;184 185 } while (RT_SUCCESS(rc));186 187 LogFlowFuncLeaveRC(rc);188 return rc;189 }190 191 165 // implementation of public methods 192 166 ///////////////////////////////////////////////////////////////////////////// … … 204 178 AssertPtr(mData.mSession); 205 179 int rc = mData.mSession->directoryRemoveFromList(this); 206 if (mData.mProcess) 207 { 208 int rc2 = mData.mSession->processRemoveFromList(mData.mProcess); 209 if (RT_SUCCESS(rc)) 210 rc = rc2; 211 } 180 181 mData.mProcessTool.Terminate(); 212 182 213 183 /* … … 233 203 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 234 204 235 ComObjPtr<GuestProcess> pProcess = mData.mProcess; 236 Assert(!pProcess.isNull()); 237 238 GuestProcessStreamBlock streamBlock; 239 GuestFsObjData objData; 240 241 int rc = parseData(streamBlock); 242 if ( RT_FAILURE(rc) 243 || streamBlock.IsEmpty()) /* More data needed. */ 244 { 245 rc = pProcess->waitForStart(30 * 1000 /* 30s timeout */); 205 GuestProcessStreamBlock curBlock; 206 int guestRc; 207 208 int rc = mData.mProcessTool.WaitEx(GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK, 209 &curBlock, &guestRc); 210 211 /* 212 * Note: The guest process can still be around to serve the next 213 * upcoming stream block next time. 214 */ 215 if ( RT_SUCCESS(rc) 216 && !mData.mProcessTool.IsRunning()) 217 { 218 rc = mData.mProcessTool.TerminatedOk(NULL /* Exit code */); 219 if (rc == VERR_NOT_EQUAL) 220 rc = VERR_ACCESS_DENIED; 246 221 } 247 222 248 223 if (RT_SUCCESS(rc)) 249 224 { 250 BYTE byBuf[_64K]; 251 size_t cbRead = 0; 252 253 /** @todo Merge with GuestSession::queryFileInfoInternal. */ 254 for (;RT_SUCCESS(rc);) 225 if (curBlock.GetCount()) /* Did we get content? */ 255 226 { 256 GuestProcessWaitResult waitRes; 257 rc = pProcess->waitFor( ProcessWaitForFlag_Terminate 258 | ProcessWaitForFlag_StdOut, 259 30 * 1000 /* Timeout */, waitRes); 260 if ( RT_FAILURE(rc) 261 || waitRes.mResult == ProcessWaitResult_Terminate 262 || waitRes.mResult == ProcessWaitResult_Error 263 || waitRes.mResult == ProcessWaitResult_Timeout) 264 { 265 if (RT_FAILURE(waitRes.mRC)) 266 rc = waitRes.mRC; 267 break; 268 } 269 270 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf), 271 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf), 272 &cbRead); 273 if (RT_FAILURE(rc)) 274 break; 275 276 if (cbRead) 277 { 278 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 279 280 rc = mData.mStream.AddData(byBuf, cbRead); 281 if (RT_FAILURE(rc)) 282 break; 283 284 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64, cbStreamOut=%RU32\n", 285 rc, cbRead, mData.mStream.GetSize())); 286 287 rc = parseData(streamBlock); 288 if (RT_SUCCESS(rc)) 289 { 290 /* Parsing the current stream block succeeded so 291 * we don't need more at the moment. */ 292 break; 293 } 294 } 295 } 296 297 LogFlowThisFunc(("Reading done with rc=%Rrc, cbRead=%RU64, cbStream=%RU32\n", 298 rc, cbRead, mData.mStream.GetSize())); 299 300 if (RT_SUCCESS(rc)) 301 { 302 rc = parseData(streamBlock); 303 if (rc == VERR_NO_DATA) /* Since this is the last parsing call, this is ok. */ 304 rc = VINF_SUCCESS; 305 } 306 307 /* 308 * Note: The guest process can still be around to serve the next 309 * upcoming stream block next time. 310 */ 311 if (RT_SUCCESS(rc)) 312 { 313 /** @todo Move into common function. */ 314 ProcessStatus_T procStatus = ProcessStatus_Undefined; 315 LONG exitCode = 0; 316 317 HRESULT hr2 = pProcess->COMGETTER(Status(&procStatus)); 318 ComAssertComRC(hr2); 319 hr2 = pProcess->COMGETTER(ExitCode(&exitCode)); 320 ComAssertComRC(hr2); 321 322 if ( ( procStatus != ProcessStatus_Started 323 && procStatus != ProcessStatus_Paused 324 && procStatus != ProcessStatus_Terminating 325 ) 326 && exitCode != 0) 327 { 328 rc = VERR_ACCESS_DENIED; 329 } 330 } 331 } 332 333 if (RT_SUCCESS(rc)) 334 { 335 if (streamBlock.GetCount()) /* Did we get content? */ 336 { 337 rc = objData.FromLs(streamBlock); 227 GuestFsObjData objData; 228 rc = objData.FromLs(curBlock); 338 229 if (RT_FAILURE(rc)) 339 230 rc = VERR_PATH_NOT_FOUND; … … 372 263 switch (rc) 373 264 { 265 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 266 hr = GuestProcess::setErrorExternal(this, guestRc); 267 break; 268 374 269 case VERR_ACCESS_DENIED: 375 270 hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Unable to read / access denied"), … … 383 278 384 279 case VERR_NO_MORE_FILES: 280 /* See SDK reference. */ 385 281 hr = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No more entries for directory \"%s\""), 386 282 mData.mName.c_str()); -
trunk/src/VBox/Main/src-client/GuestFileImpl.cpp
r42897 r43162 61 61 int GuestFile::init(GuestSession *pSession, const Utf8Str &strPath, 62 62 const Utf8Str &strOpenMode, const Utf8Str &strDisposition, uint32_t uCreationMode, 63 int64_t iOffset )63 int64_t iOffset, int *pGuestRc) 64 64 { 65 65 /* Enclose the state transition NotReady->InInit->Ready. */ … … 76 76 77 77 /** @todo Validate parameters! */ 78 /** @todo Implement guest side file handling! */ 78 79 79 80 /* Confirm a successful initialization when it's the case. */ -
trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
r43062 r43162 426 426 AssertPtr(pCallback); 427 427 #ifdef DEBUG 428 LogFlowThisFunc(("pCallback=%p\n", pCallback)); 428 LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n", 429 pCallback, uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID))); 429 430 #endif 430 431 } … … 497 498 inline int GuestProcess::callbackRemove(uint32_t uContextID) 498 499 { 500 LogFlowThisFunc(("Removing callback (Session: %RU32, Process: %RU32, Count=%RU32) CID=%RU32\n", 501 VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID), 502 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID), 503 VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID), 504 uContextID)); 505 499 506 GuestCtrlCallbacks::iterator it = 500 507 mData.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID)); … … 545 552 } 546 553 554 /* static */ 555 Utf8Str GuestProcess::guestErrorToString(int guestRc) 556 { 557 Utf8Str strError; 558 559 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */ 560 switch (guestRc) 561 { 562 case VERR_FILE_NOT_FOUND: /* This is the most likely error. */ 563 strError += Utf8StrFmt(tr("The specified file was not found on guest")); 564 break; 565 566 case VERR_INVALID_VM_HANDLE: 567 strError += Utf8StrFmt(tr("VMM device is not available (is the VM running?)")); 568 break; 569 570 case VERR_HGCM_SERVICE_NOT_FOUND: 571 strError += Utf8StrFmt(tr("The guest execution service is not available")); 572 break; 573 574 case VERR_PATH_NOT_FOUND: 575 strError += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest")); 576 break; 577 578 case VERR_BAD_EXE_FORMAT: 579 strError += Utf8StrFmt(tr("The specified file is not an executable format on guest")); 580 break; 581 582 case VERR_AUTHENTICATION_FAILURE: 583 strError += Utf8StrFmt(tr("The specified user was not able to logon on guest")); 584 break; 585 586 case VERR_INVALID_NAME: 587 strError += Utf8StrFmt(tr("The specified file is an invalid name")); 588 break; 589 590 case VERR_TIMEOUT: 591 strError += Utf8StrFmt(tr("The guest did not respond within time")); 592 break; 593 594 case VERR_CANCELLED: 595 strError += Utf8StrFmt(tr("The execution operation was canceled")); 596 break; 597 598 case VERR_PERMISSION_DENIED: 599 strError += Utf8StrFmt(tr("Invalid user/password credentials")); 600 break; 601 602 case VERR_MAX_PROCS_REACHED: 603 strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached")); 604 break; 605 606 case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */ 607 strError += Utf8StrFmt(tr("Unable to retrieving requested information")); 608 break; 609 610 case VERR_NOT_FOUND: 611 strError += Utf8StrFmt(tr("The guest execution service is not ready (yet)")); 612 break; 613 614 default: 615 strError += Utf8StrFmt(tr("%Rrc"), guestRc); 616 break; 617 } 618 619 return strError; 620 } 621 547 622 inline bool GuestProcess::isAlive(void) 548 623 { … … 649 724 return vrc; 650 725 651 BOOL fSignal = FALSE; 726 ProcessStatus_T procStatus = ProcessStatus_Undefined; 727 int procRc = VINF_SUCCESS; 728 729 bool fSignalWaiters = false; 652 730 ProcessWaitResult_T waitRes; 731 653 732 uint32_t uWaitFlags = mData.mWaitEvent 654 733 ? mData.mWaitEvent->GetWaitFlags() : 0; 655 734 switch (pData->u32Status) 656 735 { 657 case PROC_STS_STARTED:658 { 659 fSignal = (uWaitFlags & ProcessWaitForFlag_Start);736 case PROC_STS_STARTED: 737 { 738 fSignalWaiters = (uWaitFlags & ProcessWaitForFlag_Start); 660 739 /* If the caller only wants to wait until the process has been started, 661 740 * notify in any case. */ 662 741 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly) 663 fSignal = true;742 fSignalWaiters = true; 664 743 waitRes = ProcessWaitResult_Start; 665 744 666 mData.mStatus = ProcessStatus_Started;667 mData.mPID = pData->u32PID; 745 procStatus = ProcessStatus_Started; 746 mData.mPID = pData->u32PID; /* Set the process PID. */ 668 747 break; 669 748 } … … 671 750 case PROC_STS_TEN: 672 751 { 673 fSignal = TRUE; /* Signal in any case. */752 fSignalWaiters = true; /* Signal in any case. */ 674 753 waitRes = ProcessWaitResult_Terminate; 675 754 676 mData.mStatus = ProcessStatus_TerminatedNormally;755 procStatus = ProcessStatus_TerminatedNormally; 677 756 mData.mExitCode = pData->u32Flags; /* Contains the exit code. */ 678 757 break; … … 681 760 case PROC_STS_TES: 682 761 { 683 fSignal = TRUE; /* Signal in any case. */762 fSignalWaiters = true; /* Signal in any case. */ 684 763 waitRes = ProcessWaitResult_Terminate; 685 764 686 mData.mStatus = ProcessStatus_TerminatedSignal;765 procStatus = ProcessStatus_TerminatedSignal; 687 766 mData.mExitCode = pData->u32Flags; /* Contains the signal. */ 688 767 break; … … 691 770 case PROC_STS_TEA: 692 771 { 693 fSignal = TRUE; /* Signal in any case. */772 fSignalWaiters = true; /* Signal in any case. */ 694 773 waitRes = ProcessWaitResult_Terminate; 695 774 696 mData.mStatus = ProcessStatus_TerminatedAbnormally;775 procStatus = ProcessStatus_TerminatedAbnormally; 697 776 break; 698 777 } … … 700 779 case PROC_STS_TOK: 701 780 { 702 fSignal = TRUE; /* Signal in any case. */781 fSignalWaiters = true; /* Signal in any case. */ 703 782 waitRes = ProcessWaitResult_Timeout; 704 783 705 mData.mStatus = ProcessStatus_TimedOutKilled;784 procStatus = ProcessStatus_TimedOutKilled; 706 785 break; 707 786 } … … 709 788 case PROC_STS_TOA: 710 789 { 711 fSignal = TRUE; /* Signal in any case. */790 fSignalWaiters = true; /* Signal in any case. */ 712 791 waitRes = ProcessWaitResult_Timeout; 713 792 714 mData.mStatus = ProcessStatus_TimedOutAbnormally;793 procStatus = ProcessStatus_TimedOutAbnormally; 715 794 break; 716 795 } … … 718 797 case PROC_STS_DWN: 719 798 { 720 fSignal = TRUE; /* Signal in any case. */799 fSignalWaiters = true; /* Signal in any case. */ 721 800 /* Do we need to report termination? */ 722 801 if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses) … … 725 804 waitRes = ProcessWaitResult_Terminate; 726 805 727 mData.mStatus = ProcessStatus_Down;806 procStatus = ProcessStatus_Down; 728 807 break; 729 808 } … … 731 810 case PROC_STS_ERROR: 732 811 { 733 fSignal = TRUE; /* Signal in any case. */812 fSignalWaiters = true; /* Signal in any case. */ 734 813 waitRes = ProcessWaitResult_Error; 735 814 736 mData.mStatus = ProcessStatus_Error; 737 738 Utf8Str strError = Utf8StrFmt(tr("Guest process \"%s\" could not be started: "), mData.mProcess.mCommand.c_str()); 739 740 /* Note: It's not required that the process has been started before. */ 741 if (mData.mPID) 742 { 743 strError += Utf8StrFmt(tr("Error vrc=%Rrc occured (PID %RU32)"), vrc, mData.mPID); 744 } 745 else 746 { 747 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */ 748 switch (pData->u32Flags) /* pData->u32Flags contains the IPRT error code from guest side. */ 749 { 750 case VERR_FILE_NOT_FOUND: /* This is the most likely error. */ 751 strError += Utf8StrFmt(tr("The specified file was not found on guest")); 752 break; 753 754 case VERR_PATH_NOT_FOUND: 755 strError += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest")); 756 break; 757 758 case VERR_BAD_EXE_FORMAT: 759 strError += Utf8StrFmt(tr("The specified file is not an executable format on guest")); 760 break; 761 762 case VERR_AUTHENTICATION_FAILURE: 763 strError += Utf8StrFmt(tr("The specified user was not able to logon on guest")); 764 break; 765 766 case VERR_INVALID_NAME: 767 strError += Utf8StrFmt(tr("The specified file is an invalid name")); 768 break; 769 770 case VERR_TIMEOUT: 771 strError += Utf8StrFmt(tr("The guest did not respond within time")); 772 break; 773 774 case VERR_CANCELLED: 775 strError += Utf8StrFmt(tr("The execution operation was canceled")); 776 break; 777 778 case VERR_PERMISSION_DENIED: 779 strError += Utf8StrFmt(tr("Invalid user/password credentials")); 780 break; 781 782 case VERR_MAX_PROCS_REACHED: 783 strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached")); 784 break; 785 786 default: 787 strError += Utf8StrFmt(tr("Reported error %Rrc"), pData->u32Flags); 788 break; 789 } 790 } 791 792 vrc = setErrorInternal(pData->u32Flags, strError); 793 AssertRC(vrc); 815 procRc = pData->u32Flags; /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */ 816 procStatus = ProcessStatus_Error; 794 817 break; 795 818 } … … 799 822 { 800 823 /* Silently skip this request. */ 801 fSignal = TRUE; /* Signal in any case. */824 fSignalWaiters = true; /* Signal in any case. */ 802 825 waitRes = ProcessWaitResult_Status; 803 826 804 mData.mStatus = ProcessStatus_Undefined; 805 break; 806 } 807 } 808 809 LogFlowThisFunc(("Got vrc=%Rrc, waitResult=%d\n", vrc, waitRes)); 827 procStatus = ProcessStatus_Undefined; 828 break; 829 } 830 } 831 832 LogFlowThisFunc(("Got rc=%Rrc, waitRes=%d, procSts=%ld, procRc=%Rrc, fSignalWaiters=%RTbool\n", 833 vrc, waitRes, procStatus, procRc, fSignalWaiters)); 834 835 /* Set the process status. */ 836 int rc2 = setProcessStatus(procStatus, procRc); 837 if (RT_SUCCESS(vrc)) 838 vrc = rc2; 810 839 811 840 /* … … 813 842 */ 814 843 if (pCallback) 815 vrc = pCallback->Signal( );816 817 if (fSignal )818 { 819 int rc2 = signalWaiters(waitRes);844 vrc = pCallback->Signal(procRc); 845 846 if (fSignalWaiters) 847 { 848 rc2 = signalWaiters(waitRes, procRc); 820 849 if (RT_SUCCESS(vrc)) 821 850 vrc = rc2; … … 885 914 886 915 int GuestProcess::readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS, 887 void *pvData, size_t cbData, size_t *pcbRead )888 { 889 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32 \n",890 mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData ));916 void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc) 917 { 918 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32, pGuestRc=%p\n", 919 mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData, pGuestRc)); 891 920 AssertReturn(uSize, VERR_INVALID_PARAMETER); 892 921 AssertPtrReturn(pvData, VERR_INVALID_POINTER); … … 900 929 if (pcbRead) 901 930 *pcbRead = 0; 931 if (pGuestRc) 932 *pGuestRc = VINF_SUCCESS; 902 933 return VINF_SUCCESS; /* Nothing to read anymore. */ 903 934 } 904 935 936 int vrc = VINF_SUCCESS; 937 938 GuestCtrlCallback *pCallbackRead; 939 try 940 { 941 pCallbackRead = new GuestCtrlCallback(); 942 AssertPtr(pCallbackRead); 943 } 944 catch(std::bad_alloc &) 945 { 946 vrc = VERR_NO_MEMORY; 947 } 948 949 /* Create callback and add it to the map. */ 905 950 uint32_t uContextID = 0; 906 GuestCtrlCallback *pCallbackRead = new GuestCtrlCallback();907 if (!pCallbackRead)908 return VERR_NO_MEMORY;909 910 /* Create callback and add it to the map. */911 int vrc = pCallbackRead->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT);912 951 if (RT_SUCCESS(vrc)) 913 vrc = callbackAdd(pCallbackRead, &uContextID); 952 { 953 vrc = pCallbackRead->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT); 954 if (RT_SUCCESS(vrc)) 955 vrc = callbackAdd(pCallbackRead, &uContextID); 956 } 914 957 915 958 alock.release(); /* Drop the write lock again. */ … … 938 981 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 939 982 { 940 vrc = pCallbackRead->GetResultCode();941 LogFlowThisFunc(("Callback returned vrc=%Rrc, cbData=%RU32\n", vrc, pCallbackRead->GetDataSize()));942 943 if (RT_SUCCESS( vrc))983 int guestRc = pCallbackRead->GetResultCode(); 984 LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", guestRc, pCallbackRead->GetDataSize())); 985 986 if (RT_SUCCESS(guestRc)) 944 987 { 945 988 Assert(pCallbackRead->GetDataSize() == sizeof(CALLBACKDATAEXECOUT)); … … 959 1002 *pcbRead = cbRead; 960 1003 } 961 } 962 else 963 vrc = VERR_TIMEOUT; 1004 else 1005 vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ 1006 1007 if (pGuestRc) 1008 *pGuestRc = guestRc; 1009 } 964 1010 } 965 1011 … … 991 1037 if (RT_FAILURE(vrc)) 992 1038 { 993 int rc2; 994 if (vrc == VERR_INVALID_VM_HANDLE) 995 rc2 = setErrorInternal(vrc, tr("VMM device is not available (is the VM running?)")); 996 else if (vrc == VERR_NOT_FOUND) 997 rc2 = setErrorInternal(vrc, tr("The guest execution service is not ready (yet)")); 998 else if (vrc == VERR_HGCM_SERVICE_NOT_FOUND) 999 rc2 = setErrorInternal(vrc, tr("The guest execution service is not available")); 1000 else 1001 rc2 = setErrorInternal(vrc, Utf8StrFmt(tr("The HGCM call failed with error %Rrc"), vrc)); 1039 int rc2 = setProcessStatus(ProcessStatus_Error, vrc); 1002 1040 AssertRC(rc2); 1003 1041 } … … 1008 1046 1009 1047 /* Does not do locking; caller is responsible for that! */ 1010 int GuestProcess::setErrorInternal(int vrc, const Utf8Str &strMessage) 1011 { 1012 LogFlowThisFunc(("vrc=%Rrc, strMsg=%s\n", vrc, strMessage.c_str())); 1013 1014 Assert(RT_FAILURE(vrc)); 1015 Assert(!strMessage.isEmpty()); 1048 int GuestProcess::setProcessStatus(ProcessStatus_T procStatus, int procRc) 1049 { 1050 LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, procRc=%Rrc\n", 1051 mData.mStatus, procStatus, procRc)); 1016 1052 1017 1053 #ifdef DEBUG 1018 /* Do not allow overwriting an already set error. If this happens 1019 * this means we forgot some error checking/locking somewhere. */ 1020 Assert(RT_SUCCESS(mData.mRC)); 1021 Assert(mData.mErrorMsg.isEmpty()); 1054 if (procStatus == ProcessStatus_Error) 1055 { 1056 AssertMsg(RT_FAILURE(procRc), ("Guest rc must be an error (%Rrc)\n", procRc)); 1057 /* Do not allow overwriting an already set error. If this happens 1058 * this means we forgot some error checking/locking somewhere. */ 1059 AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC)); 1060 } 1061 else 1062 AssertMsg(RT_SUCCESS(procRc), ("Guest rc must not be an error (%Rrc)\n", procRc)); 1022 1063 #endif 1023 1064 1024 mData.mStatus = ProcessStatus_Error;1025 mData.mRC = vrc;1026 mData.mErrorMsg = strMessage; 1027 1028 int rc2 = signalWaiters(ProcessWaitResult_Error); 1029 LogFlowFuncLeaveRC(rc2); 1030 return rc2; 1031 } 1032 1033 HRESULT GuestProcess::setErrorExternal(void) 1034 { 1035 return RT_SUCCESS(mData.mRC) 1036 ? S_OK : setError(VBOX_E_IPRT_ERROR, "%s", mData.mErrorMsg.c_str());1037 } 1038 1039 int GuestProcess::signalWaiters(ProcessWaitResult_T enmWaitResult )1040 { 1041 LogFlowThisFunc(("enmWaitResult=%d, mWaitCount=%RU32, mWaitEvent=%p\n",1042 enmWaitResult, mData.mWaitCount, mData.mWaitEvent));1065 mData.mStatus = procStatus; 1066 mData.mRC = procRc; 1067 1068 return VINF_SUCCESS; 1069 } 1070 1071 /* static */ 1072 HRESULT GuestProcess::setErrorExternal(VirtualBoxBase *pInterface, int guestRc) 1073 { 1074 AssertPtr(pInterface); 1075 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n")); 1076 1077 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc).c_str()); 1078 } 1079 1080 int GuestProcess::signalWaiters(ProcessWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */) 1081 { 1082 LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n", 1083 enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent)); 1043 1084 1044 1085 /* Note: No write locking here -- already done in the caller. */ … … 1046 1087 int vrc = VINF_SUCCESS; 1047 1088 if (mData.mWaitEvent) 1048 vrc = mData.mWaitEvent->Signal(enmWaitResult );1089 vrc = mData.mWaitEvent->Signal(enmWaitResult, rc); 1049 1090 LogFlowFuncLeaveRC(vrc); 1050 1091 return vrc; 1051 1092 } 1052 1093 1053 int GuestProcess::startProcess( void)1094 int GuestProcess::startProcess(int *pGuestRc) 1054 1095 { 1055 1096 LogFlowThisFunc(("aCmd=%s, aTimeoutMS=%RU32, fFlags=%x\n", … … 1060 1101 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1061 1102 1062 int vrc ;1103 int vrc = VINF_SUCCESS; 1063 1104 uint32_t uContextID = 0; 1064 GuestCtrlCallback *pCallbackStart = new GuestCtrlCallback(); 1065 if (!pCallbackStart) 1066 return VERR_NO_MEMORY; 1067 1068 mData.mStatus = ProcessStatus_Starting; 1069 1070 /* Create callback and add it to the map. */ 1071 vrc = pCallbackStart->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START); 1105 1106 GuestCtrlCallback *pCallbackStart; 1107 try 1108 { 1109 pCallbackStart = new GuestCtrlCallback(); 1110 AssertPtr(pCallbackStart); 1111 } 1112 catch(std::bad_alloc &) 1113 { 1114 vrc = VERR_NO_MEMORY; 1115 } 1116 1072 1117 if (RT_SUCCESS(vrc)) 1073 vrc = callbackAdd(pCallbackStart, &uContextID); 1118 { 1119 mData.mStatus = ProcessStatus_Starting; 1120 1121 /* Create callback and add it to the map. */ 1122 vrc = pCallbackStart->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START); 1123 if (RT_SUCCESS(vrc)) 1124 vrc = callbackAdd(pCallbackStart, &uContextID); 1125 } 1074 1126 1075 1127 if (RT_SUCCESS(vrc)) … … 1175 1227 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 1176 1228 { 1177 vrc = pCallbackStart->GetResultCode(); 1178 LogFlowThisFunc(("Callback returned vrc=%Rrc\n", vrc)); 1229 int guestRc = pCallbackStart->GetResultCode(); 1230 if (pGuestRc) 1231 *pGuestRc = guestRc; 1232 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 1179 1233 } 1180 1234 else … … 1240 1294 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1241 1295 1242 int vrc = pProcess->startProcess(); 1243 if (RT_FAILURE(vrc)) 1244 { 1245 /** @todo What now? */ 1246 } 1296 int vrc = pProcess->startProcess(NULL /* Guest rc, ignored */); 1297 /* Nothing to do here anymore. */ 1247 1298 1248 1299 LogFlowFuncLeaveRC(vrc); … … 1263 1314 } 1264 1315 1265 int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestProcessWaitResult &waitRes)1316 int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc) 1266 1317 { 1267 1318 LogFlowThisFuncEnter(); … … 1269 1320 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER); 1270 1321 1271 LogFlowThisFunc(("fWaitFlags= %x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p\n",1272 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent ));1322 LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n", 1323 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc)); 1273 1324 1274 1325 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1275 1326 1276 ProcessStatus_T curStatus = mData.mStatus;1277 1278 1327 /* Did some error occur before? Then skip waiting and return. */ 1279 if (curStatus == ProcessStatus_Error) 1280 { 1281 waitRes.mResult = ProcessWaitResult_Error; 1282 return VINF_SUCCESS; 1283 } 1284 1285 waitRes.mResult = ProcessWaitResult_None; 1286 waitRes.mRC = VINF_SUCCESS; 1287 1328 if (mData.mStatus == ProcessStatus_Error) 1329 { 1330 waitResult = ProcessWaitResult_Error; 1331 AssertMsg(RT_FAILURE(mData.mRC), ("No error rc (%Rrc) set when guest process indicated an error\n", mData.mRC)); 1332 if (pGuestRc) 1333 *pGuestRc = mData.mRC; /* Return last set error. */ 1334 return VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ 1335 } 1336 1337 waitResult = ProcessWaitResult_None; 1288 1338 if ( (fWaitFlags & ProcessWaitForFlag_Terminate) 1289 1339 || (fWaitFlags & ProcessWaitForFlag_StdIn) … … 1297 1347 case ProcessStatus_TerminatedAbnormally: 1298 1348 case ProcessStatus_Down: 1299 waitRes.mResult = ProcessWaitResult_Terminate; 1300 waitRes.mRC = mData.mRC; 1349 waitResult = ProcessWaitResult_Terminate; 1301 1350 break; 1302 1351 1303 1352 case ProcessStatus_TimedOutKilled: 1304 1353 case ProcessStatus_TimedOutAbnormally: 1305 waitRes.mResult = ProcessWaitResult_Timeout; 1306 waitRes.mRC = mData.mRC; 1354 waitResult = ProcessWaitResult_Timeout; 1307 1355 break; 1308 1356 1309 1357 case ProcessStatus_Error: 1310 waitRes.mResult = ProcessWaitResult_Error; 1311 waitRes.mRC = mData.mRC; 1358 /* Handled above. */ 1312 1359 break; 1313 1360 1314 1361 case ProcessStatus_Started: 1315 1362 { 1316 /* Filter out waits which are *not* supported using1317 * older guest control Guest Additions. */1318 if (mData.mParent->getProtocolVersion() < 2)1319 {1320 /* We don't support waiting for stdin, out + err,1321 * just skip waiting then. */1322 if ( (fWaitFlags & ProcessWaitForFlag_StdIn)1323 || (fWaitFlags & ProcessWaitForFlag_StdOut)1324 || (fWaitFlags & ProcessWaitForFlag_StdErr))1325 {1326 /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */1327 waitRes.mResult = ProcessWaitResult_WaitFlagNotSupported;1328 }1329 }1330 1331 1363 /* 1332 1364 * If ProcessCreateFlag_WaitForProcessStartOnly was specified on process creation the … … 1335 1367 */ 1336 1368 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly) 1337 waitRes .mResult = ProcessWaitResult_Start;1369 waitResult = ProcessWaitResult_Start; 1338 1370 break; 1339 1371 } … … 1360 1392 case ProcessStatus_TerminatedAbnormally: 1361 1393 case ProcessStatus_Down: 1362 waitRes .mResult = ProcessWaitResult_Start;1394 waitResult = ProcessWaitResult_Start; 1363 1395 break; 1364 1396 1365 1397 case ProcessStatus_Error: 1366 waitRes.mResult = ProcessWaitResult_Error; 1367 waitRes.mRC = mData.mRC; 1398 waitResult = ProcessWaitResult_Error; 1368 1399 break; 1369 1400 1370 1401 case ProcessStatus_TimedOutKilled: 1371 1402 case ProcessStatus_TimedOutAbnormally: 1372 waitRes.mResult = ProcessWaitResult_Timeout; 1373 waitRes.mRC = mData.mRC; 1403 waitResult = ProcessWaitResult_Timeout; 1374 1404 break; 1375 1405 … … 1385 1415 } 1386 1416 1387 LogFlowThisFunc(("waitResult=%ld, waitRC=%Rrc\n", waitRes.mResult, waitRes.mRC)); 1388 1389 /* No waiting needed? Return immediately. */ 1390 if (waitRes.mResult != ProcessWaitResult_None) 1391 return VINF_SUCCESS; 1417 /* Filter out waits which are *not* supported using 1418 * older guest control Guest Additions. */ 1419 if (mData.mParent->getProtocolVersion() < 2) 1420 { 1421 if ( waitResult == ProcessWaitResult_None 1422 /* We don't support waiting for stdin, out + err, 1423 * just skip waiting then. */ 1424 && ( (fWaitFlags & ProcessWaitForFlag_StdIn) 1425 || (fWaitFlags & ProcessWaitForFlag_StdOut) 1426 || (fWaitFlags & ProcessWaitForFlag_StdErr) 1427 ) 1428 ) 1429 { 1430 /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */ 1431 waitResult = ProcessWaitResult_WaitFlagNotSupported; 1432 } 1433 } 1434 1435 LogFlowThisFunc(("procStatus=%ld, procRc=%Rrc, waitResult=%ld\n", 1436 mData.mStatus, mData.mRC, waitResult)); 1437 1438 /* No waiting needed? Return immediately using the last set error. */ 1439 if (waitResult != ProcessWaitResult_None) 1440 { 1441 if (pGuestRc) 1442 *pGuestRc = mData.mRC; /* Return last set error (if any). */ 1443 return RT_SUCCESS(mData.mRC) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ 1444 } 1392 1445 1393 1446 if (mData.mWaitCount > 0) … … 1395 1448 mData.mWaitCount++; 1396 1449 1397 Assert(mData.mWaitEvent == NULL); 1398 mData.mWaitEvent = new GuestProcessEvent(fWaitFlags); 1399 AssertPtrReturn(mData.mWaitEvent, VERR_NO_MEMORY); 1400 1401 alock.release(); /* Release lock before waiting. */ 1402 1403 int vrc = mData.mWaitEvent->Wait(uTimeoutMS); 1450 int vrc = VINF_SUCCESS; 1451 try 1452 { 1453 Assert(mData.mWaitEvent == NULL); 1454 mData.mWaitEvent = new GuestProcessWaitEvent(fWaitFlags); 1455 } 1456 catch(std::bad_alloc &) 1457 { 1458 vrc = VERR_NO_MEMORY; 1459 } 1460 1404 1461 if (RT_SUCCESS(vrc)) 1405 1462 { 1406 waitRes = mData.mWaitEvent->GetResult(); 1407 } 1408 else if (vrc == VERR_TIMEOUT) 1409 { 1410 waitRes.mRC = VINF_SUCCESS; 1411 waitRes.mResult = ProcessWaitResult_Timeout; 1412 1413 vrc = VINF_SUCCESS; 1414 } 1415 1416 alock.acquire(); /* Get the lock again. */ 1417 1418 /* Note: The caller always is responsible of deleting the 1419 * stuff it created before. See close() for more information. */ 1420 delete mData.mWaitEvent; 1421 mData.mWaitEvent = NULL; 1422 1463 GuestProcessWaitEvent *pEvent = mData.mWaitEvent; 1464 AssertPtr(pEvent); 1465 1466 alock.release(); /* Release lock before waiting. */ 1467 1468 vrc = pEvent->Wait(uTimeoutMS); 1469 if (RT_SUCCESS(vrc)) 1470 { 1471 waitResult = pEvent->GetWaitResult(); 1472 int waitRc = pEvent->GetWaitRc(); 1473 1474 LogFlowThisFunc(("Waiting event returned rc=%Rrc\n", waitRc)); 1475 1476 if (pGuestRc) 1477 *pGuestRc = waitRc; 1478 1479 vrc = RT_SUCCESS(waitRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ 1480 } 1481 1482 alock.acquire(); /* Get the lock again. */ 1483 1484 /* Note: The caller always is responsible of deleting the 1485 * stuff it created before. See close() for more information. */ 1486 delete mData.mWaitEvent; 1487 mData.mWaitEvent = NULL; 1488 } 1489 1490 Assert(mData.mWaitCount); 1423 1491 mData.mWaitCount--; 1424 1492 … … 1427 1495 } 1428 1496 1429 int GuestProcess::waitForStart(uint32_t uTimeoutMS) 1430 { 1431 LogFlowThisFunc(("uTimeoutMS=%RU32\n", uTimeoutMS)); 1497 int GuestProcess::writeData(uint32_t uHandle, uint32_t uFlags, 1498 void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc) 1499 { 1500 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p, pGuestRc=%p\n", 1501 mData.mPID, uHandle, uFlags, pvData, cbData, uTimeoutMS, puWritten, pGuestRc)); 1502 /* All is optional. There can be 0 byte writes. */ 1503 1504 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1505 1506 if (mData.mStatus != ProcessStatus_Started) 1507 { 1508 if (puWritten) 1509 *puWritten = 0; 1510 if (pGuestRc) 1511 *pGuestRc = VINF_SUCCESS; 1512 return VINF_SUCCESS; /* Not available for writing (anymore). */ 1513 } 1432 1514 1433 1515 int vrc = VINF_SUCCESS; 1434 1516 1435 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 1436 if (mData.mStatus != ProcessStatus_Started) 1437 { 1438 alock.release(); 1439 1440 GuestProcessWaitResult waitRes; 1441 vrc = waitFor(ProcessWaitForFlag_Start, uTimeoutMS, waitRes); 1442 if ( RT_FAILURE(vrc) 1443 || waitRes.mResult == ProcessWaitResult_Start) 1444 { 1445 if (RT_SUCCESS(vrc)) 1446 vrc = waitRes.mRC; 1447 } 1448 /** @todo More error handling needed. */ 1449 } 1450 1451 LogFlowFuncLeaveRC(vrc); 1452 return vrc; 1453 } 1454 1455 int GuestProcess::writeData(uint32_t uHandle, uint32_t uFlags, 1456 void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten) 1457 { 1458 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p\n", 1459 mData.mPID, uHandle, uFlags, pvData, cbData, uTimeoutMS, puWritten)); 1460 /* All is optional. There can be 0 byte writes. */ 1461 1462 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1463 1464 if (mData.mStatus != ProcessStatus_Started) 1465 return VINF_SUCCESS; /* Not available for writing (anymore). */ 1466 1517 GuestCtrlCallback *pCallbackWrite; 1518 try 1519 { 1520 pCallbackWrite = new GuestCtrlCallback(); 1521 AssertPtr(pCallbackWrite); 1522 } 1523 catch(std::bad_alloc &) 1524 { 1525 vrc = VERR_NO_MEMORY; 1526 } 1527 1528 /* Create callback and add it to the map. */ 1467 1529 uint32_t uContextID = 0; 1468 GuestCtrlCallback *pCallbackWrite = new GuestCtrlCallback();1469 if (!pCallbackWrite)1470 return VERR_NO_MEMORY;1471 1472 /* Create callback and add it to the map. */1473 int vrc = pCallbackWrite->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS);1474 1530 if (RT_SUCCESS(vrc)) 1475 vrc = callbackAdd(pCallbackWrite, &uContextID); 1531 { 1532 vrc = pCallbackWrite->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS); 1533 if (RT_SUCCESS(vrc)) 1534 vrc = callbackAdd(pCallbackWrite, &uContextID); 1535 } 1476 1536 1477 1537 alock.release(); /* Drop the write lock again. */ … … 1501 1561 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 1502 1562 { 1503 vrc = pCallbackWrite->GetResultCode();1504 LogFlowThisFunc(("Callback returned vrc=%Rrc, cbData=%RU32\n", vrc, pCallbackWrite->GetDataSize()));1505 1506 if (RT_SUCCESS( vrc))1563 int guestRc = pCallbackWrite->GetResultCode(); 1564 LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", guestRc, pCallbackWrite->GetDataSize())); 1565 1566 if (RT_SUCCESS(guestRc)) 1507 1567 { 1508 1568 Assert(pCallbackWrite->GetDataSize() == sizeof(CALLBACKDATAEXECINSTATUS)); … … 1536 1596 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); 1537 1597 1598 if (pGuestRc) 1599 *pGuestRc = guestRc; 1600 1538 1601 if (puWritten) 1539 1602 *puWritten = cbWritten; 1603 1604 if (RT_FAILURE(guestRc)) 1605 vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ 1540 1606 } 1541 1607 } 1542 else1543 vrc = VERR_TIMEOUT;1544 1608 } 1545 1609 … … 1573 1637 Assert(data.size() >= aToRead); 1574 1638 1575 size_t cbRead; 1576 int vrc = readData(aHandle, aToRead, aTimeoutMS, data.raw(), aToRead, &cbRead); 1639 HRESULT hr = S_OK; 1640 1641 size_t cbRead; int guestRc; 1642 int vrc = readData(aHandle, aToRead, aTimeoutMS, data.raw(), aToRead, &cbRead, &guestRc); 1577 1643 if (RT_SUCCESS(vrc)) 1578 1644 { … … 1581 1647 data.detachTo(ComSafeArrayOutArg(aData)); 1582 1648 } 1583 1584 LogFlowThisFunc(("readData returned %Rrc, cbRead=%RU64\n", vrc, cbRead)); 1585 1586 /** @todo Do setError() here. */ 1587 HRESULT hr = RT_SUCCESS(vrc) ? S_OK : VBOX_E_IPRT_ERROR; 1649 else 1650 { 1651 switch (vrc) 1652 { 1653 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 1654 hr = GuestProcess::setErrorExternal(this, guestRc); 1655 break; 1656 1657 default: 1658 hr = setError(VBOX_E_IPRT_ERROR, 1659 tr("Reading from process \"%s\" (PID %RU32) failed: %Rrc"), 1660 mData.mProcess.mCommand.c_str(), mData.mPID, vrc); 1661 break; 1662 } 1663 } 1664 1665 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64\n", vrc, cbRead)); 1666 1588 1667 LogFlowFuncLeaveRC(vrc); 1589 1590 1668 return hr; 1591 1669 #endif /* VBOX_WITH_GUEST_CONTROL */ … … 1657 1735 * Note: Do not hold any locks here while waiting! 1658 1736 */ 1659 HRESULT hr ;1660 1661 GuestProcessWaitResult waitRes;1662 int vrc = waitFor(aWaitFlags, aTimeoutMS, waitRes );1737 HRESULT hr = S_OK; 1738 1739 int guestRc; ProcessWaitResult_T waitResult; 1740 int vrc = waitFor(aWaitFlags, aTimeoutMS, waitResult, &guestRc); 1663 1741 if (RT_SUCCESS(vrc)) 1664 1742 { 1665 *aReason = waitRes.mResult; 1666 hr = setErrorExternal(); 1743 *aReason = waitResult; 1667 1744 } 1668 1745 else 1669 1746 { 1670 hr = setError(VBOX_E_IPRT_ERROR, 1671 tr("Waiting for process \"%s\" (PID %RU32) failed with vrc=%Rrc"), 1672 mData.mProcess.mCommand.c_str(), mData.mPID, vrc); 1673 } 1747 switch (vrc) 1748 { 1749 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 1750 hr = GuestProcess::setErrorExternal(this, guestRc); 1751 break; 1752 1753 default: 1754 hr = setError(VBOX_E_IPRT_ERROR, 1755 tr("Waiting for process \"%s\" (PID %RU32) failed: %Rrc"), 1756 mData.mProcess.mCommand.c_str(), mData.mPID, vrc); 1757 break; 1758 } 1759 } 1760 1674 1761 LogFlowFuncLeaveRC(vrc); 1675 1762 return hr; … … 1716 1803 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1717 1804 1718 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); 1719 int vrc = writeData(aHandle, aFlags, data.raw(), data.size(), aTimeoutMS, (uint32_t*)aWritten); 1720 1721 LogFlowThisFunc(("writeData returned %Rrc, aWritten=%RU32\n", vrc, aWritten)); 1722 1723 /** @todo Do setError() here. */ 1724 HRESULT hr = RT_SUCCESS(vrc) ? S_OK : VBOX_E_IPRT_ERROR; 1805 HRESULT hr = S_OK; 1806 1807 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); int guestRc; 1808 int vrc = writeData(aHandle, aFlags, data.raw(), data.size(), aTimeoutMS, (uint32_t*)aWritten, &guestRc); 1809 if (RT_FAILURE(vrc)) 1810 { 1811 switch (vrc) 1812 { 1813 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 1814 hr = GuestProcess::setErrorExternal(this, guestRc); 1815 break; 1816 1817 default: 1818 hr = setError(VBOX_E_IPRT_ERROR, 1819 tr("Writing to process \"%s\" (PID %RU32) failed: %Rrc"), 1820 mData.mProcess.mCommand.c_str(), mData.mPID, vrc); 1821 break; 1822 } 1823 } 1824 1825 LogFlowThisFunc(("rc=%Rrc, aWritten=%RU32\n", vrc, aWritten)); 1826 1725 1827 LogFlowFuncLeaveRC(vrc); 1726 1727 1828 return hr; 1728 1829 #endif /* VBOX_WITH_GUEST_CONTROL */ … … 1754 1855 } 1755 1856 1857 /////////////////////////////////////////////////////////////////////////////// 1858 1859 GuestProcessTool::GuestProcessTool(void) 1860 : pSession(NULL) 1861 { 1862 } 1863 1864 GuestProcessTool::~GuestProcessTool(void) 1865 { 1866 Terminate(); 1867 } 1868 1869 int GuestProcessTool::Init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo, 1870 bool fAsync, int *pGuestRc) 1871 { 1872 LogFlowThisFunc(("pGuestSession=%p, szCmd=%s, fAsync=%RTbool\n", 1873 pGuestSession, startupInfo.mCommand.c_str(), fAsync)); 1874 1875 AssertPtrReturn(pGuestSession, VERR_INVALID_POINTER); 1876 1877 pSession = pGuestSession; 1878 mStartupInfo = startupInfo; 1879 1880 /* Make sure the process is hidden. */ 1881 mStartupInfo.mFlags |= ProcessCreateFlag_Hidden; 1882 1883 int vrc = pSession->processCreateExInteral(mStartupInfo, pProcess); 1884 if (RT_SUCCESS(vrc)) 1885 vrc = fAsync ? pProcess->startProcessAsync() : pProcess->startProcess(pGuestRc); 1886 1887 if ( !fAsync 1888 && ( pGuestRc 1889 && RT_FAILURE(*pGuestRc) 1890 ) 1891 ) 1892 { 1893 vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ 1894 } 1895 1896 LogFlowFuncLeaveRC(vrc); 1897 return vrc; 1898 } 1899 1900 int GuestProcessTool::GetCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock &strmBlock) 1901 { 1902 const GuestProcessStream *pStream = NULL; 1903 if (uHandle == OUTPUT_HANDLE_ID_STDOUT) 1904 pStream = &mStdOut; 1905 else if (uHandle == OUTPUT_HANDLE_ID_STDERR) 1906 pStream = &mStdErr; 1907 1908 if (!pStream) 1909 return VERR_INVALID_PARAMETER; 1910 1911 int vrc; 1912 do 1913 { 1914 /* Try parsing the data to see if the current block is complete. */ 1915 vrc = mStdOut.ParseBlock(strmBlock); 1916 if (strmBlock.GetCount()) 1917 break; 1918 } while (RT_SUCCESS(vrc)); 1919 1920 LogFlowThisFunc(("rc=%Rrc, %RU64 pairs\n", 1921 vrc, strmBlock.GetCount())); 1922 return vrc; 1923 } 1924 1925 bool GuestProcessTool::IsRunning(void) 1926 { 1927 AssertReturn(!pProcess.isNull(), true); 1928 1929 ProcessStatus_T procStatus = ProcessStatus_Undefined; 1930 HRESULT hr = pProcess->COMGETTER(Status(&procStatus)); 1931 Assert(SUCCEEDED(hr)); 1932 1933 if ( procStatus != ProcessStatus_Started 1934 && procStatus != ProcessStatus_Paused 1935 && procStatus != ProcessStatus_Terminating) 1936 { 1937 return false; 1938 } 1939 1940 return true; 1941 } 1942 1943 int GuestProcessTool::TerminatedOk(LONG *pExitCode) 1944 { 1945 Assert(!pProcess.isNull()); 1946 /* pExitCode is optional. */ 1947 1948 if (!IsRunning()) 1949 { 1950 LONG exitCode; 1951 HRESULT hr = pProcess->COMGETTER(ExitCode(&exitCode)); 1952 Assert(SUCCEEDED(hr)); 1953 1954 if (pExitCode) 1955 *pExitCode = exitCode; 1956 1957 if (exitCode != 0) 1958 return VERR_NOT_EQUAL; /** @todo Special guest control rc needed! */ 1959 return VINF_SUCCESS; 1960 } 1961 1962 return VERR_INVALID_STATE; /** @todo Special guest control rc needed! */ 1963 } 1964 1965 int GuestProcessTool::Wait(uint32_t fFlags, int *pGuestRc) 1966 { 1967 return WaitEx(fFlags, NULL /* pStreamBlock */, pGuestRc); 1968 } 1969 1970 int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBlock, int *pGuestRc) 1971 { 1972 LogFlowThisFunc(("pSession=%p, pProcess=%p, fFlags=0x%x, pStreamBlock=%p, pGuestRc=%p\n", 1973 pSession, pProcess, fFlags, pStreamBlock, pGuestRc)); 1974 1975 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1976 Assert(!pProcess.isNull()); 1977 /* Other parameters are optional. */ 1978 1979 /* Can we parse the next block without waiting? */ 1980 int vrc; 1981 if (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK) 1982 { 1983 AssertPtr(pStreamBlock); 1984 vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock); 1985 if (RT_SUCCESS(vrc)) 1986 return vrc; 1987 } 1988 1989 /* Do the waiting. */ 1990 uint32_t fWaitFlags = ProcessWaitForFlag_Terminate; 1991 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdOut) 1992 fWaitFlags |= ProcessWaitForFlag_StdOut; 1993 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdErr) 1994 fWaitFlags |= ProcessWaitForFlag_StdErr; 1995 1996 LogFlowFunc(("waitFlags=0x%x\n", fWaitFlags)); 1997 1998 /** @todo Decrease timeout. */ 1999 uint32_t uTimeoutMS = mStartupInfo.mTimeoutMS; 2000 2001 int guestRc; 2002 bool fDone = false; 2003 2004 BYTE byBuf[_64K]; 2005 size_t cbRead; 2006 2007 bool fHandleStdOut = false; 2008 bool fHandleStdErr = false; 2009 2010 ProcessWaitResult_T waitRes; 2011 do 2012 { 2013 vrc = pProcess->waitFor(fWaitFlags, 2014 uTimeoutMS, waitRes, &guestRc); 2015 if (RT_FAILURE(vrc)) 2016 break; 2017 2018 switch (waitRes) 2019 { 2020 case ProcessWaitResult_StdOut: 2021 fHandleStdOut = true; 2022 break; 2023 2024 case ProcessWaitResult_StdErr: 2025 fHandleStdErr = true; 2026 break; 2027 2028 case ProcessWaitResult_WaitFlagNotSupported: 2029 if (fWaitFlags & ProcessWaitForFlag_StdOut) 2030 fHandleStdOut = true; 2031 if (fWaitFlags & ProcessWaitForFlag_StdErr) 2032 fHandleStdErr = true; 2033 /* Since waiting for stdout / stderr is not supported by the guest, 2034 * wait a bit to not hog the CPU too much when polling for data. */ 2035 RTThreadSleep(1); /* Optional, don't check rc. */ 2036 break; 2037 2038 case ProcessWaitResult_Error: 2039 case ProcessWaitResult_Terminate: 2040 fDone = true; 2041 break; 2042 2043 default: 2044 AssertMsgFailed(("Unhandled process wait result %ld\n", waitRes)); 2045 fDone = true; 2046 break; 2047 } 2048 2049 if (fHandleStdOut) 2050 { 2051 vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf), 2052 uTimeoutMS, byBuf, sizeof(byBuf), 2053 &cbRead, &guestRc); 2054 if (RT_FAILURE(vrc)) 2055 break; 2056 2057 if (cbRead) 2058 { 2059 LogFlowThisFunc(("Received %RU64 bytes from stdout\n", cbRead)); 2060 vrc = mStdOut.AddData(byBuf, cbRead); 2061 2062 if ( RT_SUCCESS(vrc) 2063 && (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK)) 2064 { 2065 AssertPtr(pStreamBlock); 2066 vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock); 2067 if (RT_SUCCESS(vrc)) 2068 fDone = true; 2069 } 2070 } 2071 2072 fHandleStdOut = false; 2073 } 2074 2075 if (fHandleStdErr) 2076 { 2077 vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDERR, sizeof(byBuf), 2078 uTimeoutMS, byBuf, sizeof(byBuf), 2079 &cbRead, &guestRc); 2080 if (RT_FAILURE(vrc)) 2081 break; 2082 2083 if (cbRead) 2084 { 2085 LogFlowThisFunc(("Received %RU64 bytes from stderr\n", cbRead)); 2086 vrc = mStdErr.AddData(byBuf, cbRead); 2087 } 2088 2089 fHandleStdErr = false; 2090 } 2091 2092 } while (!fDone && RT_SUCCESS(vrc)); 2093 2094 LogFlowThisFunc(("Loop ended with rc=%Rrc, guestRc=%Rrc, waitRes=%ld\n", 2095 vrc, guestRc, waitRes)); 2096 if (pGuestRc) 2097 *pGuestRc = guestRc; 2098 2099 LogFlowFuncLeaveRC(vrc); 2100 return vrc; 2101 } 2102 2103 void GuestProcessTool::Terminate(void) 2104 { 2105 LogFlowThisFuncEnter(); 2106 2107 if (!pProcess.isNull()) 2108 { 2109 Assert(pSession); 2110 int rc2 = pSession->processRemoveFromList(pProcess); 2111 AssertRC(rc2); 2112 2113 pProcess.setNull(); 2114 } 2115 2116 LogFlowThisFuncLeave(); 2117 } 2118 -
trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
r42928 r43162 426 426 Assert(mData.mDirectories.size()); 427 427 LogFlowFunc(("Removing directory \"%s\" (Session: %RU32) (now total %ld directories)\n", 428 Utf8Str(strName).c_str(), mData.m NumObjects- 1));428 Utf8Str(strName).c_str(), mData.mId, mData.mDirectories.size() - 1)); 429 429 430 430 mData.mDirectories.erase(itDirs); … … 436 436 } 437 437 438 int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags )438 int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags, int *pGuestRc) 439 439 { 440 440 LogFlowThisFunc(("strPath=%s, uMode=%x, uFlags=%x\n", … … 442 442 443 443 GuestProcessStartupInfo procInfo; 444 procInfo.mName = Utf8StrFmt(tr("Creating directory \"%s\"", strPath.c_str())); 445 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKDIR); 446 procInfo.mFlags = ProcessCreateFlag_Hidden; 447 448 int rc = VINF_SUCCESS; 444 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKDIR); 445 procInfo.mFlags = ProcessCreateFlag_Hidden; 446 447 int vrc = VINF_SUCCESS; 449 448 450 449 /* Construct arguments. */ … … 461 460 } 462 461 else 463 rc = VERR_INVALID_PARAMETER;462 vrc = VERR_BUFFER_OVERFLOW; 464 463 } 465 464 procInfo.mArguments.push_back(strPath); /* The directory we want to create. */ 466 465 467 ComObjPtr<GuestProcess> pProcess; 468 rc = processCreateExInteral(procInfo, pProcess); 469 if (RT_SUCCESS(rc)) 470 rc = pProcess->startProcess(); 471 if (RT_SUCCESS(rc)) 472 { 473 GuestProcessWaitResult waitRes; 474 rc = pProcess->waitFor(ProcessWaitForFlag_Terminate, 30 * 1000 /* Timeout */, waitRes); 475 if (RT_SUCCESS(rc)) 476 { 477 ProcessStatus_T procStatus; 478 HRESULT hr = pProcess->COMGETTER(Status)(&procStatus); 479 ComAssertComRC(hr); 480 if (procStatus == ProcessStatus_TerminatedNormally) 481 { 482 LONG lExitCode; 483 pProcess->COMGETTER(ExitCode)(&lExitCode); 484 if (lExitCode != 0) 485 return VERR_CANT_CREATE; 486 } 487 else 488 rc = VERR_BROKEN_PIPE; /** @todo Find a better rc. */ 489 } 490 } 491 492 LogFlowFuncLeaveRC(rc); 493 return rc; 494 } 495 496 int GuestSession::directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData) 466 int guestRc; 467 if (RT_SUCCESS(vrc)) 468 { 469 GuestProcessTool procTool; 470 vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc); 471 if (RT_SUCCESS(vrc)) 472 { 473 if (RT_SUCCESS(guestRc)) 474 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc); 475 } 476 477 if (RT_SUCCESS(vrc)) 478 { 479 if (RT_SUCCESS(guestRc)) 480 guestRc = procTool.TerminatedOk(NULL /* Exit code */); 481 } 482 483 if (pGuestRc) 484 *pGuestRc = guestRc; 485 } 486 487 LogFlowFuncLeaveRC(vrc); 488 if (RT_FAILURE(vrc)) 489 return vrc; 490 return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ 491 } 492 493 int GuestSession::directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc) 497 494 { 498 495 LogFlowThisFunc(("strPath=%s\n", strPath.c_str())); 499 496 500 int rc = fsQueryInfoInternal(strPath, objData); 501 if (RT_SUCCESS(rc)) 502 { 503 rc = objData.mType == FsObjType_Directory 504 ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY; 505 } 506 507 LogFlowFuncLeaveRC(rc); 508 return rc; 509 } 510 511 int GuestSession::objectCreateTempInternal(Utf8Str strTemplate, 512 Utf8Str strPath, 513 bool fDirectory, 514 Utf8Str &strName, int *prc) 497 int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc); 498 if (RT_SUCCESS(vrc)) 499 { 500 vrc = objData.mType == FsObjType_Directory 501 ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY; 502 } 503 504 LogFlowFuncLeaveRC(vrc); 505 return vrc; 506 } 507 508 int GuestSession::objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath, 509 bool fDirectory, const Utf8Str &strName, int *pGuestRc) 515 510 { 516 511 GuestProcessStartupInfo procInfo; 517 GuestProcessStream streamOut;518 ComObjPtr<GuestProcess> pProcess;519 int rc = VINF_SUCCESS;520 521 if (fDirectory)522 procInfo.mName = Utf8StrFmt(tr("Creating temporary directory from template \"%s\"",523 strTemplate.c_str()));524 else525 procInfo.mName = Utf8StrFmt(tr("Creating temporary file from template \"%s\"",526 strTemplate.c_str()));527 512 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKTEMP); 528 procInfo.mFlags = ProcessCreateFlag_Hidden 529 | ProcessCreateFlag_WaitForStdOut; 530 /* Construct arguments. */ 513 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; 531 514 procInfo.mArguments.push_back(Utf8Str("--machinereadable")); 532 515 if (fDirectory) 533 516 procInfo.mArguments.push_back(Utf8Str("-d")); 534 if (strPath.length()) 517 if (strPath.length()) /* Otherwise use /tmp or equivalent. */ 535 518 { 536 519 procInfo.mArguments.push_back(Utf8Str("-t")); … … 539 522 procInfo.mArguments.push_back(strTemplate); 540 523 541 rc = processCreateExInteral(procInfo, pProcess); 542 if (RT_SUCCESS(rc)) 543 rc = pProcess->startProcess(); 544 if (RT_SUCCESS(rc)) 545 { 546 GuestProcessWaitResult waitRes; 547 BYTE byBuf[_64K]; 548 size_t cbRead; 549 550 for (;;) 551 { 552 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut, 553 30 * 1000 /* Timeout */, waitRes); 554 if ( RT_FAILURE(rc) 555 || waitRes.mResult == ProcessWaitResult_Terminate 556 || waitRes.mResult == ProcessWaitResult_Error 557 || waitRes.mResult == ProcessWaitResult_Timeout) 558 { 559 break; 560 } 561 562 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf), 563 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf), 564 &cbRead); 565 if (RT_FAILURE(rc)) 566 break; 567 568 if (cbRead) 569 { 570 rc = streamOut.AddData(byBuf, cbRead); 571 if (RT_FAILURE(rc)) 572 break; 573 } 574 } 575 576 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n", 577 rc, cbRead, streamOut.GetSize())); 578 } 579 else 580 LogThisFunc(("Error while starting temporary object creation tool on guest: %Rrc\n", rc)); 581 if (RT_FAILURE(rc)) 582 LogThisFunc(("Error while running temporary object creation tool: %Rrc\n", rc)); 583 else if (!streamOut.GetSize()) 584 { 585 LogThisFunc(("No return code after creating temporary object\n")); 586 rc = VERR_NO_DATA; 587 } 588 if (RT_SUCCESS(rc)) 589 { 590 const char *pcszName; 591 int64_t i64rc; 592 GuestProcessStreamBlock streamBlock; 593 rc = streamOut.ParseBlock(streamBlock); 594 if (RT_SUCCESS(rc)) 595 { 596 pcszName = streamBlock.GetString("name"); 597 if (pcszName) 598 strName = pcszName; 599 else 600 { 601 LogThisFunc(("No name returned after creating temporary object\n")); 602 rc = VERR_NO_DATA; 603 } 604 if (RT_FAILURE(rc = streamBlock.GetInt64Ex("rc", &i64rc))) 605 LogThisFunc(("No return code after creating temporary object\n")); 606 } 607 if ( RT_SUCCESS(rc) 608 && ( i64rc == VERR_INVALID_PARAMETER 609 || i64rc == VERR_NOT_SUPPORTED)) 610 rc = (int)i64rc; 611 if (RT_SUCCESS(rc)) 612 *prc = (int)i64rc; 613 } 614 else 615 LogThisFunc(("Error while getting return code from creating temporary object: %Rrc\n", rc)); 616 return rc; 524 GuestProcessTool procTool; int guestRc; 525 int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc); 526 if (RT_SUCCESS(vrc)) 527 { 528 if (RT_SUCCESS(guestRc)) 529 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc); 530 } 531 532 if (RT_SUCCESS(vrc)) 533 { 534 if (RT_SUCCESS(guestRc)) 535 guestRc = procTool.TerminatedOk(NULL /* Exit code */); 536 } 537 538 if (pGuestRc) 539 *pGuestRc = guestRc; 540 541 if (RT_FAILURE(vrc)) 542 return vrc; 543 return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ 617 544 } 618 545 … … 630 557 return VERR_COM_UNEXPECTED; 631 558 632 int rc = pDirectory->init(this /* Parent */,633 strPath, strFilter, uFlags);634 if (RT_FAILURE( rc))635 return rc;559 int vrc = pDirectory->init(this /* Parent */, 560 strPath, strFilter, uFlags); 561 if (RT_FAILURE(vrc)) 562 return vrc; 636 563 637 564 /* Add the created directory to our vector. */ … … 641 568 strPath.c_str(), mData.mId)); 642 569 643 LogFlowFuncLeaveRC( rc);644 return rc;570 LogFlowFuncLeaveRC(vrc); 571 return vrc; 645 572 } 646 573 … … 704 631 } 705 632 706 /** 707 * Implementation of FileRemove(). Can throw an exception due to the use of 708 * Utf8Str, Utf8StrFmt and std::vector near the beginning (and others?). The 709 * caller should catch this. On success, *prc will be set to the return code 710 * of the delete operation to distinguish between API and command failure. 711 */ 712 int GuestSession::fileRemoveInternal(Utf8Str strPath, int *prc) 633 int GuestSession::fileRemoveInternal(const Utf8Str &strPath, int *pGuestRc) 713 634 { 714 635 GuestProcessStartupInfo procInfo; 715 636 GuestProcessStream streamOut; 716 int rc = VINF_SUCCESS; 717 718 AssertPtrReturn(prc, VERR_INVALID_POINTER); 719 procInfo.mName = Utf8StrFmt(tr("Removing file \"%s\"", 720 strPath.c_str())); 637 721 638 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_RM); 722 procInfo.mFlags = ProcessCreateFlag_Hidden 723 | ProcessCreateFlag_WaitForStdOut; 724 /* Construct arguments. */ 639 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; 725 640 procInfo.mArguments.push_back(Utf8Str("--machinereadable")); 726 procInfo.mArguments.push_back(strPath); /* The directory we want to create. */ 727 728 ComObjPtr<GuestProcess> pProcess; 729 rc = processCreateExInteral(procInfo, pProcess); 730 if (RT_SUCCESS(rc)) 731 rc = pProcess->startProcess(); 732 if (RT_SUCCESS(rc)) 733 { 734 GuestProcessWaitResult waitRes; 735 BYTE byBuf[_64K]; 736 size_t cbRead; 737 738 for (;;) 739 { 740 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut, 741 30 * 1000 /* Timeout */, waitRes); 742 if ( RT_FAILURE(rc) 743 || waitRes.mResult == ProcessWaitResult_Terminate 744 || waitRes.mResult == ProcessWaitResult_Error 745 || waitRes.mResult == ProcessWaitResult_Timeout) 746 { 747 break; 748 } 749 750 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf), 751 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf), 752 &cbRead); 753 if (RT_FAILURE(rc)) 754 break; 755 756 if (cbRead) 757 { 758 rc = streamOut.AddData(byBuf, cbRead); 759 if (RT_FAILURE(rc)) 760 break; 761 } 762 } 763 764 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n", 765 rc, cbRead, streamOut.GetSize())); 766 } 767 else 768 LogThisFunc(("Error starting delete tool on guest: %Rrc\n", rc)); 769 if (RT_FAILURE(rc)) 770 LogThisFunc(("Error running delete tool on guest: %Rrc\n", rc)); 771 else if (!streamOut.GetSize()) 772 { 773 LogThisFunc(("No return code after deleting file")); 774 rc = VERR_NO_DATA; 775 } 776 if (RT_SUCCESS(rc)) 777 { 778 GuestProcessStreamBlock streamBlock; 779 int64_t i64rc; 780 rc = streamOut.ParseBlock(streamBlock); 781 streamBlock.GetString("fname"); 782 rc = streamBlock.GetInt64Ex("rc", &i64rc); 783 if (RT_SUCCESS(rc)) 784 *prc = (int)i64rc; 785 } 786 else 787 Log(("Error getting return code from deleting file: %Rrc\n", rc)); 788 return rc; 641 procInfo.mArguments.push_back(strPath); /* The file we want to remove. */ 642 643 GuestProcessTool procTool; int guestRc; 644 int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc); 645 if (RT_SUCCESS(vrc)) 646 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc); 647 648 if (RT_SUCCESS(vrc)) 649 { 650 if (RT_SUCCESS(guestRc)) 651 guestRc = procTool.TerminatedOk(NULL /* Exit code */); 652 } 653 654 if (pGuestRc) 655 *pGuestRc = guestRc; 656 657 if (RT_FAILURE(vrc)) 658 return vrc; 659 return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ 789 660 } 790 661 791 662 int GuestSession::fileOpenInternal(const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition, 792 uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile )663 uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile, int *pGuestRc) 793 664 { 794 665 LogFlowThisFunc(("strPath=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%x, iOffset=%RI64\n", … … 800 671 return VERR_COM_UNEXPECTED; 801 672 802 int rc = pFile->init(this /* Parent */, 803 strPath, strOpenMode, strDisposition, uCreationMode, iOffset); 804 if (RT_FAILURE(rc)) 805 return rc; 673 int vrc = pFile->init(this /* Parent */, 674 strPath, strOpenMode, strDisposition, uCreationMode, iOffset, pGuestRc); 675 if (RT_FAILURE(vrc)) 676 return vrc; 677 /** @todo Handle guestRc. */ 806 678 807 679 /* Add the created directory to our vector. */ … … 813 685 strPath.c_str(), mData.mId, mData.mProcesses.size(), mData.mNumObjects)); 814 686 815 LogFlowFuncLeaveRC( rc);816 return rc;817 } 818 819 int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData )687 LogFlowFuncLeaveRC(vrc); 688 return vrc; 689 } 690 691 int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc) 820 692 { 821 693 LogFlowThisFunc(("strPath=%s\n", strPath.c_str())); 822 694 823 int rc = fsQueryInfoInternal(strPath, objData);824 if (RT_SUCCESS( rc))825 { 826 rc = objData.mType == FsObjType_File827 ? VINF_SUCCESS : VERR_NOT_A_FILE;828 } 829 830 LogFlowFuncLeaveRC( rc);831 return rc;832 } 833 834 int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize )695 int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc); 696 if (RT_SUCCESS(vrc)) 697 { 698 vrc = objData.mType == FsObjType_File 699 ? VINF_SUCCESS : VERR_NOT_A_FILE; 700 } 701 702 LogFlowFuncLeaveRC(vrc); 703 return vrc; 704 } 705 706 int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize, int *pGuestRc) 835 707 { 836 708 AssertPtrReturn(pllSize, VERR_INVALID_POINTER); 837 709 838 710 GuestFsObjData objData; 839 int rc = fileQueryInfoInternal(strPath, objData); 840 if (RT_SUCCESS(rc)) 841 { 842 if (objData.mType == FsObjType_File) 843 *pllSize = objData.mObjectSize; 844 else 845 rc = VERR_NOT_A_FILE; 846 } 847 848 return rc; 849 } 850 851 int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData) 711 int vrc = fileQueryInfoInternal(strPath, objData, pGuestRc); 712 if (RT_SUCCESS(vrc)) 713 *pllSize = objData.mObjectSize; 714 715 return vrc; 716 } 717 718 int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc) 852 719 { 853 720 LogFlowThisFunc(("strPath=%s\n", strPath.c_str())); … … 855 722 /** @todo Merge this with IGuestFile::queryInfo(). */ 856 723 GuestProcessStartupInfo procInfo; 857 procInfo.mName = Utf8StrFmt(tr("Querying info for \"%s\""), strPath.c_str());858 724 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT); 859 procInfo.mFlags = ProcessCreateFlag_ Hidden | ProcessCreateFlag_WaitForStdOut;725 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; 860 726 861 727 /* Construct arguments. */ … … 863 729 procInfo.mArguments.push_back(strPath); 864 730 865 GuestProcessStream streamOut; 866 867 ComObjPtr<GuestProcess> pProcess; 868 int rc = processCreateExInteral(procInfo, pProcess); 869 if (RT_SUCCESS(rc)) 870 rc = pProcess->startProcess(); 871 if (RT_SUCCESS(rc)) 872 { 873 GuestProcessWaitResult waitRes; 874 BYTE byBuf[_64K]; 875 size_t cbRead = 0; 876 877 /** @todo Merge with GuestDirectory::read. */ 878 for (;;) 879 { 880 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut, 881 30 * 1000 /* Timeout */, waitRes); 882 if ( RT_FAILURE(rc) 883 || waitRes.mResult == ProcessWaitResult_Terminate 884 || waitRes.mResult == ProcessWaitResult_Error 885 || waitRes.mResult == ProcessWaitResult_Timeout) 886 { 887 break; 888 } 889 890 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf), 891 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf), 892 &cbRead); 893 if (RT_FAILURE(rc)) 894 break; 895 896 if (cbRead) 897 { 898 rc = streamOut.AddData(byBuf, cbRead); 899 if (RT_FAILURE(rc)) 900 break; 901 } 902 } 903 904 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64, cbStreamOut=%RU32\n", 905 rc, cbRead, streamOut.GetSize())); 906 } 907 908 if (RT_SUCCESS(rc)) 909 { 910 GuestProcessStreamBlock streamBlock; 911 rc = streamOut.ParseBlock(streamBlock); 912 if (RT_SUCCESS(rc)) 913 { 914 rc = objData.FromStat(streamBlock); 915 } 916 else 917 AssertMsgFailed(("Parsing stream block failed: %Rrc\n", rc)); 918 } 919 920 LogFlowFuncLeaveRC(rc); 921 return rc; 731 GuestProcessTool procTool; int guestRc; 732 int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc); 733 if (RT_SUCCESS(vrc)) 734 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc); 735 if (RT_SUCCESS(vrc)) 736 { 737 guestRc = procTool.TerminatedOk(NULL /* Exit code */); 738 if (RT_SUCCESS(guestRc)) 739 { 740 GuestProcessStreamBlock curBlock; 741 vrc = procTool.GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, curBlock); 742 /** @todo Check for more / validate blocks! */ 743 if (RT_SUCCESS(vrc)) 744 vrc = objData.FromStat(curBlock); 745 } 746 } 747 748 if (pGuestRc) 749 *pGuestRc = guestRc; 750 751 LogFlowFuncLeaveRC(vrc); 752 if (RT_FAILURE(vrc)) 753 return vrc; 754 return RT_SUCCESS(guestRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */ 922 755 } 923 756 … … 1341 1174 HRESULT hr = S_OK; 1342 1175 1343 ComObjPtr <GuestDirectory> pDirectory; 1344 int rc = directoryCreateInternal(Utf8Str(aPath), (uint32_t)aMode, fFlags );1176 ComObjPtr <GuestDirectory> pDirectory; int guestRc; 1177 int rc = directoryCreateInternal(Utf8Str(aPath), (uint32_t)aMode, fFlags, &guestRc); 1345 1178 if (RT_FAILURE(rc)) 1346 1179 { 1347 1180 switch (rc) 1348 1181 { 1182 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 1183 hr = GuestProcess::setErrorExternal(this, guestRc); 1184 break; 1185 1349 1186 case VERR_INVALID_PARAMETER: 1350 1187 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Invalid parameters given")); … … 1377 1214 1378 1215 if (RT_UNLIKELY((aTemplate) == NULL || *(aTemplate) == '\0')) 1379 return setError(E_INVALIDARG, tr("No file to remove specified")); 1380 1381 AutoCaller autoCaller(this); 1382 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1383 1384 int rc = VINF_SUCCESS; 1385 1386 try /* Can this be done without exceptions? */ 1387 { 1388 Utf8Str strName; 1389 if (RT_FAILURE(objectCreateTempInternal(Utf8Str(aTemplate), 1390 Utf8Str(aPath), 1391 true, strName, &rc))) 1392 return E_FAIL; 1393 HRESULT hrc = rc == VERR_INVALID_PARAMETER ? E_INVALIDARG 1394 : rc == VERR_NOT_SUPPORTED ? VBOX_E_NOT_SUPPORTED 1395 : RT_FAILURE(rc) ? VBOX_E_IPRT_ERROR 1396 : S_OK; 1397 if (FAILED(hrc)) 1398 return setError(hrc, tr("Temporary directory creation failed: %Rrc"), 1399 rc); 1216 return setError(E_INVALIDARG, tr("No template specified")); 1217 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0')) 1218 return setError(E_INVALIDARG, tr("No directory name specified")); 1219 CheckComArgOutPointerValid(aDirectory); 1220 1221 AutoCaller autoCaller(this); 1222 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1223 1224 HRESULT hr = S_OK; 1225 1226 Utf8Str strName; int guestRc; 1227 int rc = objectCreateTempInternal(Utf8Str(aTemplate), 1228 Utf8Str(aPath), 1229 true /* Directory */, strName, &guestRc); 1230 if (RT_SUCCESS(rc)) 1231 { 1400 1232 strName.cloneTo(aDirectory); 1401 return S_OK; 1402 } 1403 catch (...) 1404 { 1405 return E_OUTOFMEMORY; 1406 } 1233 } 1234 else 1235 { 1236 switch (rc) 1237 { 1238 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 1239 hr = GuestProcess::setErrorExternal(this, guestRc); 1240 break; 1241 1242 default: 1243 hr = setError(VBOX_E_IPRT_ERROR, tr("Temporary directory creation \"%s\" with template \"%s\" failed: %Rrc"), 1244 Utf8Str(aPath).c_str(), Utf8Str(aTemplate).c_str(), rc); 1245 break; 1246 } 1247 } 1248 1249 return hr; 1407 1250 #endif /* VBOX_WITH_GUEST_CONTROL */ 1408 1251 } … … 1424 1267 HRESULT hr = S_OK; 1425 1268 1426 GuestFsObjData objData; 1427 int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData );1269 GuestFsObjData objData; int guestRc; 1270 int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData, &guestRc); 1428 1271 if (RT_SUCCESS(rc)) 1429 1272 { … … 1434 1277 switch (rc) 1435 1278 { 1436 /** @todo Add more errors here! */ 1279 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 1280 hr = GuestProcess::setErrorExternal(this, guestRc); 1281 break; 1437 1282 1438 1283 default: 1439 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence failed: %Rrc"), rc); 1284 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence \"%s\" failed: %Rrc"), 1285 Utf8Str(aPath).c_str(), rc); 1440 1286 break; 1441 1287 } … … 1456 1302 return setError(E_INVALIDARG, tr("No directory to open specified")); 1457 1303 if (RT_UNLIKELY((aFilter) != NULL && *(aFilter) != '\0')) 1458 return setError(E_INVALIDARG, tr("Directory filters not implemented yet")); 1459 1304 return setError(E_INVALIDARG, tr("Directory filters are not implemented yet")); 1460 1305 CheckComArgOutPointerValid(aDirectory); 1461 1306 … … 1480 1325 if (RT_SUCCESS(rc)) 1481 1326 { 1482 if (aDirectory) 1483 { 1484 /* Return directory object to the caller. */ 1485 hr = pDirectory.queryInterfaceTo(aDirectory); 1486 } 1487 else 1488 { 1489 rc = directoryRemoveFromList(pDirectory); 1490 if (RT_FAILURE(rc)) 1491 hr = setError(VBOX_E_IPRT_ERROR, tr("Unable to close directory object, rc=%Rrc"), rc); 1492 } 1327 /* Return directory object to the caller. */ 1328 hr = pDirectory.queryInterfaceTo(aDirectory); 1493 1329 } 1494 1330 else … … 1497 1333 { 1498 1334 case VERR_INVALID_PARAMETER: 1499 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Invalid parameters given")); 1335 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed; invalid parameters given", 1336 Utf8Str(aPath).c_str())); 1500 1337 break; 1501 1338 1502 case VERR_BROKEN_PIPE:1503 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Unexpectedly aborted"));1504 break;1505 1506 1339 default: 1507 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: %Rrc"), rc); 1340 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed: %Rrc"), 1341 Utf8Str(aPath).c_str(),rc); 1508 1342 break; 1509 1343 } … … 1530 1364 HRESULT hr = S_OK; 1531 1365 1532 GuestFsObjData objData; 1533 int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData);1534 if (RT_SUCCESS( rc))1366 GuestFsObjData objData; int guestRc; 1367 int vrc = directoryQueryInfoInternal(Utf8Str(aPath), objData, &guestRc); 1368 if (RT_SUCCESS(vrc)) 1535 1369 { 1536 1370 if (objData.mType == FsObjType_Directory) … … 1538 1372 ComObjPtr<GuestFsObjInfo> pFsObjInfo; 1539 1373 hr = pFsObjInfo.createObject(); 1540 if (FAILED(hr)) 1541 return VERR_COM_UNEXPECTED; 1542 1543 rc = pFsObjInfo->init(objData);1544 if (RT_SUCCESS(rc))1374 if (FAILED(hr)) return hr; 1375 1376 vrc = pFsObjInfo->init(objData); 1377 if (RT_SUCCESS(vrc)) 1378 { 1545 1379 hr = pFsObjInfo.queryInterfaceTo(aInfo); 1546 } 1547 } 1548 1549 if (RT_FAILURE(rc)) 1550 { 1551 switch (rc) 1552 { 1553 /** @todo Add more errors here! */ 1380 if (FAILED(hr)) return hr; 1381 } 1382 } 1383 } 1384 1385 if (RT_FAILURE(vrc)) 1386 { 1387 switch (vrc) 1388 { 1389 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 1390 hr = GuestProcess::setErrorExternal(this, guestRc); 1391 break; 1554 1392 1555 1393 case VERR_NOT_A_DIRECTORY: 1556 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a directory")); 1394 hr = setError(VBOX_E_IPRT_ERROR, tr("Element \"%s\" exists but is not a directory", 1395 Utf8Str(aPath).c_str())); 1557 1396 break; 1558 1397 1559 1398 default: 1560 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information failed: %Rrc"), rc); 1399 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information for \"%s\" failed: %Rrc"), 1400 Utf8Str(aPath).c_str(), vrc); 1561 1401 break; 1562 1402 } … … 1737 1577 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1738 1578 1579 GuestFsObjData objData; int guestRc; 1580 int vrc = fileQueryInfoInternal(Utf8Str(aPath), objData, &guestRc); 1581 if (RT_SUCCESS(vrc)) 1582 { 1583 *aExists = TRUE; 1584 return S_OK; 1585 } 1586 1739 1587 HRESULT hr = S_OK; 1740 1588 1741 GuestFsObjData objData; 1742 int rc = fileQueryInfoInternal(Utf8Str(aPath), objData); 1743 if (RT_SUCCESS(rc)) 1744 { 1745 *aExists = objData.mType == FsObjType_File; 1746 } 1747 else 1748 { 1749 switch (rc) 1750 { 1751 /** @todo Add more errors here! */ 1752 1753 default: 1754 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file existence failed: %Rrc"), rc); 1755 break; 1756 } 1589 switch (vrc) 1590 { 1591 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 1592 hr = GuestProcess::setErrorExternal(this, guestRc); 1593 break; 1594 1595 case VERR_NOT_A_FILE: 1596 *aExists = FALSE; 1597 break; 1598 1599 default: 1600 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information for \"%s\" failed: %Rrc"), 1601 Utf8Str(aPath).c_str(), vrc); 1602 break; 1757 1603 } 1758 1604 … … 1774 1620 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1775 1621 1776 try /* Can this be done without exceptions? */ 1777 { 1778 int rc2; 1779 int rc = fileRemoveInternal(Utf8Str(aPath), &rc2); 1780 if (RT_FAILURE((rc))) 1781 return setError(E_FAIL, 1782 tr("Internal error deleting file: %Rrc"), rc); 1783 else if (RT_FAILURE((rc2))) 1784 return setError(VBOX_E_IPRT_ERROR, 1785 tr("File deletion on guest returned: %Rrc"), rc2); 1786 } 1787 catch (...) 1788 { 1789 return E_OUTOFMEMORY; 1790 } 1791 return S_OK; 1622 HRESULT hr = S_OK; 1623 1624 int guestRc; 1625 int vrc = fileRemoveInternal(Utf8Str(aPath), &guestRc); 1626 if (RT_FAILURE(vrc)) 1627 { 1628 switch (vrc) 1629 { 1630 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 1631 hr = GuestProcess::setErrorExternal(this, guestRc); 1632 break; 1633 1634 default: 1635 hr = setError(VBOX_E_IPRT_ERROR, tr("Removing file \"%s\" failed: %Rrc"), 1636 Utf8Str(aPath).c_str(), vrc); 1637 break; 1638 } 1639 } 1640 1641 return hr; 1792 1642 #endif /* VBOX_WITH_GUEST_CONTROL */ 1793 1643 } … … 1820 1670 HRESULT hr = S_OK; 1821 1671 1822 ComObjPtr <GuestFile> pFile; 1823 int rc = fileOpenInternal(Utf8Str(aPath), Utf8Str(aOpenMode), Utf8Str(aDisposition),1824 aCreationMode, aOffset, pFile);1825 if (RT_SUCCESS( rc))1672 ComObjPtr <GuestFile> pFile; int guestRc; 1673 int vrc = fileOpenInternal(Utf8Str(aPath), Utf8Str(aOpenMode), Utf8Str(aDisposition), 1674 aCreationMode, aOffset, pFile, &guestRc); 1675 if (RT_SUCCESS(vrc)) 1826 1676 { 1827 1677 /* Return directory object to the caller. */ … … 1830 1680 else 1831 1681 { 1832 switch (rc) 1833 { 1834 /** @todo Add more error info! */ 1682 switch (vrc) 1683 { 1684 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 1685 hr = GuestProcess::setErrorExternal(this, guestRc); 1686 break; 1835 1687 1836 1688 default: 1837 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc); 1838 break; 1689 hr = setError(VBOX_E_IPRT_ERROR, tr("Creating directory \"%s\" failed: %Rrc"), 1690 Utf8Str(aPath).c_str(), vrc); 1691 break; 1839 1692 } 1840 1693 } … … 1860 1713 HRESULT hr = S_OK; 1861 1714 1862 GuestFsObjData objData; 1863 int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);1864 if (RT_SUCCESS( rc))1715 GuestFsObjData objData; int guestRc; 1716 int vrc = fileQueryInfoInternal(Utf8Str(aPath), objData, &guestRc); 1717 if (RT_SUCCESS(vrc)) 1865 1718 { 1866 1719 ComObjPtr<GuestFsObjInfo> pFsObjInfo; 1867 1720 hr = pFsObjInfo.createObject(); 1868 if (FAILED(hr)) 1869 return VERR_COM_UNEXPECTED; 1870 1871 rc = pFsObjInfo->init(objData);1872 if (RT_SUCCESS(rc))1721 if (FAILED(hr)) return hr; 1722 1723 vrc = pFsObjInfo->init(objData); 1724 if (RT_SUCCESS(vrc)) 1725 { 1873 1726 hr = pFsObjInfo.queryInterfaceTo(aInfo); 1874 } 1875 1876 if (RT_FAILURE(rc)) 1877 { 1878 switch (rc) 1879 { 1880 /** @todo Add more errors here! */ 1727 if (FAILED(hr)) return hr; 1728 } 1729 } 1730 1731 if (RT_FAILURE(vrc)) 1732 { 1733 switch (vrc) 1734 { 1735 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 1736 hr = GuestProcess::setErrorExternal(this, guestRc); 1737 break; 1881 1738 1882 1739 case VERR_NOT_A_FILE: … … 1885 1742 1886 1743 default: 1887 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), rc);1744 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), vrc); 1888 1745 break; 1889 1746 } … … 1910 1767 HRESULT hr = S_OK; 1911 1768 1912 int64_t llSize; 1913 int rc = fileQuerySizeInternal(Utf8Str(aPath), &llSize);1914 if (RT_SUCCESS( rc))1769 int64_t llSize; int guestRc; 1770 int vrc = fileQuerySizeInternal(Utf8Str(aPath), &llSize, &guestRc); 1771 if (RT_SUCCESS(vrc)) 1915 1772 { 1916 1773 *aSize = llSize; … … 1918 1775 else 1919 1776 { 1920 switch (rc) 1921 { 1922 /** @todo Add more errors here! */ 1777 switch (vrc) 1778 { 1779 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 1780 hr = GuestProcess::setErrorExternal(this, guestRc); 1781 break; 1923 1782 1924 1783 default: 1925 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), rc);1784 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), vrc); 1926 1785 break; 1927 1786 } … … 1970 1829 com::SafeArray<LONG> affinity; 1971 1830 1972 HRESULT hr = ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment), 1973 ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess); 1974 return hr; 1831 return ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment), 1832 ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess); 1975 1833 #endif /* VBOX_WITH_GUEST_CONTROL */ 1976 1834 } -
trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp
r43061 r43162 50 50 * Update file flags. 51 51 */ 52 #define UPDATEFILE_FLAG_NONE RT_BIT(0)52 #define UPDATEFILE_FLAG_NONE 0 53 53 /** Copy over the file from host to the 54 54 * guest. */ 55 #define UPDATEFILE_FLAG_COPY_FROM_ISO RT_BIT( 1)55 #define UPDATEFILE_FLAG_COPY_FROM_ISO RT_BIT(0) 56 56 /** Execute file on the guest after it has 57 57 * been successfully transfered. */ … … 251 251 252 252 GuestProcessStartupInfo procInfo; 253 procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to the guest to \"%s\" (%RU64 bytes)"),254 mSource.c_str(), mDest.c_str(), mSourceSize);255 253 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_CAT); 256 254 procInfo.mFlags = ProcessCreateFlag_Hidden; … … 260 258 261 259 /* Startup process. */ 262 ComObjPtr<GuestProcess> pProcess; 260 ComObjPtr<GuestProcess> pProcess; int guestRc; 263 261 rc = pSession->processCreateExInteral(procInfo, pProcess); 264 262 if (RT_SUCCESS(rc)) 265 rc = pProcess->startProcess( );263 rc = pProcess->startProcess(&guestRc); 266 264 if (RT_FAILURE(rc)) 267 265 { 268 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 269 Utf8StrFmt(GuestSession::tr("Unable to start guest process: %Rrc"), rc)); 270 } 271 else 272 { 273 GuestProcessWaitResult waitRes; 266 switch (rc) 267 { 268 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 269 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 270 GuestProcess::guestErrorToString(guestRc)); 271 break; 272 273 default: 274 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 275 Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"), 276 mSource.c_str(), rc)); 277 break; 278 } 279 } 280 281 if (RT_SUCCESS(rc)) 282 { 283 ProcessWaitResult_T waitRes; 274 284 BYTE byBuf[_64K]; 275 285 … … 280 290 for (;;) 281 291 { 292 int guestRc; 282 293 rc = pProcess->waitFor(ProcessWaitForFlag_StdIn, 283 30 * 1000 /* Timeout */, waitRes );294 30 * 1000 /* Timeout */, waitRes, &guestRc); 284 295 if ( RT_FAILURE(rc) 285 || ( waitRes .mResult!= ProcessWaitResult_StdIn286 && waitRes .mResult!= ProcessWaitResult_WaitFlagNotSupported))296 || ( waitRes != ProcessWaitResult_StdIn 297 && waitRes != ProcessWaitResult_WaitFlagNotSupported)) 287 298 { 288 299 break; … … 291 302 /* If the guest does not support waiting for stdin, we now yield in 292 303 * order to reduce the CPU load due to busy waiting. */ 293 if (waitRes .mResult== ProcessWaitResult_WaitFlagNotSupported)294 RTThread Yield(); /* Optional, don't check rc. */304 if (waitRes == ProcessWaitResult_WaitFlagNotSupported) 305 RTThreadSleep(1); /* Optional, don't check rc. */ 295 306 296 307 size_t cbRead = 0; … … 320 331 { 321 332 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 322 Utf8StrFmt(GuestSession::tr("Seeking file \"%s\" offset %RU64 failed: %Rrc"),333 Utf8StrFmt(GuestSession::tr("Seeking file \"%s\" to offset %RU64 failed: %Rrc"), 323 334 mSource.c_str(), cbWrittenTotal, rc)); 324 335 break; … … 333 344 || (cbToRead - cbRead == 0) 334 345 /* ... or does the user want to cancel? */ 335 || ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled))) 346 || ( !mProgress.isNull() 347 && SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled))) 336 348 && fCanceled) 337 349 ) 338 350 { 351 LogFlowThisFunc(("Writing last chunk cbRead=%RU64\n", cbRead)); 339 352 fFlags |= ProcessInputFlag_EndOfFile; 340 353 } … … 344 357 rc = pProcess->writeData(0 /* StdIn */, fFlags, 345 358 byBuf, cbRead, 346 30 * 1000 /* Timeout */, &cbWritten );359 30 * 1000 /* Timeout */, &cbWritten, &guestRc); 347 360 if (RT_FAILURE(rc)) 348 361 { 349 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 350 Utf8StrFmt(GuestSession::tr("Writing to file \"%s\" (offset %RU64) failed: %Rrc"), 351 mDest.c_str(), cbWrittenTotal, rc)); 362 switch (rc) 363 { 364 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 365 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 366 GuestProcess::guestErrorToString(guestRc)); 367 break; 368 369 default: 370 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 371 Utf8StrFmt(GuestSession::tr("Writing to file \"%s\" (offset %RU64) failed: %Rrc"), 372 mDest.c_str(), cbWrittenTotal, rc)); 373 break; 374 } 375 352 376 break; 353 377 } 354 355 LogFlowThisFunc(("cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n",356 cbWritten, cbToRead - cbWritten, cbWrittenTotal + cbWritten, mSourceSize));357 378 358 379 /* Only subtract bytes reported written by the guest. */ … … 363 384 cbWrittenTotal += cbWritten; 364 385 Assert(cbWrittenTotal <= mSourceSize); 386 387 LogFlowThisFunc(("rc=%Rrc, cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n", 388 rc, cbWritten, cbToRead, cbWrittenTotal, mSourceSize)); 365 389 366 390 /* Did the user cancel the operation above? */ … … 381 405 } /* for */ 382 406 407 LogFlowThisFunc(("Copy loop ended with rc=%Rrc\n" ,rc)); 408 383 409 if ( !fCanceled 384 410 || RT_SUCCESS(rc)) … … 393 419 /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write 394 420 * to the destination -> access denied. */ 395 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, 396 Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""), 397 mSource.c_str(), mDest.c_str())); 421 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 422 Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""), 423 mSource.c_str(), mDest.c_str())); 424 rc = VERR_GENERAL_FAILURE; /* Fudge. */ 398 425 } 399 426 else if (cbWrittenTotal < mSourceSize) 400 427 { 401 428 /* If we did not copy all let the user know. */ 402 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, 403 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed (%RU64/%RU64 bytes transfered)"), 404 mSource.c_str(), cbWrittenTotal, mSourceSize)); 429 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 430 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed (%RU64/%RU64 bytes transfered)"), 431 mSource.c_str(), cbWrittenTotal, mSourceSize)); 432 rc = VERR_GENERAL_FAILURE; /* Fudge. */ 405 433 } 406 434 else 407 435 { 408 436 rc = pProcess->waitFor(ProcessWaitForFlag_Terminate, 409 30 * 1000 /* Timeout */, waitRes );437 30 * 1000 /* Timeout */, waitRes, &guestRc); 410 438 if ( RT_FAILURE(rc) 411 || waitRes .mResult!= ProcessWaitResult_Terminate)439 || waitRes != ProcessWaitResult_Terminate) 412 440 { 413 441 if (RT_FAILURE(rc)) 414 rc =setProgressErrorMsg(VBOX_E_IPRT_ERROR,415 416 442 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 443 Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed: %Rrc"), 444 mSource.c_str(), rc)); 417 445 else 418 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, 419 Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed with wait result %ld"), 420 mSource.c_str(), waitRes.mResult)); 446 { 447 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 448 Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed with wait result %ld"), 449 mSource.c_str(), waitRes)); 450 rc = VERR_GENERAL_FAILURE; /* Fudge. */ 451 } 421 452 } 422 453 … … 431 462 ) 432 463 { 433 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, 434 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed with status %ld, exit code %ld"), 435 mSource.c_str(), procStatus, exitCode)); /**@todo Add stringify methods! */ 464 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 465 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed with status %ld, exit code %ld"), 466 mSource.c_str(), procStatus, exitCode)); /**@todo Add stringify methods! */ 467 rc = VERR_GENERAL_FAILURE; /* Fudge. */ 436 468 } 437 469 } … … 508 540 ** @todo Implement guest file locking! 509 541 */ 510 GuestFsObjData objData; 511 int rc = pSession->fileQueryInfoInternal(Utf8Str(mSource), objData );542 GuestFsObjData objData; int guestRc; 543 int rc = pSession->fileQueryInfoInternal(Utf8Str(mSource), objData, &guestRc); 512 544 if (RT_FAILURE(rc)) 513 545 { … … 545 577 546 578 /* Startup process. */ 547 ComObjPtr<GuestProcess> pProcess; 579 ComObjPtr<GuestProcess> pProcess; int guestRc; 548 580 rc = pSession->processCreateExInteral(procInfo, pProcess); 549 581 if (RT_SUCCESS(rc)) 550 rc = pProcess->startProcess( );582 rc = pProcess->startProcess(&guestRc); 551 583 if (RT_FAILURE(rc)) 552 584 { 553 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 554 Utf8StrFmt(GuestSession::tr("Unable to start guest process for copying data from guest to host: %Rrc"), rc)); 585 switch (rc) 586 { 587 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 588 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 589 GuestProcess::guestErrorToString(guestRc)); 590 break; 591 592 default: 593 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 594 Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"), 595 mSource.c_str(), rc)); 596 break; 597 } 555 598 } 556 599 else 557 600 { 558 GuestProcessWaitResultwaitRes;601 ProcessWaitResult_T waitRes; 559 602 BYTE byBuf[_64K]; 560 603 … … 563 606 uint64_t cbToRead = objData.mObjectSize; 564 607 608 int guestRc; 609 565 610 for (;;) 566 611 { 567 612 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut, 568 30 * 1000 /* Timeout */, waitRes); 569 if ( waitRes.mResult == ProcessWaitResult_StdOut 570 || waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported) 613 30 * 1000 /* Timeout */, waitRes, &guestRc); 614 if (RT_FAILURE(rc)) 615 { 616 switch (rc) 617 { 618 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 619 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 620 GuestProcess::guestErrorToString(guestRc)); 621 break; 622 623 default: 624 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 625 Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"), 626 mSource.c_str(), rc)); 627 break; 628 } 629 630 break; 631 } 632 633 if ( waitRes == ProcessWaitResult_StdOut 634 || waitRes == ProcessWaitResult_WaitFlagNotSupported) 571 635 { 572 636 /* If the guest does not support waiting for stdin, we now yield in 573 637 * order to reduce the CPU load due to busy waiting. */ 574 if (waitRes .mResult== ProcessWaitResult_WaitFlagNotSupported)575 RTThread Yield(); /* Optional, don't check rc. */576 577 size_t cbRead; 638 if (waitRes == ProcessWaitResult_WaitFlagNotSupported) 639 RTThreadSleep(1); /* Optional, don't check rc. */ 640 641 size_t cbRead; int guestRc; 578 642 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf), 579 643 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf), 580 &cbRead );644 &cbRead, &guestRc); 581 645 if (RT_FAILURE(rc)) 582 646 { 583 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 584 Utf8StrFmt(GuestSession::tr("Reading from file \"%s\" (offset %RU64) failed: %Rrc"), 585 mSource.c_str(), cbWrittenTotal, rc)); 647 switch (rc) 648 { 649 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 650 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 651 GuestProcess::guestErrorToString(guestRc)); 652 break; 653 654 default: 655 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 656 Utf8StrFmt(GuestSession::tr("Reading from file \"%s\" (offset %RU64) failed: %Rrc"), 657 mSource.c_str(), cbWrittenTotal, rc)); 658 break; 659 } 660 586 661 break; 587 662 } … … 616 691 } 617 692 } 618 else if ( RT_FAILURE(rc) 619 || waitRes.mResult == ProcessWaitResult_Terminate 620 || waitRes.mResult == ProcessWaitResult_Error 621 || waitRes.mResult == ProcessWaitResult_Timeout) 693 else 622 694 { 623 if (RT_FAILURE(waitRes.mRC))624 rc = waitRes.mRC;625 695 break; 626 696 } 697 627 698 } /* for */ 628 699 629 LogFlowThisFunc(("rc=%Rrc, cbWrittenTotal=%RU64, cbSize=%RI64, cbToRead=%RU64\n",630 rc, cbWrittenTotal, objData.mObjectSize, cbToRead));700 LogFlowThisFunc(("rc=%Rrc, guestrc=%Rrc, waitRes=%ld, cbWrittenTotal=%RU64, cbSize=%RI64, cbToRead=%RU64\n", 701 rc, guestRc, waitRes, cbWrittenTotal, objData.mObjectSize, cbToRead)); 631 702 632 703 if ( !fCanceled … … 794 865 795 866 GuestFsObjData objData; 796 int64_t cbSizeOnGuest; 797 rc = pSession->fileQuerySizeInternal(strFileDest, &cbSizeOnGuest );867 int64_t cbSizeOnGuest; int guestRc; 868 rc = pSession->fileQuerySizeInternal(strFileDest, &cbSizeOnGuest, &guestRc); 798 869 if ( RT_SUCCESS(rc) 799 870 && cbSize == (uint64_t)cbSizeOnGuest) … … 811 882 } 812 883 else 813 LogFlowThisFunc(("Error copying Guest Additions installer file \"%s\": %Rrc\n", 814 strFileDest.c_str(), rc)); 884 { 885 switch (rc) 886 { 887 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 888 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 889 GuestProcess::guestErrorToString(guestRc)); 890 break; 891 892 default: 893 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 894 Utf8StrFmt(GuestSession::tr("Error while querying size for file \"%s\": %Rrc"), 895 strFileDest.c_str(), rc)); 896 break; 897 } 898 } 815 899 } 816 900 … … 829 913 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 830 914 831 ComObjPtr<GuestProcess> pProcess; 832 int rc = pSession->processCreateExInteral(procInfo, pProcess); 833 if (RT_SUCCESS(rc)) 834 rc = pProcess->startProcess(); 835 836 if (RT_SUCCESS(rc)) 837 { 838 LogRel(("Running %s ...\n", procInfo.mName.c_str())); 839 840 GuestProcessWaitResult waitRes; 841 rc = pProcess->waitFor(ProcessWaitForFlag_Terminate, 842 10 * 60 * 1000 /* 10 mins Timeout */, waitRes); 843 LogFlowThisFunc(("waitFor rc=%Rrc, waitRes=%ld\n", rc, waitRes)); 844 if (waitRes.mResult == ProcessWaitResult_Terminate) 845 { 846 ProcessStatus_T procStatus; 847 LONG exitCode; 848 if ( ( SUCCEEDED(pProcess->COMGETTER(Status(&procStatus))) 849 && procStatus != ProcessStatus_TerminatedNormally) 850 || ( SUCCEEDED(pProcess->COMGETTER(ExitCode(&exitCode))) 851 && exitCode != 0) 852 ) 853 { 915 LogRel(("Running %s ...\n", procInfo.mName.c_str())); 916 917 LONG exitCode; 918 GuestProcessTool procTool; int guestRc; 919 int vrc = procTool.Init(pSession, procInfo, false /* Async */, &guestRc); 920 if (RT_SUCCESS(vrc)) 921 { 922 if (RT_SUCCESS(guestRc)) 923 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc); 924 if (RT_SUCCESS(vrc)) 925 vrc = procTool.TerminatedOk(&exitCode); 926 } 927 928 if (RT_FAILURE(vrc)) 929 { 930 switch (vrc) 931 { 932 case VERR_NOT_EQUAL: /** @todo Special guest control rc needed! */ 854 933 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 855 Utf8StrFmt(GuestSession::tr("Running %s failed with status %ld, exit code %ld"), 856 procInfo.mName.c_str(), procStatus, exitCode)); 857 rc = VERR_GENERAL_FAILURE; /* Fudge. */ 858 } 859 else /* Yay, success! */ 860 { 861 LogFlowThisFunc(("%s successfully completed\n", procInfo.mName.c_str())); 862 } 863 } 864 else if ( procInfo.mFlags == ProcessCreateFlag_WaitForProcessStartOnly 865 && waitRes.mResult == ProcessWaitResult_Start) 866 { 867 LogFlowThisFunc(("%s successfully started\n", procInfo.mName.c_str())); 868 } 869 else 870 { 871 /** @todo Unify error handling. */ 872 if (RT_FAILURE(rc)) 873 { 934 Utf8StrFmt(GuestSession::tr("Running update file \"%s\" on guest terminated with exit code %ld"), 935 procInfo.mCommand.c_str(), exitCode)); 936 break; 937 938 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 874 939 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 875 Utf8StrFmt(GuestSession::tr("Error while waiting running %s: %Rrc"), 876 procInfo.mName.c_str(), rc)); 877 } 878 else 879 { 880 if (pProcess->errorMsg().isEmpty()) 881 { 882 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 883 Utf8StrFmt(GuestSession::tr("Running %s returned unexpectedly with status %ld"), 884 procInfo.mName.c_str(), waitRes.mResult)); 885 } 886 else 887 setProgressErrorMsg(VBOX_E_IPRT_ERROR, pProcess->errorMsg()); 888 rc = VERR_GENERAL_FAILURE; /* Fudge. */ 889 } 890 } 891 } 892 893 if (!pProcess.isNull()) 894 pProcess->uninit(); 895 896 return rc; 940 GuestProcess::guestErrorToString(vrc)); 941 break; 942 943 default: 944 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 945 Utf8StrFmt(GuestSession::tr("Error while running update file \"%s\" on guest: %Rrc"), 946 procInfo.mCommand.c_str(), vrc)); 947 break; 948 } 949 } 950 951 return vrc; 897 952 } 898 953 … … 1080 1135 rc = getGuestProperty(pGuest, "/VirtualBox/GuestAdd/Version", strAddsVer); 1081 1136 if ( RT_SUCCESS(rc) 1082 && RTStrVersionCompare(strAddsVer.c_str(), "4.2 ") >=0)1137 && RTStrVersionCompare(strAddsVer.c_str(), "4.2r80329") > 0) 1083 1138 { 1084 1139 fUseInstallDir = true; … … 1107 1162 1108 1163 /* Create the installation directory. */ 1164 int guestRc; 1109 1165 rc = pSession->directoryCreateInternal(strUpdateDir, 1110 755 /* Mode */, DirectoryCreateFlag_Parents );1166 755 /* Mode */, DirectoryCreateFlag_Parents, &guestRc); 1111 1167 if (RT_FAILURE(rc)) 1112 hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1113 Utf8StrFmt(GuestSession::tr("Error creating installation directory \"%s\" on the guest: %Rrc"), 1114 strUpdateDir.c_str(), rc)); 1168 { 1169 switch (rc) 1170 { 1171 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ 1172 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1173 GuestProcess::guestErrorToString(guestRc)); 1174 break; 1175 1176 default: 1177 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1178 Utf8StrFmt(GuestSession::tr("Error creating installation directory \"%s\" on the guest: %Rrc"), 1179 strUpdateDir.c_str(), rc)); 1180 break; 1181 } 1182 } 1115 1183 if (RT_SUCCESS(rc)) 1116 1184 rc = setProgress(10);
Note:
See TracChangeset
for help on using the changeset viewer.