Changeset 42810 in vbox
- Timestamp:
- Aug 14, 2012 2:45:11 PM (13 years ago)
- svn:sync-xref-src-repo-rev:
- 80054
- Location:
- trunk/src/VBox
- Files:
-
- 5 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r42808 r42810 807 807 } 808 808 809 #ifdef DEBUG810 if (fVerbose)811 RTPrintf("rc=%Rrc, waitResult=%ld\n", rc, waitResult);812 #endif813 809 switch (waitResult) 814 810 { … … 838 834 fCompleted = true; 839 835 break; 840 case ProcessWaitResult_Any: 841 fReadStdOut = fReadStdErr = true; 842 break; 836 case ProcessWaitResult_WaitFlagNotSupported: 837 { 838 /* The guest does not support waiting for stdout/err, so 839 * yield to reduce the CPU load due to busy waiting. */ 840 RTThreadYield(); /* Optional, don't check rc. */ 841 842 /* Try both, stdout + stderr. */ 843 fReadStdOut = fReadStdErr = true; 844 break; 845 } 843 846 default: 844 847 /* Ignore all other results, let the timeout expire */; -
trunk/src/VBox/Main/Makefile.kmk
r42551 r42810 639 639 ifdef VBOX_WITH_GUEST_CONTROL 640 640 VBoxC_SOURCES += \ 641 src-client/GuestSessionImplTasks.cpp \ 641 642 src-client/GuestCtrlPrivate.cpp \ 642 643 src-client/GuestCtrlImplTasks.cpp \ -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r42806 r42810 9035 9035 <enum 9036 9036 name="ProcessWaitResult" 9037 uuid=" 24a4d49f-a7c1-44b0-b01f-5686a316466b"9037 uuid="40719cbe-f192-4fe9-a231-6697b3c8e2b4" 9038 9038 > 9039 9039 <desc> … … 9088 9088 <desc>Data on stderr became available for reading.</desc> 9089 9089 </const> 9090 <const name=" Any"value="9">9090 <const name="WaitFlagNotSupported" value="9"> 9091 9091 <desc> 9092 9092 A waiting flag specified in the <link to="IProcess::waitFor"/> call -
trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
r42787 r42810 1283 1283 || (fWaitFlags & ProcessWaitForFlag_StdErr)) 1284 1284 { 1285 /* Use _ Anybecause we don't know what to tell the caller. */1286 waitRes.mResult = ProcessWaitResult_ Any;1285 /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */ 1286 waitRes.mResult = ProcessWaitResult_WaitFlagNotSupported; 1287 1287 } 1288 1288 } … … 1384 1384 vrc = waitFor(ProcessWaitForFlag_Start, uTimeoutMS, waitRes); 1385 1385 if ( RT_FAILURE(vrc) 1386 || ( waitRes.mResult == ProcessWaitResult_Start 1387 && waitRes.mResult == ProcessWaitResult_Any 1388 ) 1389 ) 1386 || waitRes.mResult == ProcessWaitResult_Start) 1390 1387 { 1391 1388 if (RT_SUCCESS(vrc)) 1392 1389 vrc = waitRes.mRC; 1393 1390 } 1391 /** @todo More error handling needed. */ 1394 1392 } 1395 1393 -
trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
r42808 r42810 63 63 BaseFinalRelease(); 64 64 LogFlowThisFuncLeave(); 65 }66 67 // session task classes68 /////////////////////////////////////////////////////////////////////////////69 70 GuestSessionTask::GuestSessionTask(GuestSession *pSession)71 {72 mSession = pSession;73 }74 75 GuestSessionTask::~GuestSessionTask(void)76 {77 }78 79 int GuestSessionTask::setProgress(ULONG uPercent)80 {81 if (mProgress.isNull()) /* Progress is optional. */82 return VINF_SUCCESS;83 84 BOOL fCanceled;85 if ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))86 && fCanceled)87 return VERR_CANCELLED;88 BOOL fCompleted;89 if ( SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))90 && !fCompleted)91 return VINF_SUCCESS;92 HRESULT hr = mProgress->SetCurrentOperationProgress(uPercent);93 if (FAILED(hr))94 return VERR_COM_UNEXPECTED;95 96 return VINF_SUCCESS;97 }98 99 int GuestSessionTask::setProgressSuccess(void)100 {101 if (mProgress.isNull()) /* Progress is optional. */102 return VINF_SUCCESS;103 104 BOOL fCanceled;105 BOOL fCompleted;106 if ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))107 && !fCanceled108 && SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))109 && !fCompleted)110 {111 HRESULT hr = mProgress->notifyComplete(S_OK);112 if (FAILED(hr))113 return VERR_COM_UNEXPECTED; /** @todo Find a better rc. */114 }115 116 return VINF_SUCCESS;117 }118 119 HRESULT GuestSessionTask::setProgressErrorMsg(HRESULT hr, const Utf8Str &strMsg)120 {121 if (mProgress.isNull()) /* Progress is optional. */122 return hr; /* Return original rc. */123 124 BOOL fCanceled;125 BOOL fCompleted;126 if ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))127 && !fCanceled128 && SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))129 && !fCompleted)130 {131 HRESULT hr2 = mProgress->notifyComplete(hr,132 COM_IIDOF(IGuestSession),133 GuestSession::getStaticComponentName(),134 strMsg.c_str());135 if (FAILED(hr2))136 return hr2;137 }138 return hr; /* Return original rc. */139 }140 141 SessionTaskCopyTo::SessionTaskCopyTo(GuestSession *pSession,142 const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags)143 : mSource(strSource),144 mDest(strDest),145 mSourceFile(NULL),146 mSourceOffset(0),147 mSourceSize(0),148 GuestSessionTask(pSession)149 {150 mCopyFileFlags = uFlags;151 }152 153 /** @todo Merge this and the above call and let the above call do the open/close file handling so that the154 * inner code only has to deal with file handles. No time now ... */155 SessionTaskCopyTo::SessionTaskCopyTo(GuestSession *pSession,156 PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize,157 const Utf8Str &strDest, uint32_t uFlags)158 : GuestSessionTask(pSession)159 {160 mSourceFile = pSourceFile;161 mSourceOffset = cbSourceOffset;162 mSourceSize = cbSourceSize;163 mDest = strDest;164 mCopyFileFlags = uFlags;165 }166 167 SessionTaskCopyTo::~SessionTaskCopyTo(void)168 {169 170 }171 172 int SessionTaskCopyTo::Run(void)173 {174 LogFlowThisFuncEnter();175 176 ComObjPtr<GuestSession> pSession = mSession;177 Assert(!pSession.isNull());178 179 AutoCaller autoCaller(pSession);180 if (FAILED(autoCaller.rc())) return autoCaller.rc();181 182 if (mCopyFileFlags)183 {184 setProgressErrorMsg(VBOX_E_IPRT_ERROR,185 Utf8StrFmt(GuestSession::tr("Copy flags (%#x) not implemented yet"),186 mCopyFileFlags));187 return VERR_INVALID_PARAMETER;188 }189 190 int rc;191 192 RTFILE fileLocal;193 PRTFILE pFile = &fileLocal;194 195 if (!mSourceFile)196 {197 /* Does our source file exist? */198 if (!RTFileExists(mSource.c_str()))199 {200 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,201 Utf8StrFmt(GuestSession::tr("Source file \"%s\" does not exist or is not a file"),202 mSource.c_str()));203 }204 else205 {206 rc = RTFileOpen(pFile, mSource.c_str(),207 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);208 if (RT_FAILURE(rc))209 {210 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,211 Utf8StrFmt(GuestSession::tr("Could not open source file \"%s\" for reading: %Rrc"),212 mSource.c_str(), rc));213 }214 else215 {216 rc = RTFileGetSize(*pFile, &mSourceSize);217 if (RT_FAILURE(rc))218 {219 setProgressErrorMsg(VBOX_E_IPRT_ERROR,220 Utf8StrFmt(GuestSession::tr("Could not query file size of \"%s\": %Rrc"),221 mSource.c_str(), rc));222 }223 }224 }225 }226 else227 {228 pFile = mSourceFile;229 /* Size + offset are optional. */230 }231 232 GuestProcessStartupInfo procInfo;233 procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to the guest to \"%s\" (%RU64 bytes)"),234 mSource.c_str(), mDest.c_str(), mSourceSize);235 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_CAT);236 procInfo.mFlags = ProcessCreateFlag_Hidden;237 238 /* Set arguments.*/239 procInfo.mArguments.push_back(Utf8StrFmt("--output=%s", mDest.c_str())); /** @todo Do we need path conversion? */240 241 /* Startup process. */242 ComObjPtr<GuestProcess> pProcess;243 rc = pSession->processCreateExInteral(procInfo, pProcess);244 if (RT_SUCCESS(rc))245 rc = pProcess->startProcess();246 if (RT_FAILURE(rc))247 {248 setProgressErrorMsg(VBOX_E_IPRT_ERROR,249 Utf8StrFmt(GuestSession::tr("Unable to start guest process: %Rrc"), rc));250 }251 else252 {253 GuestProcessWaitResult waitRes;254 BYTE byBuf[_64K];255 256 BOOL fCanceled = FALSE;257 uint64_t cbWrittenTotal = 0;258 uint64_t cbToRead = mSourceSize;259 260 for (;;)261 {262 rc = pProcess->waitFor(ProcessWaitForFlag_StdIn,263 30 * 1000 /* Timeout */, waitRes);264 if ( RT_FAILURE(rc)265 || ( waitRes.mResult != ProcessWaitResult_StdIn266 && waitRes.mResult != ProcessWaitResult_Any))267 {268 break;269 }270 271 size_t cbRead = 0;272 if (mSourceSize) /* If we have nothing to write, take a shortcut. */273 {274 /** @todo Not very efficient, but works for now. */275 rc = RTFileSeek(*pFile, mSourceOffset + cbWrittenTotal,276 RTFILE_SEEK_BEGIN, NULL /* poffActual */);277 if (RT_SUCCESS(rc))278 {279 rc = RTFileRead(*pFile, (uint8_t*)byBuf,280 RT_MIN(cbToRead, sizeof(byBuf)), &cbRead);281 /*282 * Some other error occured? There might be a chance that RTFileRead283 * could not resolve/map the native error code to an IPRT code, so just284 * print a generic error.285 */286 if (RT_FAILURE(rc))287 {288 setProgressErrorMsg(VBOX_E_IPRT_ERROR,289 Utf8StrFmt(GuestSession::tr("Could not read from file \"%s\" (%Rrc)"),290 mSource.c_str(), rc));291 break;292 }293 }294 else295 {296 setProgressErrorMsg(VBOX_E_IPRT_ERROR,297 Utf8StrFmt(GuestSession::tr("Seeking file \"%s\" offset %RU64 failed: %Rrc"),298 mSource.c_str(), cbWrittenTotal, rc));299 break;300 }301 }302 303 uint32_t fFlags = ProcessInputFlag_None;304 305 /* Did we reach the end of the content we want to transfer (last chunk)? */306 if ( (cbRead < sizeof(byBuf))307 /* Did we reach the last block which is exactly _64K? */308 || (cbToRead - cbRead == 0)309 /* ... or does the user want to cancel? */310 || ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))311 && fCanceled)312 )313 {314 fFlags |= ProcessInputFlag_EndOfFile;315 }316 317 uint32_t cbWritten;318 Assert(sizeof(byBuf) >= cbRead);319 rc = pProcess->writeData(0 /* StdIn */, fFlags,320 byBuf, cbRead,321 30 * 1000 /* Timeout */, &cbWritten);322 if (RT_FAILURE(rc))323 {324 setProgressErrorMsg(VBOX_E_IPRT_ERROR,325 Utf8StrFmt(GuestSession::tr("Writing to file \"%s\" (offset %RU64) failed: %Rrc"),326 mDest.c_str(), cbWrittenTotal, rc));327 break;328 }329 330 LogFlowThisFunc(("cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n",331 cbWritten, cbToRead - cbWritten, cbWrittenTotal + cbWritten, mSourceSize));332 333 /* Only subtract bytes reported written by the guest. */334 Assert(cbToRead >= cbWritten);335 cbToRead -= cbWritten;336 337 /* Update total bytes written to the guest. */338 cbWrittenTotal += cbWritten;339 Assert(cbWrittenTotal <= mSourceSize);340 341 /* Did the user cancel the operation above? */342 if (fCanceled)343 break;344 345 /* Update the progress.346 * Watch out for division by zero. */347 mSourceSize > 0348 ? rc = setProgress((ULONG)(cbWrittenTotal * 100 / mSourceSize))349 : rc = setProgress(100);350 if (RT_FAILURE(rc))351 break;352 353 /* End of file reached? */354 if (!cbToRead)355 break;356 } /* for */357 358 if ( !fCanceled359 || RT_SUCCESS(rc))360 {361 /*362 * Even if we succeeded until here make sure to check whether we really transfered363 * everything.364 */365 if ( mSourceSize > 0366 && cbWrittenTotal == 0)367 {368 /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write369 * to the destination -> access denied. */370 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,371 Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""),372 mSource.c_str(), mDest.c_str()));373 }374 else if (cbWrittenTotal < mSourceSize)375 {376 /* If we did not copy all let the user know. */377 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,378 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed (%RU64/%RU64 bytes transfered)"),379 mSource.c_str(), cbWrittenTotal, mSourceSize));380 }381 else382 {383 rc = pProcess->waitFor(ProcessWaitForFlag_Terminate,384 30 * 1000 /* Timeout */, waitRes);385 if ( RT_FAILURE(rc)386 || waitRes.mResult != ProcessWaitResult_Terminate)387 {388 if (RT_FAILURE(rc))389 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,390 Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed: %Rrc"),391 mSource.c_str(), rc));392 else393 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,394 Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed with wait result %ld"),395 mSource.c_str(), waitRes.mResult));396 }397 398 if (RT_SUCCESS(rc))399 {400 ProcessStatus_T procStatus;401 LONG exitCode;402 if ( ( SUCCEEDED(pProcess->COMGETTER(Status(&procStatus)))403 && procStatus != ProcessStatus_TerminatedNormally)404 || ( SUCCEEDED(pProcess->COMGETTER(ExitCode(&exitCode)))405 && exitCode != 0)406 )407 {408 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,409 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed with status %ld, exit code %ld"),410 mSource.c_str(), procStatus, exitCode)); /**@todo Add stringify methods! */411 }412 }413 414 if (RT_SUCCESS(rc))415 rc = setProgressSuccess();416 }417 }418 419 pProcess->close();420 } /* processCreateExInteral */421 422 if (!mSourceFile) /* Only close locally opened files. */423 RTFileClose(*pFile);424 425 LogFlowFuncLeaveRC(rc);426 return rc;427 }428 429 int SessionTaskCopyTo::RunAsync(const Utf8Str &strDesc, ComObjPtr<Progress> &pProgress)430 {431 LogFlowThisFunc(("strDesc=%s, strSource=%s, strDest=%s, mCopyFileFlags=%x\n",432 strDesc.c_str(), mSource.c_str(), mDest.c_str(), mCopyFileFlags));433 434 mDesc = strDesc;435 mProgress = pProgress;436 437 int rc = RTThreadCreate(NULL, SessionTaskCopyTo::taskThread, this,438 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,439 "gctlCpyTo");440 LogFlowFuncLeaveRC(rc);441 return rc;442 }443 444 /* static */445 int SessionTaskCopyTo::taskThread(RTTHREAD Thread, void *pvUser)446 {447 std::auto_ptr<SessionTaskCopyTo> task(static_cast<SessionTaskCopyTo*>(pvUser));448 AssertReturn(task.get(), VERR_GENERAL_FAILURE);449 450 LogFlowFunc(("pTask=%p\n", task.get()));451 return task->Run();452 }453 454 SessionTaskCopyFrom::SessionTaskCopyFrom(GuestSession *pSession,455 const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags)456 : GuestSessionTask(pSession)457 {458 mSource = strSource;459 mDest = strDest;460 mFlags = uFlags;461 }462 463 SessionTaskCopyFrom::~SessionTaskCopyFrom(void)464 {465 466 }467 468 int SessionTaskCopyFrom::Run(void)469 {470 LogFlowThisFuncEnter();471 472 ComObjPtr<GuestSession> pSession = mSession;473 Assert(!pSession.isNull());474 475 AutoCaller autoCaller(pSession);476 if (FAILED(autoCaller.rc())) return autoCaller.rc();477 478 /*479 * Note: There will be races between querying file size + reading the guest file's480 * content because we currently *do not* lock down the guest file when doing the481 * actual operations.482 ** @todo Implement guest file locking!483 */484 GuestFsObjData objData;485 int rc = pSession->fileQueryInfoInternal(Utf8Str(mSource), objData);486 if (RT_FAILURE(rc))487 {488 setProgressErrorMsg(VBOX_E_IPRT_ERROR,489 Utf8StrFmt(GuestSession::tr("Querying guest file information for \"%s\" failed: %Rrc"),490 mSource.c_str(), rc));491 }492 else if (objData.mType != FsObjType_File) /* Only single files are supported at the moment. */493 {494 rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR,495 Utf8StrFmt(GuestSession::tr("Object \"%s\" on the guest is not a file"), mSource.c_str()));496 }497 498 if (RT_SUCCESS(rc))499 {500 RTFILE fileDest;501 rc = RTFileOpen(&fileDest, mDest.c_str(),502 RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); /** @todo Use the correct open modes! */503 if (RT_FAILURE(rc))504 {505 setProgressErrorMsg(VBOX_E_IPRT_ERROR,506 Utf8StrFmt(GuestSession::tr("Error opening destination file \"%s\": %Rrc"),507 mDest.c_str(), rc));508 }509 else510 {511 GuestProcessStartupInfo procInfo;512 procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"),513 mSource.c_str(), mDest.c_str(), objData.mObjectSize);514 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_CAT);515 procInfo.mFlags = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;516 517 /* Set arguments.*/518 procInfo.mArguments.push_back(mSource); /* Which file to output? */519 520 /* Startup process. */521 ComObjPtr<GuestProcess> pProcess;522 rc = pSession->processCreateExInteral(procInfo, pProcess);523 if (RT_SUCCESS(rc))524 rc = pProcess->startProcess();525 if (RT_FAILURE(rc))526 {527 setProgressErrorMsg(VBOX_E_IPRT_ERROR,528 Utf8StrFmt(GuestSession::tr("Unable to start guest process for copying data from guest to host: %Rrc"), rc));529 }530 else531 {532 GuestProcessWaitResult waitRes;533 BYTE byBuf[_64K];534 535 BOOL fCanceled = FALSE;536 uint64_t cbWrittenTotal = 0;537 uint64_t cbToRead = objData.mObjectSize;538 539 for (;;)540 {541 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,542 30 * 1000 /* Timeout */, waitRes);543 if ( waitRes.mResult == ProcessWaitResult_StdOut544 || waitRes.mResult == ProcessWaitResult_Any)545 {546 size_t cbRead;547 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),548 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),549 &cbRead);550 if (RT_FAILURE(rc))551 {552 setProgressErrorMsg(VBOX_E_IPRT_ERROR,553 Utf8StrFmt(GuestSession::tr("Reading from file \"%s\" (offset %RU64) failed: %Rrc"),554 mSource.c_str(), cbWrittenTotal, rc));555 break;556 }557 558 if (cbRead)559 {560 rc = RTFileWrite(fileDest, byBuf, cbRead, NULL /* No partial writes */);561 if (RT_FAILURE(rc))562 {563 setProgressErrorMsg(VBOX_E_IPRT_ERROR,564 Utf8StrFmt(GuestSession::tr("Error writing to file \"%s\" (%RU64 bytes left): %Rrc"),565 mDest.c_str(), cbToRead, rc));566 break;567 }568 569 /* Only subtract bytes reported written by the guest. */570 Assert(cbToRead >= cbRead);571 cbToRead -= cbRead;572 573 /* Update total bytes written to the guest. */574 cbWrittenTotal += cbRead;575 Assert(cbWrittenTotal <= (uint64_t)objData.mObjectSize);576 577 /* Did the user cancel the operation above? */578 if ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))579 && fCanceled)580 break;581 582 rc = setProgress((ULONG)(cbWrittenTotal / ((uint64_t)objData.mObjectSize / 100.0)));583 if (RT_FAILURE(rc))584 break;585 }586 }587 else if ( RT_FAILURE(rc)588 || waitRes.mResult == ProcessWaitResult_Terminate589 || waitRes.mResult == ProcessWaitResult_Error590 || waitRes.mResult == ProcessWaitResult_Timeout)591 {592 if (RT_FAILURE(waitRes.mRC))593 rc = waitRes.mRC;594 break;595 }596 } /* for */597 598 LogFlowThisFunc(("rc=%Rrc, cbWrittenTotal=%RU64, cbSize=%RI64, cbToRead=%RU64\n",599 rc, cbWrittenTotal, objData.mObjectSize, cbToRead));600 601 if ( !fCanceled602 || RT_SUCCESS(rc))603 {604 /*605 * Even if we succeeded until here make sure to check whether we really transfered606 * everything.607 */608 if ( objData.mObjectSize > 0609 && cbWrittenTotal == 0)610 {611 /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write612 * to the destination -> access denied. */613 setProgressErrorMsg(VBOX_E_IPRT_ERROR,614 Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""),615 mSource.c_str(), mDest.c_str()));616 rc = VERR_GENERAL_FAILURE; /* Fudge. */617 }618 else if (cbWrittenTotal < (uint64_t)objData.mObjectSize)619 {620 /* If we did not copy all let the user know. */621 setProgressErrorMsg(VBOX_E_IPRT_ERROR,622 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed (%RU64/%RI64 bytes transfered)"),623 mSource.c_str(), cbWrittenTotal, objData.mObjectSize));624 rc = VERR_GENERAL_FAILURE; /* Fudge. */625 }626 else627 {628 ProcessStatus_T procStatus;629 LONG exitCode;630 if ( ( SUCCEEDED(pProcess->COMGETTER(Status(&procStatus)))631 && procStatus != ProcessStatus_TerminatedNormally)632 || ( SUCCEEDED(pProcess->COMGETTER(ExitCode(&exitCode)))633 && exitCode != 0)634 )635 {636 setProgressErrorMsg(VBOX_E_IPRT_ERROR,637 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed with status %ld, exit code %d"),638 mSource.c_str(), procStatus, exitCode)); /**@todo Add stringify methods! */639 rc = VERR_GENERAL_FAILURE; /* Fudge. */640 }641 else /* Yay, success! */642 rc = setProgressSuccess();643 }644 }645 646 pProcess->close();647 }648 649 RTFileClose(fileDest);650 }651 }652 653 LogFlowFuncLeaveRC(rc);654 return rc;655 }656 657 int SessionTaskCopyFrom::RunAsync(const Utf8Str &strDesc, ComObjPtr<Progress> &pProgress)658 {659 LogFlowThisFunc(("strDesc=%s, strSource=%s, strDest=%s, uFlags=%x\n",660 strDesc.c_str(), mSource.c_str(), mDest.c_str(), mFlags));661 662 mDesc = strDesc;663 mProgress = pProgress;664 665 int rc = RTThreadCreate(NULL, SessionTaskCopyFrom::taskThread, this,666 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,667 "gctlCpyFrom");668 LogFlowFuncLeaveRC(rc);669 return rc;670 }671 672 /* static */673 int SessionTaskCopyFrom::taskThread(RTTHREAD Thread, void *pvUser)674 {675 std::auto_ptr<SessionTaskCopyFrom> task(static_cast<SessionTaskCopyFrom*>(pvUser));676 AssertReturn(task.get(), VERR_GENERAL_FAILURE);677 678 LogFlowFunc(("pTask=%p\n", task.get()));679 return task->Run();680 }681 682 SessionTaskUpdateAdditions::SessionTaskUpdateAdditions(GuestSession *pSession,683 const Utf8Str &strSource, uint32_t uFlags)684 : GuestSessionTask(pSession)685 {686 mSource = strSource;687 mFlags = uFlags;688 }689 690 SessionTaskUpdateAdditions::~SessionTaskUpdateAdditions(void)691 {692 693 }694 695 int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFSFILE pISO,696 Utf8Str const &strFileSource, const Utf8Str &strFileDest,697 bool fOptional, uint32_t *pcbSize)698 {699 AssertPtrReturn(pSession, VERR_INVALID_POINTER);700 AssertPtrReturn(pISO, VERR_INVALID_POINTER);701 /* pcbSize is optional. */702 703 uint32_t cbOffset;704 size_t cbSize;705 706 int rc = RTIsoFsGetFileInfo(pISO, strFileSource.c_str(), &cbOffset, &cbSize);707 if (RT_FAILURE(rc))708 {709 if (fOptional)710 return VINF_SUCCESS;711 712 return rc;713 }714 715 Assert(cbOffset);716 Assert(cbSize);717 rc = RTFileSeek(pISO->file, cbOffset, RTFILE_SEEK_BEGIN, NULL);718 719 /* Copy over the Guest Additions file to the guest. */720 if (RT_SUCCESS(rc))721 {722 LogRel(("Copying Guest Additions installer file \"%s\" to \"%s\" on guest ...\n",723 strFileSource.c_str(), strFileDest.c_str()));724 725 if (RT_SUCCESS(rc))726 {727 SessionTaskCopyTo *pTask = new SessionTaskCopyTo(pSession /* GuestSession */,728 &pISO->file, cbOffset, cbSize,729 strFileDest, CopyFileFlag_None);730 AssertPtrReturn(pTask, VERR_NO_MEMORY);731 732 ComObjPtr<Progress> pProgressCopyTo;733 rc = pSession->startTaskAsync(Utf8StrFmt(GuestSession::tr("Copying Guest Additions installer file \"%s\" to \"%s\" on guest"),734 mSource.c_str(), strFileDest.c_str()),735 pTask, pProgressCopyTo);736 if (RT_SUCCESS(rc))737 {738 BOOL fCanceled = FALSE;739 HRESULT hr = pProgressCopyTo->WaitForCompletion(-1);740 if ( SUCCEEDED(pProgressCopyTo->COMGETTER(Canceled)(&fCanceled))741 && fCanceled)742 {743 rc = VERR_GENERAL_FAILURE; /* Fudge. */744 }745 else if (FAILED(hr))746 {747 Assert(FAILED(hr));748 rc = VERR_GENERAL_FAILURE; /* Fudge. */749 }750 }751 }752 }753 754 /** @todo Note: Since there is no file locking involved at the moment, there can be modifications755 * between finished copying, the verification and the actual execution. */756 757 /* Determine where the installer image ended up and if it has the correct size. */758 if (RT_SUCCESS(rc))759 {760 LogRel(("Verifying Guest Additions installer file \"%s\" ...\n", strFileDest.c_str()));761 762 GuestFsObjData objData;763 int64_t cbSizeOnGuest;764 rc = pSession->fileQuerySizeInternal(strFileDest, &cbSizeOnGuest);765 #ifdef VBOX_SERVICE_ENVARG_BUG766 if (RT_FAILURE(rc))767 {768 /* Ugly hack: Because older Guest Additions have problems with environment variable769 expansion in parameters we have to check an alternative location on Windows.770 So check for "%TEMP%\" being "C:\\Windows\\system32\\EMP" actually. */771 if (strFileDest.startsWith("%TEMP%\\", RTCString::CaseSensitive))772 {773 Utf8Str strFileDestBug = "C:\\Windows\\system32\\EMP" + strFileDest.substr(sizeof("%TEMP%\\") - sizeof(char));774 rc = pSession->fileQuerySizeInternal(strFileDestBug, &cbSizeOnGuest);775 }776 }777 #endif778 if ( RT_SUCCESS(rc)779 && cbSize == (uint64_t)cbSizeOnGuest)780 {781 LogRel(("Guest Additions installer file \"%s\" successfully verified\n",782 strFileDest.c_str()));783 }784 else785 {786 if (RT_SUCCESS(rc)) /* Size does not match. */787 rc = VERR_BROKEN_PIPE; /** @todo FInd a better error. */788 }789 790 if (RT_SUCCESS(rc))791 {792 if (pcbSize)793 *pcbSize = cbSizeOnGuest;794 }795 }796 797 return rc;798 }799 800 int SessionTaskUpdateAdditions::runFile(GuestSession *pSession, GuestProcessStartupInfo &procInfo)801 {802 AssertPtrReturn(pSession, VERR_INVALID_POINTER);803 804 #ifdef VBOX_SERVICE_ENVARG_BUG805 GuestFsObjData objData;806 int rc = pSession->fileQueryInfoInternal(procInfo.mCommand, objData);807 if (RT_FAILURE(rc))808 procInfo.mCommand = "C:\\Windows\\system32\\EMP" + procInfo.mCommand.substr(sizeof("%TEMP%\\") - sizeof(char));809 #endif810 811 ComObjPtr<GuestProcess> pProcess;812 rc = pSession->processCreateExInteral(procInfo, pProcess);813 if (RT_SUCCESS(rc))814 rc = pProcess->startProcess();815 816 if (RT_SUCCESS(rc))817 {818 LogRel(("Running %s ...\n", procInfo.mName.c_str()));819 820 GuestProcessWaitResult waitRes;821 rc = pProcess->waitFor(ProcessWaitForFlag_Terminate,822 10 * 60 * 1000 /* 10 mins Timeout */, waitRes);823 if (waitRes.mResult == ProcessWaitResult_Terminate)824 {825 ProcessStatus_T procStatus;826 LONG exitCode;827 if ( ( SUCCEEDED(pProcess->COMGETTER(Status(&procStatus)))828 && procStatus != ProcessStatus_TerminatedNormally)829 || ( SUCCEEDED(pProcess->COMGETTER(ExitCode(&exitCode)))830 && exitCode != 0)831 )832 {833 setProgressErrorMsg(VBOX_E_IPRT_ERROR,834 Utf8StrFmt(GuestSession::tr("Running %s failed with status %ld, exit code %ld"),835 procInfo.mName.c_str(), procStatus, exitCode));836 rc = VERR_GENERAL_FAILURE; /* Fudge. */837 }838 else /* Yay, success! */839 {840 LogRel(("%s successfully completed\n", procInfo.mName.c_str()));841 }842 }843 else844 {845 if (RT_FAILURE(rc))846 setProgressErrorMsg(VBOX_E_IPRT_ERROR,847 Utf8StrFmt(GuestSession::tr("Error while waiting running %s: %Rrc"),848 procInfo.mName.c_str(), rc));849 else850 {851 setProgressErrorMsg(VBOX_E_IPRT_ERROR, pProcess->errorMsg());852 rc = VERR_GENERAL_FAILURE; /* Fudge. */853 }854 }855 }856 857 if (!pProcess.isNull())858 pProcess->close();859 860 return rc;861 }862 863 int SessionTaskUpdateAdditions::Run(void)864 {865 LogFlowThisFuncEnter();866 867 ComObjPtr<GuestSession> pSession = mSession;868 Assert(!pSession.isNull());869 870 AutoCaller autoCaller(pSession);871 if (FAILED(autoCaller.rc())) return autoCaller.rc();872 873 int rc = setProgress(10);874 if (RT_FAILURE(rc))875 return rc;876 877 HRESULT hr = S_OK;878 879 LogRel(("Automatic update of Guest Additions started, using \"%s\"\n", mSource.c_str()));880 881 /*882 * Determine guest OS type and the required installer image.883 * At the moment only Windows guests are supported.884 */885 Utf8Str strInstallerImage;886 887 ComObjPtr<Guest> pGuest(mSession->getParent());888 Bstr osTypeId;889 if ( SUCCEEDED(pGuest->COMGETTER(OSTypeId(osTypeId.asOutParam())))890 && !osTypeId.isEmpty())891 {892 Utf8Str osTypeIdUtf8(osTypeId); /* Needed for .contains(). */893 if ( osTypeIdUtf8.contains("Microsoft", Utf8Str::CaseInsensitive)894 || osTypeIdUtf8.contains("Windows", Utf8Str::CaseInsensitive))895 {896 if (osTypeIdUtf8.contains("64", Utf8Str::CaseInsensitive))897 strInstallerImage = "VBOXWINDOWSADDITIONS_AMD64.EXE";898 else899 strInstallerImage = "VBOXWINDOWSADDITIONS_X86.EXE";900 /* Since the installers are located in the root directory,901 * no further path processing needs to be done (yet). */902 }903 else /* Everything else is not supported (yet). */904 {905 hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,906 Utf8StrFmt(GuestSession::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"),907 osTypeIdUtf8.c_str()));908 rc = VERR_GENERAL_FAILURE; /* Fudge. */909 }910 }911 else912 {913 hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,914 Utf8StrFmt(GuestSession::tr("Could not detected guest OS type/version, please update manually")));915 rc = VERR_GENERAL_FAILURE; /* Fudge. */916 }917 918 RTISOFSFILE iso;919 if (RT_SUCCESS(rc))920 {921 Assert(!strInstallerImage.isEmpty());922 923 /*924 * Try to open the .ISO file and locate the specified installer.925 */926 rc = RTIsoFsOpen(&iso, mSource.c_str());927 if (RT_FAILURE(rc))928 {929 hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,930 Utf8StrFmt(GuestSession::tr("Unable to open Guest Additions .ISO file \"%s\": %Rrc"),931 mSource.c_str(), rc));932 }933 else934 {935 rc = setProgress(5);936 937 /** @todo Add support for non-Windows as well! */938 Utf8Str strInstallerDest = "%TEMP%\\VBoxWindowsAdditions.exe";939 bool fInstallCertificates = false;940 941 if (RT_SUCCESS(rc))942 {943 /*944 * Copy over main installer to the guest.945 */946 rc = copyFileToGuest(pSession, &iso, strInstallerImage, strInstallerDest,947 false /* File is not optional */, NULL /* cbSize */);948 if (RT_SUCCESS(rc))949 rc = setProgress(20);950 951 /*952 * Install needed certificates for the WHQL crap.953 ** @todo Only for Windows!954 */955 if (RT_SUCCESS(rc))956 {957 rc = copyFileToGuest(pSession, &iso, "CERT/ORACLE_VBOX.CER", "%TEMP%\\oracle-vbox.cer",958 true /* File is optional */, NULL /* cbSize */);959 if (RT_SUCCESS(rc))960 {961 rc = setProgress(30);962 if (RT_SUCCESS(rc))963 {964 rc = copyFileToGuest(pSession, &iso, "CERT/VBOXCERTUTIL.EXE", "%TEMP%\\VBoxCertUtil.exe",965 true /* File is optional */, NULL /* cbSize */);966 if (RT_SUCCESS(rc))967 {968 fInstallCertificates = true;969 rc = setProgress(40);970 }971 else972 hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,973 Utf8StrFmt(GuestSession::tr("Error while copying certificate installation tool to the guest: %Rrc"), rc));974 }975 }976 else977 hr = setProgressErrorMsg(VBOX_E_IPRT_ERROR,978 Utf8StrFmt(GuestSession::tr("Error while copying certificate to the guest: %Rrc"), rc));979 }980 }981 982 /*983 * Run VBoxCertUtil.exe to install the Oracle certificate.984 */985 if ( RT_SUCCESS(rc)986 && fInstallCertificates)987 {988 LogRel(("Installing certificates on the guest ...\n"));989 990 GuestProcessStartupInfo procInfo;991 procInfo.mName = Utf8StrFmt(GuestSession::tr("VirtualBox Guest Additions Certificate Utility"));992 procInfo.mCommand = Utf8Str("%TEMP%\\VBoxCertUtil.exe");993 procInfo.mFlags = ProcessCreateFlag_Hidden;994 995 /* Construct arguments. */996 /** @todo Remove hardcoded paths. */997 procInfo.mArguments.push_back(Utf8Str("add-trusted-publisher"));998 /* Ugly hack: Because older Guest Additions have problems with environment variable999 expansion in parameters we have to check an alternative location on Windows.1000 So check for "%TEMP%\VBoxWindowsAdditions.exe" in a screwed up way. */1001 #ifdef VBOX_SERVICE_ENVARG_BUG1002 GuestFsObjData objData;1003 rc = pSession->fileQueryInfoInternal("%TEMP%\\oracle-vbox.cer", objData);1004 if (RT_SUCCESS(rc))1005 #endif1006 procInfo.mArguments.push_back(Utf8Str("%TEMP%\\oracle-vbox.cer"));1007 #ifdef VBOX_SERVICE_ENVARG_BUG1008 else1009 procInfo.mArguments.push_back(Utf8Str("C:\\Windows\\system32\\EMPoracle-vbox.cer"));1010 #endif1011 /* Overwrite rc in any case. */1012 rc = runFile(pSession, procInfo);1013 }1014 1015 if (RT_SUCCESS(rc))1016 rc = setProgress(60);1017 1018 if (RT_SUCCESS(rc))1019 {1020 LogRel(("Updating Guest Additions ...\n"));1021 1022 GuestProcessStartupInfo procInfo;1023 procInfo.mName = Utf8StrFmt(GuestSession::tr("VirtualBox Guest Additions Setup"));1024 procInfo.mCommand = Utf8Str(strInstallerDest);1025 procInfo.mFlags = ProcessCreateFlag_Hidden;1026 /* If the caller does not want to wait for out guest update process to end,1027 * complete the progress object now so that the caller can do other work. */1028 if (mFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly)1029 procInfo.mFlags |= ProcessCreateFlag_WaitForProcessStartOnly;1030 1031 /* Construct arguments. */1032 procInfo.mArguments.push_back(Utf8Str("/S")); /* We want to install in silent mode. */1033 procInfo.mArguments.push_back(Utf8Str("/l")); /* ... and logging enabled. */1034 /* Don't quit VBoxService during upgrade because it still is used for this1035 * piece of code we're in right now (that is, here!) ... */1036 procInfo.mArguments.push_back(Utf8Str("/no_vboxservice_exit"));1037 /* Tell the installer to report its current installation status1038 * using a running VBoxTray instance via balloon messages in the1039 * Windows taskbar. */1040 procInfo.mArguments.push_back(Utf8Str("/post_installstatus"));1041 1042 rc = runFile(pSession, procInfo);1043 if (RT_SUCCESS(rc))1044 hr = setProgressSuccess();1045 }1046 RTIsoFsClose(&iso);1047 }1048 }1049 1050 LogFlowFuncLeaveRC(rc);1051 return rc;1052 }1053 1054 int SessionTaskUpdateAdditions::RunAsync(const Utf8Str &strDesc, ComObjPtr<Progress> &pProgress)1055 {1056 LogFlowThisFunc(("strDesc=%s, strSource=%s, uFlags=%x\n",1057 strDesc.c_str(), mSource.c_str(), mFlags));1058 1059 mDesc = strDesc;1060 mProgress = pProgress;1061 1062 int rc = RTThreadCreate(NULL, SessionTaskUpdateAdditions::taskThread, this,1063 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,1064 "gctlUpGA");1065 LogFlowFuncLeaveRC(rc);1066 return rc;1067 }1068 1069 /* static */1070 int SessionTaskUpdateAdditions::taskThread(RTTHREAD Thread, void *pvUser)1071 {1072 std::auto_ptr<SessionTaskUpdateAdditions> task(static_cast<SessionTaskUpdateAdditions*>(pvUser));1073 AssertReturn(task.get(), VERR_GENERAL_FAILURE);1074 1075 LogFlowFunc(("pTask=%p\n", task.get()));1076 return task->Run();1077 65 } 1078 66 -
trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp
r42808 r42810 34 34 #include <iprt/file.h> /* For CopyTo/From. */ 35 35 36 #include <VBox/com/array.h>37 #include <VBox/version.h>38 39 36 40 37 /* … … 45 42 */ 46 43 #define VBOX_SERVICE_ENVARG_BUG 47 48 // constructor / destructor49 /////////////////////////////////////////////////////////////////////////////50 51 DEFINE_EMPTY_CTOR_DTOR(GuestSession)52 53 HRESULT GuestSession::FinalConstruct(void)54 {55 LogFlowThisFunc(("\n"));56 return BaseFinalConstruct();57 }58 59 void GuestSession::FinalRelease(void)60 {61 LogFlowThisFuncEnter();62 uninit();63 BaseFinalRelease();64 LogFlowThisFuncLeave();65 }66 44 67 45 // session task classes … … 264 242 if ( RT_FAILURE(rc) 265 243 || ( waitRes.mResult != ProcessWaitResult_StdIn 266 && waitRes.mResult != ProcessWaitResult_ Any))244 && waitRes.mResult != ProcessWaitResult_WaitFlagNotSupported)) 267 245 { 268 246 break; 269 247 } 248 249 /* If the guest does not support waiting for stdin, we now yield in 250 * order to reduce the CPU load due to busy waiting. */ 251 if (waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported) 252 RTThreadYield(); /* Optional, don't check rc. */ 270 253 271 254 size_t cbRead = 0; … … 542 525 30 * 1000 /* Timeout */, waitRes); 543 526 if ( waitRes.mResult == ProcessWaitResult_StdOut 544 || waitRes.mResult == ProcessWaitResult_ Any)527 || waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported) 545 528 { 529 /* If the guest does not support waiting for stdin, we now yield in 530 * order to reduce the CPU load due to busy waiting. */ 531 if (waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported) 532 RTThreadYield(); /* Optional, don't check rc. */ 533 546 534 size_t cbRead; 547 535 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf), … … 1077 1065 } 1078 1066 1079 // public initializer/uninitializer for internal purposes only1080 /////////////////////////////////////////////////////////////////////////////1081 1082 int GuestSession::init(Guest *aGuest, ULONG aSessionID,1083 Utf8Str aUser, Utf8Str aPassword, Utf8Str aDomain, Utf8Str aName)1084 {1085 LogFlowThisFuncEnter();1086 1087 AssertPtrReturn(aGuest, VERR_INVALID_POINTER);1088 1089 /* Enclose the state transition NotReady->InInit->Ready. */1090 AutoInitSpan autoInitSpan(this);1091 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);1092 1093 mData.mTimeout = 30 * 60 * 1000; /* Session timeout is 30 mins by default. */1094 mData.mParent = aGuest;1095 mData.mId = aSessionID;1096 1097 mData.mCredentials.mUser = aUser;1098 mData.mCredentials.mPassword = aPassword;1099 mData.mCredentials.mDomain = aDomain;1100 mData.mName = aName;1101 1102 /* Confirm a successful initialization when it's the case. */1103 autoInitSpan.setSucceeded();1104 1105 LogFlowFuncLeaveRC(VINF_SUCCESS);1106 return VINF_SUCCESS;1107 }1108 1109 /**1110 * Uninitializes the instance.1111 * Called from FinalRelease().1112 */1113 void GuestSession::uninit(void)1114 {1115 LogFlowThisFuncEnter();1116 1117 /* Enclose the state transition Ready->InUninit->NotReady. */1118 AutoUninitSpan autoUninitSpan(this);1119 if (autoUninitSpan.uninitDone())1120 return;1121 1122 #ifdef VBOX_WITH_GUEST_CONTROL1123 for (SessionDirectories::iterator itDirs = mData.mDirectories.begin();1124 itDirs != mData.mDirectories.end(); ++itDirs)1125 {1126 (*itDirs)->uninit();1127 (*itDirs).setNull();1128 }1129 mData.mDirectories.clear();1130 1131 for (SessionFiles::iterator itFiles = mData.mFiles.begin();1132 itFiles != mData.mFiles.end(); ++itFiles)1133 {1134 (*itFiles)->uninit();1135 (*itFiles).setNull();1136 }1137 mData.mFiles.clear();1138 1139 for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();1140 itProcs != mData.mProcesses.end(); ++itProcs)1141 {1142 itProcs->second->close();1143 }1144 1145 for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();1146 itProcs != mData.mProcesses.end(); ++itProcs)1147 {1148 itProcs->second->uninit();1149 itProcs->second.setNull();1150 }1151 mData.mProcesses.clear();1152 1153 mData.mParent->sessionClose(this);1154 1155 LogFlowThisFuncLeave();1156 #endif1157 }1158 1159 // implementation of public getters/setters for attributes1160 /////////////////////////////////////////////////////////////////////////////1161 1162 STDMETHODIMP GuestSession::COMGETTER(User)(BSTR *aUser)1163 {1164 #ifndef VBOX_WITH_GUEST_CONTROL1165 ReturnComNotImplemented();1166 #else1167 LogFlowThisFuncEnter();1168 1169 CheckComArgOutPointerValid(aUser);1170 1171 AutoCaller autoCaller(this);1172 if (FAILED(autoCaller.rc())) return autoCaller.rc();1173 1174 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);1175 1176 mData.mCredentials.mUser.cloneTo(aUser);1177 1178 LogFlowFuncLeaveRC(S_OK);1179 return S_OK;1180 #endif /* VBOX_WITH_GUEST_CONTROL */1181 }1182 1183 STDMETHODIMP GuestSession::COMGETTER(Domain)(BSTR *aDomain)1184 {1185 #ifndef VBOX_WITH_GUEST_CONTROL1186 ReturnComNotImplemented();1187 #else1188 LogFlowThisFuncEnter();1189 1190 CheckComArgOutPointerValid(aDomain);1191 1192 AutoCaller autoCaller(this);1193 if (FAILED(autoCaller.rc())) return autoCaller.rc();1194 1195 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);1196 1197 mData.mCredentials.mDomain.cloneTo(aDomain);1198 1199 LogFlowFuncLeaveRC(S_OK);1200 return S_OK;1201 #endif /* VBOX_WITH_GUEST_CONTROL */1202 }1203 1204 STDMETHODIMP GuestSession::COMGETTER(Name)(BSTR *aName)1205 {1206 #ifndef VBOX_WITH_GUEST_CONTROL1207 ReturnComNotImplemented();1208 #else1209 LogFlowThisFuncEnter();1210 1211 CheckComArgOutPointerValid(aName);1212 1213 AutoCaller autoCaller(this);1214 if (FAILED(autoCaller.rc())) return autoCaller.rc();1215 1216 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);1217 1218 mData.mName.cloneTo(aName);1219 1220 LogFlowFuncLeaveRC(S_OK);1221 return S_OK;1222 #endif /* VBOX_WITH_GUEST_CONTROL */1223 }1224 1225 STDMETHODIMP GuestSession::COMGETTER(Id)(ULONG *aId)1226 {1227 #ifndef VBOX_WITH_GUEST_CONTROL1228 ReturnComNotImplemented();1229 #else1230 LogFlowThisFuncEnter();1231 1232 CheckComArgOutPointerValid(aId);1233 1234 AutoCaller autoCaller(this);1235 if (FAILED(autoCaller.rc())) return autoCaller.rc();1236 1237 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);1238 1239 *aId = mData.mId;1240 1241 LogFlowFuncLeaveRC(S_OK);1242 return S_OK;1243 #endif /* VBOX_WITH_GUEST_CONTROL */1244 }1245 1246 STDMETHODIMP GuestSession::COMGETTER(Timeout)(ULONG *aTimeout)1247 {1248 #ifndef VBOX_WITH_GUEST_CONTROL1249 ReturnComNotImplemented();1250 #else1251 LogFlowThisFuncEnter();1252 1253 CheckComArgOutPointerValid(aTimeout);1254 1255 AutoCaller autoCaller(this);1256 if (FAILED(autoCaller.rc())) return autoCaller.rc();1257 1258 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);1259 1260 *aTimeout = mData.mTimeout;1261 1262 LogFlowFuncLeaveRC(S_OK);1263 return S_OK;1264 #endif /* VBOX_WITH_GUEST_CONTROL */1265 }1266 1267 STDMETHODIMP GuestSession::COMSETTER(Timeout)(ULONG aTimeout)1268 {1269 #ifndef VBOX_WITH_GUEST_CONTROL1270 ReturnComNotImplemented();1271 #else1272 LogFlowThisFuncEnter();1273 1274 AutoCaller autoCaller(this);1275 if (FAILED(autoCaller.rc())) return autoCaller.rc();1276 1277 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);1278 1279 mData.mTimeout = aTimeout;1280 1281 LogFlowFuncLeaveRC(S_OK);1282 return S_OK;1283 #endif /* VBOX_WITH_GUEST_CONTROL */1284 }1285 1286 STDMETHODIMP GuestSession::COMGETTER(Environment)(ComSafeArrayOut(BSTR, aEnvironment))1287 {1288 #ifndef VBOX_WITH_GUEST_CONTROL1289 ReturnComNotImplemented();1290 #else1291 LogFlowThisFuncEnter();1292 1293 CheckComArgOutSafeArrayPointerValid(aEnvironment);1294 1295 AutoCaller autoCaller(this);1296 if (FAILED(autoCaller.rc())) return autoCaller.rc();1297 1298 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);1299 1300 size_t cEnvVars = mData.mEnvironment.Size();1301 LogFlowThisFunc(("%s cEnvVars=%RU32\n", mData.mName.c_str(), cEnvVars));1302 com::SafeArray<BSTR> environment(cEnvVars);1303 1304 for (size_t i = 0; i < cEnvVars; i++)1305 {1306 Bstr strEnv(mData.mEnvironment.Get(i));1307 strEnv.cloneTo(&environment[i]);1308 }1309 environment.detachTo(ComSafeArrayOutArg(aEnvironment));1310 1311 LogFlowFuncLeaveRC(S_OK);1312 return S_OK;1313 #endif /* VBOX_WITH_GUEST_CONTROL */1314 }1315 1316 STDMETHODIMP GuestSession::COMSETTER(Environment)(ComSafeArrayIn(IN_BSTR, aValues))1317 {1318 #ifndef VBOX_WITH_GUEST_CONTROL1319 ReturnComNotImplemented();1320 #else1321 LogFlowThisFuncEnter();1322 1323 AutoCaller autoCaller(this);1324 if (FAILED(autoCaller.rc())) return autoCaller.rc();1325 1326 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);1327 1328 com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aValues));1329 1330 int rc = VINF_SUCCESS;1331 for (size_t i = 0; i < environment.size() && RT_SUCCESS(rc); i++)1332 {1333 Utf8Str strEnv(environment[i]);1334 if (!strEnv.isEmpty()) /* Silently skip empty entries. */1335 rc = mData.mEnvironment.Set(strEnv);1336 }1337 1338 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;1339 LogFlowFuncLeaveRC(hr);1340 return hr;1341 #endif /* VBOX_WITH_GUEST_CONTROL */1342 }1343 1344 STDMETHODIMP GuestSession::COMGETTER(Processes)(ComSafeArrayOut(IGuestProcess *, aProcesses))1345 {1346 #ifndef VBOX_WITH_GUEST_CONTROL1347 ReturnComNotImplemented();1348 #else1349 LogFlowThisFuncEnter();1350 1351 CheckComArgOutSafeArrayPointerValid(aProcesses);1352 1353 AutoCaller autoCaller(this);1354 if (FAILED(autoCaller.rc())) return autoCaller.rc();1355 1356 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);1357 1358 SafeIfaceArray<IGuestProcess> collection(mData.mProcesses);1359 collection.detachTo(ComSafeArrayOutArg(aProcesses));1360 1361 LogFlowFuncLeaveRC(S_OK);1362 return S_OK;1363 #endif /* VBOX_WITH_GUEST_CONTROL */1364 }1365 1366 STDMETHODIMP GuestSession::COMGETTER(Directories)(ComSafeArrayOut(IGuestDirectory *, aDirectories))1367 {1368 #ifndef VBOX_WITH_GUEST_CONTROL1369 ReturnComNotImplemented();1370 #else1371 LogFlowThisFuncEnter();1372 1373 CheckComArgOutSafeArrayPointerValid(aDirectories);1374 1375 AutoCaller autoCaller(this);1376 if (FAILED(autoCaller.rc())) return autoCaller.rc();1377 1378 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);1379 1380 SafeIfaceArray<IGuestDirectory> collection(mData.mDirectories);1381 collection.detachTo(ComSafeArrayOutArg(aDirectories));1382 1383 LogFlowFuncLeaveRC(S_OK);1384 return S_OK;1385 #endif /* VBOX_WITH_GUEST_CONTROL */1386 }1387 1388 STDMETHODIMP GuestSession::COMGETTER(Files)(ComSafeArrayOut(IGuestFile *, aFiles))1389 {1390 #ifndef VBOX_WITH_GUEST_CONTROL1391 ReturnComNotImplemented();1392 #else1393 LogFlowThisFuncEnter();1394 1395 CheckComArgOutSafeArrayPointerValid(aFiles);1396 1397 AutoCaller autoCaller(this);1398 if (FAILED(autoCaller.rc())) return autoCaller.rc();1399 1400 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);1401 1402 SafeIfaceArray<IGuestFile> collection(mData.mFiles);1403 collection.detachTo(ComSafeArrayOutArg(aFiles));1404 1405 LogFlowFuncLeaveRC(S_OK);1406 return S_OK;1407 #endif /* VBOX_WITH_GUEST_CONTROL */1408 }1409 1410 // private methods1411 /////////////////////////////////////////////////////////////////////////////1412 1413 int GuestSession::directoryClose(ComObjPtr<GuestDirectory> pDirectory)1414 {1415 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);1416 1417 for (SessionDirectories::iterator itDirs = mData.mDirectories.begin();1418 itDirs != mData.mDirectories.end(); ++itDirs)1419 {1420 if (pDirectory == (*itDirs))1421 {1422 mData.mDirectories.erase(itDirs);1423 return VINF_SUCCESS;1424 }1425 }1426 1427 return VERR_NOT_FOUND;1428 }1429 1430 int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags)1431 {1432 LogFlowThisFunc(("strPath=%s, uMode=%x, uFlags=%x\n",1433 strPath.c_str(), uMode, uFlags));1434 1435 GuestProcessStartupInfo procInfo;1436 procInfo.mName = Utf8StrFmt(tr("Creating directory \"%s\"", strPath.c_str()));1437 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKDIR);1438 procInfo.mFlags = ProcessCreateFlag_Hidden;1439 1440 int rc = VINF_SUCCESS;1441 1442 /* Construct arguments. */1443 if (uFlags & DirectoryCreateFlag_Parents)1444 procInfo.mArguments.push_back(Utf8Str("--parents")); /* We also want to create the parent directories. */1445 if (uMode)1446 {1447 procInfo.mArguments.push_back(Utf8Str("--mode")); /* Set the creation mode. */1448 1449 char szMode[16];1450 if (RTStrPrintf(szMode, sizeof(szMode), "%o", uMode))1451 {1452 procInfo.mArguments.push_back(Utf8Str(szMode));1453 }1454 else1455 rc = VERR_INVALID_PARAMETER;1456 }1457 procInfo.mArguments.push_back(strPath); /* The directory we want to create. */1458 1459 ComObjPtr<GuestProcess> pProcess;1460 rc = processCreateExInteral(procInfo, pProcess);1461 if (RT_SUCCESS(rc))1462 rc = pProcess->startProcess();1463 if (RT_SUCCESS(rc))1464 {1465 GuestProcessWaitResult waitRes;1466 rc = pProcess->waitFor(ProcessWaitForFlag_Terminate, 30 * 1000 /* Timeout */, waitRes);1467 if (RT_SUCCESS(rc))1468 {1469 ProcessStatus_T procStatus;1470 HRESULT hr = pProcess->COMGETTER(Status)(&procStatus);1471 ComAssertComRC(hr);1472 if (procStatus == ProcessStatus_TerminatedNormally)1473 {1474 LONG lExitCode;1475 pProcess->COMGETTER(ExitCode)(&lExitCode);1476 if (lExitCode != 0)1477 return VERR_CANT_CREATE;1478 }1479 else1480 rc = VERR_BROKEN_PIPE; /** @todo Find a better rc. */1481 }1482 }1483 1484 LogFlowFuncLeaveRC(rc);1485 return rc;1486 }1487 1488 int GuestSession::directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)1489 {1490 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));1491 1492 int rc = fsQueryInfoInternal(strPath, objData);1493 if (RT_SUCCESS(rc))1494 {1495 rc = objData.mType == FsObjType_Directory1496 ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;1497 }1498 1499 LogFlowFuncLeaveRC(rc);1500 return rc;1501 }1502 1503 int GuestSession::objectCreateTempInternal(Utf8Str strTemplate,1504 Utf8Str strPath,1505 bool fDirectory,1506 Utf8Str &strName, int *prc)1507 {1508 GuestProcessStartupInfo procInfo;1509 GuestProcessStream streamOut;1510 ComObjPtr<GuestProcess> pProcess;1511 int rc = VINF_SUCCESS;1512 1513 if (fDirectory)1514 procInfo.mName = Utf8StrFmt(tr("Creating temporary directory from template \"%s\"",1515 strTemplate.c_str()));1516 else1517 procInfo.mName = Utf8StrFmt(tr("Creating temporary file from template \"%s\"",1518 strTemplate.c_str()));1519 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);1520 procInfo.mFlags = ProcessCreateFlag_Hidden1521 | ProcessCreateFlag_WaitForStdOut;1522 /* Construct arguments. */1523 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));1524 if (fDirectory)1525 procInfo.mArguments.push_back(Utf8Str("-d"));1526 if (strPath.length()) /* Otherwise use /tmp or equivalent. */1527 {1528 procInfo.mArguments.push_back(Utf8Str("-t"));1529 procInfo.mArguments.push_back(strPath);1530 }1531 procInfo.mArguments.push_back(strTemplate);1532 1533 rc = processCreateExInteral(procInfo, pProcess);1534 if (RT_SUCCESS(rc))1535 {1536 GuestProcessWaitResult waitRes;1537 BYTE byBuf[_64K];1538 size_t cbRead;1539 1540 for (;;)1541 {1542 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,1543 30 * 1000 /* Timeout */, waitRes);1544 if ( RT_FAILURE(rc)1545 || waitRes.mResult == ProcessWaitResult_Terminate1546 || waitRes.mResult == ProcessWaitResult_Error1547 || waitRes.mResult == ProcessWaitResult_Timeout)1548 {1549 break;1550 }1551 1552 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),1553 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),1554 &cbRead);1555 if (RT_FAILURE(rc))1556 break;1557 1558 if (cbRead)1559 {1560 rc = streamOut.AddData(byBuf, cbRead);1561 if (RT_FAILURE(rc))1562 break;1563 }1564 }1565 1566 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n",1567 rc, cbRead, streamOut.GetSize()));1568 }1569 else1570 LogThisFunc(("Error while starting temporary object creation tool on guest: %Rrc\n", rc));1571 if (RT_FAILURE(rc))1572 LogThisFunc(("Error while running temporary object creation tool: %Rrc\n", rc));1573 else if (!streamOut.GetSize())1574 {1575 LogThisFunc(("No return code after creating temporary object\n"));1576 rc = VERR_NO_DATA;1577 }1578 if (RT_SUCCESS(rc))1579 {1580 const char *pcszName;1581 int64_t i64rc;1582 GuestProcessStreamBlock streamBlock;1583 rc = streamOut.ParseBlock(streamBlock);1584 if (RT_SUCCESS(rc))1585 {1586 pcszName = streamBlock.GetString("name");1587 if (pcszName)1588 strName = pcszName;1589 else1590 {1591 LogThisFunc(("No name returned after creating temporary object\n"));1592 rc = VERR_NO_DATA;1593 }1594 if (RT_FAILURE(rc = streamBlock.GetInt64Ex("rc", &i64rc)))1595 LogThisFunc(("No return code after creating temporary object\n"));1596 }1597 if ( RT_SUCCESS(rc)1598 && ( i64rc == VERR_INVALID_PARAMETER1599 || i64rc == VERR_NOT_SUPPORTED))1600 rc = (int)i64rc;1601 if (RT_SUCCESS(rc))1602 *prc = (int)i64rc;1603 }1604 else1605 LogThisFunc(("Error while getting return code from creating temporary object: %Rrc\n", rc));1606 return rc;1607 }1608 1609 int GuestSession::directoryOpenInternal(const Utf8Str &strPath, const Utf8Str &strFilter,1610 uint32_t uFlags, ComObjPtr<GuestDirectory> &pDirectory)1611 {1612 LogFlowThisFunc(("strPath=%s, strPath=%s, uFlags=%x\n",1613 strPath.c_str(), strFilter.c_str(), uFlags));1614 1615 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);1616 1617 /* Create the directory object. */1618 HRESULT hr = pDirectory.createObject();1619 if (FAILED(hr))1620 return VERR_COM_UNEXPECTED;1621 1622 int rc = pDirectory->init(this /* Parent */,1623 strPath, strFilter, uFlags);1624 if (RT_FAILURE(rc))1625 return rc;1626 1627 /* Add the created directory to our vector. */1628 mData.mDirectories.push_back(pDirectory);1629 1630 LogFlowFunc(("Added new directory \"%s\" (Session: %RU32)\n",1631 strPath.c_str(), mData.mId));1632 1633 LogFlowFuncLeaveRC(rc);1634 return rc;1635 }1636 1637 int GuestSession::dispatchToProcess(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData)1638 {1639 LogFlowFuncEnter();1640 1641 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);1642 1643 uint32_t uProcessID = VBOX_GUESTCTRL_CONTEXTID_GET_PROCESS(uContextID);1644 #ifdef DEBUG1645 LogFlowFunc(("uProcessID=%RU32 (%RU32 total)\n",1646 uProcessID, mData.mProcesses.size()));1647 #endif1648 int rc;1649 SessionProcesses::const_iterator itProc1650 = mData.mProcesses.find(uProcessID);1651 if (itProc != mData.mProcesses.end())1652 {1653 ComObjPtr<GuestProcess> pProcess(itProc->second);1654 Assert(!pProcess.isNull());1655 1656 alock.release();1657 rc = pProcess->callbackDispatcher(uContextID, uFunction, pvData, cbData);1658 }1659 else1660 rc = VERR_NOT_FOUND;1661 1662 LogFlowFuncLeaveRC(rc);1663 return rc;1664 }1665 1666 int GuestSession::fileClose(ComObjPtr<GuestFile> pFile)1667 {1668 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);1669 1670 for (SessionFiles::iterator itFiles = mData.mFiles.begin();1671 itFiles != mData.mFiles.end(); ++itFiles)1672 {1673 if (pFile == (*itFiles))1674 {1675 mData.mFiles.erase(itFiles);1676 return VINF_SUCCESS;1677 }1678 }1679 1680 return VERR_NOT_FOUND;1681 }1682 1683 /**1684 * Implementation of FileRemove(). Can throw an exception due to the use of1685 * Utf8Str, Utf8StrFmt and std::vector near the beginning (and others?). The1686 * caller should catch this. On success, *prc will be set to the return code1687 * of the delete operation to distinguish between API and command failure.1688 */1689 int GuestSession::fileRemoveInternal(Utf8Str strPath, int *prc)1690 {1691 GuestProcessStartupInfo procInfo;1692 GuestProcessStream streamOut;1693 int rc = VINF_SUCCESS;1694 1695 AssertPtrReturn(prc, VERR_INVALID_POINTER);1696 procInfo.mName = Utf8StrFmt(tr("Removing file \"%s\"",1697 strPath.c_str()));1698 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_RM);1699 procInfo.mFlags = ProcessCreateFlag_Hidden1700 | ProcessCreateFlag_WaitForStdOut;1701 /* Construct arguments. */1702 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));1703 procInfo.mArguments.push_back(strPath); /* The directory we want to create. */1704 1705 ComObjPtr<GuestProcess> pProcess;1706 rc = processCreateExInteral(procInfo, pProcess);1707 if (RT_SUCCESS(rc))1708 rc = pProcess->startProcess();1709 if (RT_SUCCESS(rc))1710 {1711 GuestProcessWaitResult waitRes;1712 BYTE byBuf[_64K];1713 size_t cbRead;1714 1715 for (;;)1716 {1717 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,1718 30 * 1000 /* Timeout */, waitRes);1719 if ( RT_FAILURE(rc)1720 || waitRes.mResult == ProcessWaitResult_Terminate1721 || waitRes.mResult == ProcessWaitResult_Error1722 || waitRes.mResult == ProcessWaitResult_Timeout)1723 {1724 break;1725 }1726 1727 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),1728 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),1729 &cbRead);1730 if (RT_FAILURE(rc))1731 break;1732 1733 if (cbRead)1734 {1735 rc = streamOut.AddData(byBuf, cbRead);1736 if (RT_FAILURE(rc))1737 break;1738 }1739 }1740 1741 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n",1742 rc, cbRead, streamOut.GetSize()));1743 }1744 else1745 LogThisFunc(("Error starting delete tool on guest: %Rrc\n", rc));1746 if (RT_FAILURE(rc))1747 LogThisFunc(("Error running delete tool on guest: %Rrc\n", rc));1748 else if (!streamOut.GetSize())1749 {1750 LogThisFunc(("No return code after deleting file"));1751 rc = VERR_NO_DATA;1752 }1753 if (RT_SUCCESS(rc))1754 {1755 GuestProcessStreamBlock streamBlock;1756 int64_t i64rc;1757 rc = streamOut.ParseBlock(streamBlock);1758 streamBlock.GetString("fname");1759 rc = streamBlock.GetInt64Ex("rc", &i64rc);1760 if (RT_SUCCESS(rc))1761 *prc = (int)i64rc;1762 }1763 else1764 Log(("Error getting return code from deleting file: %Rrc\n", rc));1765 return rc;1766 }1767 1768 int GuestSession::fileOpenInternal(const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition,1769 uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile)1770 {1771 LogFlowThisFunc(("strPath=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%x, iOffset=%RI64\n",1772 strPath.c_str(), strOpenMode.c_str(), strDisposition.c_str(), uCreationMode, iOffset));1773 1774 /* Create the directory object. */1775 HRESULT hr = pFile.createObject();1776 if (FAILED(hr))1777 return VERR_COM_UNEXPECTED;1778 1779 /* Note: There will be a race between creating and getting/initing the directory1780 object here. */1781 int rc = pFile->init(this /* Parent */,1782 strPath, strOpenMode, strDisposition, uCreationMode, iOffset);1783 if (RT_FAILURE(rc))1784 return rc;1785 1786 /* Add the created directory to our vector. */1787 mData.mFiles.push_back(pFile);1788 1789 LogFlowFunc(("Added new file \"%s\" (Session: %RU32\n",1790 strPath.c_str(), mData.mId));1791 1792 LogFlowFuncLeaveRC(rc);1793 return rc;1794 }1795 1796 int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)1797 {1798 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));1799 1800 int rc = fsQueryInfoInternal(strPath, objData);1801 if (RT_SUCCESS(rc))1802 {1803 rc = objData.mType == FsObjType_File1804 ? VINF_SUCCESS : VERR_NOT_A_FILE;1805 }1806 1807 LogFlowFuncLeaveRC(rc);1808 return rc;1809 }1810 1811 int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize)1812 {1813 AssertPtrReturn(pllSize, VERR_INVALID_POINTER);1814 1815 GuestFsObjData objData;1816 int rc = fileQueryInfoInternal(strPath, objData);1817 if (RT_SUCCESS(rc))1818 {1819 if (objData.mType == FsObjType_File)1820 *pllSize = objData.mObjectSize;1821 else1822 rc = VERR_NOT_A_FILE;1823 }1824 1825 return rc;1826 }1827 1828 int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)1829 {1830 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));1831 1832 GuestProcessStartupInfo procInfo;1833 procInfo.mName = Utf8StrFmt(tr("Querying info for \"%s\""), strPath.c_str());1834 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT);1835 procInfo.mFlags = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;1836 1837 /* Construct arguments. */1838 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));1839 procInfo.mArguments.push_back(strPath);1840 1841 GuestProcessStream streamOut;1842 1843 ComObjPtr<GuestProcess> pProcess;1844 int rc = processCreateExInteral(procInfo, pProcess);1845 if (RT_SUCCESS(rc))1846 rc = pProcess->startProcess();1847 if (RT_SUCCESS(rc))1848 {1849 GuestProcessWaitResult waitRes;1850 BYTE byBuf[_64K];1851 size_t cbRead = 0;1852 1853 /** @todo Merge with GuestDirectory::read. */1854 for (;;)1855 {1856 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,1857 30 * 1000 /* Timeout */, waitRes);1858 if ( RT_FAILURE(rc)1859 || waitRes.mResult == ProcessWaitResult_Terminate1860 || waitRes.mResult == ProcessWaitResult_Error1861 || waitRes.mResult == ProcessWaitResult_Timeout)1862 {1863 break;1864 }1865 1866 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),1867 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),1868 &cbRead);1869 if (RT_FAILURE(rc))1870 break;1871 1872 if (cbRead)1873 {1874 rc = streamOut.AddData(byBuf, cbRead);1875 if (RT_FAILURE(rc))1876 break;1877 }1878 }1879 1880 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64, cbStreamOut=%RU32\n",1881 rc, cbRead, streamOut.GetSize()));1882 }1883 1884 if (RT_SUCCESS(rc))1885 {1886 GuestProcessStreamBlock streamBlock;1887 rc = streamOut.ParseBlock(streamBlock);1888 if (RT_SUCCESS(rc))1889 {1890 rc = objData.FromStat(streamBlock);1891 }1892 else1893 AssertMsgFailed(("Parsing stream block failed: %Rrc\n", rc));1894 }1895 1896 LogFlowFuncLeaveRC(rc);1897 return rc;1898 }1899 1900 const GuestCredentials& GuestSession::getCredentials(void)1901 {1902 return mData.mCredentials;1903 }1904 1905 const GuestEnvironment& GuestSession::getEnvironment(void)1906 {1907 return mData.mEnvironment;1908 }1909 1910 Utf8Str GuestSession::getName(void)1911 {1912 return mData.mName;1913 }1914 1915 int GuestSession::processClose(ComObjPtr<GuestProcess> pProcess)1916 {1917 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);1918 1919 for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();1920 itProcs != mData.mProcesses.end(); ++itProcs)1921 {1922 if (pProcess == itProcs->second)1923 {1924 LogFlowFunc(("Removing process (Session: %RU32) with process ID=%RU32, guest PID=%RU32 (now total %ld processes)\n",1925 mData.mId, itProcs->second->getProcessID(), itProcs->second->getPID(), mData.mProcesses.size() - 1));1926 1927 mData.mProcesses.erase(itProcs);1928 return VINF_SUCCESS;1929 }1930 }1931 1932 return VERR_NOT_FOUND;1933 }1934 1935 /**1936 * Creates but does *not* start the process yet. See GuestProcess::startProcess() or1937 * GuestProcess::startProcessAsync() for that.1938 *1939 * @return IPRT status code.1940 * @param procInfo1941 * @param pProcess1942 */1943 int GuestSession::processCreateExInteral(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)1944 {1945 LogFlowFunc(("mCmd=%s, mFlags=%x, mTimeoutMS=%RU32\n",1946 procInfo.mCommand.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));1947 #ifdef DEBUG1948 if (procInfo.mArguments.size())1949 {1950 LogFlowFunc(("Arguments:"));1951 ProcessArguments::const_iterator it = procInfo.mArguments.begin();1952 while (it != procInfo.mArguments.end())1953 {1954 LogFlow((" %s", (*it).c_str()));1955 it++;1956 }1957 LogFlow(("\n"));1958 }1959 #endif1960 1961 /* Validate flags. */1962 if (procInfo.mFlags)1963 {1964 if ( !(procInfo.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)1965 && !(procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)1966 && !(procInfo.mFlags & ProcessCreateFlag_Hidden)1967 && !(procInfo.mFlags & ProcessCreateFlag_NoProfile)1968 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)1969 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdErr))1970 {1971 return VERR_INVALID_PARAMETER;1972 }1973 }1974 1975 /* Adjust timeout. If set to 0, we define1976 * an infinite timeout. */1977 if (procInfo.mTimeoutMS == 0)1978 procInfo.mTimeoutMS = UINT32_MAX;1979 1980 /** @tood Implement process priority + affinity. */1981 1982 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);1983 1984 int rc = VERR_MAX_PROCS_REACHED;1985 if (mData.mProcesses.size() >= VBOX_GUESTCTRL_MAX_PROCESSES)1986 return rc;1987 1988 /* Create a new (host-based) process ID and assign it. */1989 uint32_t uNewProcessID = 0;1990 ULONG uTries = 0;1991 1992 for (;;)1993 {1994 /* Is the context ID already used? */1995 if (!processExists(uNewProcessID, NULL /* pProgress */))1996 {1997 /* Callback with context ID was not found. This means1998 * we can use this context ID for our new callback we want1999 * to add below. */2000 rc = VINF_SUCCESS;2001 break;2002 }2003 uNewProcessID++;2004 if (uNewProcessID == VBOX_GUESTCTRL_MAX_PROCESSES)2005 uNewProcessID = 0;2006 2007 if (++uTries == UINT32_MAX)2008 break; /* Don't try too hard. */2009 }2010 2011 if (RT_FAILURE(rc))2012 return rc;2013 2014 /* Create the process object. */2015 HRESULT hr = pProcess.createObject();2016 if (FAILED(hr))2017 return VERR_COM_UNEXPECTED;2018 2019 rc = pProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */,2020 uNewProcessID, procInfo);2021 if (RT_FAILURE(rc))2022 return rc;2023 2024 /* Add the created process to our map. */2025 mData.mProcesses[uNewProcessID] = pProcess;2026 2027 LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes)\n",2028 mData.mId, uNewProcessID, mData.mProcesses.size()));2029 2030 return rc;2031 }2032 2033 inline bool GuestSession::processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess)2034 {2035 SessionProcesses::const_iterator it = mData.mProcesses.find(uProcessID);2036 if (it != mData.mProcesses.end())2037 {2038 if (pProcess)2039 *pProcess = it->second;2040 return true;2041 }2042 return false;2043 }2044 2045 inline int GuestSession::processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess)2046 {2047 AssertReturn(uPID, false);2048 /* pProcess is optional. */2049 2050 SessionProcesses::iterator it = mData.mProcesses.begin();2051 for (; it != mData.mProcesses.end(); it++)2052 {2053 ComObjPtr<GuestProcess> pCurProc = it->second;2054 AutoCaller procCaller(pCurProc);2055 if (procCaller.rc())2056 return VERR_COM_INVALID_OBJECT_STATE;2057 2058 if (it->second->getPID() == uPID)2059 {2060 if (pProcess)2061 *pProcess = pCurProc;2062 return VINF_SUCCESS;2063 }2064 }2065 2066 return VERR_NOT_FOUND;2067 }2068 2069 int GuestSession::startTaskAsync(const Utf8Str &strTaskDesc,2070 GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress)2071 {2072 LogFlowThisFunc(("strTaskDesc=%s, pTask=%p\n", strTaskDesc.c_str(), pTask));2073 2074 AssertPtrReturn(pTask, VERR_INVALID_POINTER);2075 2076 /* Create the progress object. */2077 HRESULT hr = pProgress.createObject();2078 if (FAILED(hr))2079 return VERR_COM_UNEXPECTED;2080 2081 hr = pProgress->init(static_cast<IGuestSession*>(this),2082 Bstr(strTaskDesc).raw(),2083 TRUE /* aCancelable */);2084 if (FAILED(hr))2085 return VERR_COM_UNEXPECTED;2086 2087 /* Initialize our worker task. */2088 std::auto_ptr<GuestSessionTask> task(pTask);2089 2090 int rc = task->RunAsync(strTaskDesc, pProgress);2091 if (RT_FAILURE(rc))2092 return rc;2093 2094 /* Don't destruct on success. */2095 task.release();2096 2097 LogFlowFuncLeaveRC(rc);2098 return rc;2099 }2100 2101 /**2102 * Queries/collects information prior to establishing a guest session.2103 * This is necessary to know which guest control protocol version to use,2104 * among other things (later).2105 *2106 * @return IPRT status code.2107 */2108 int GuestSession::queryInfo(void)2109 {2110 #if 12111 /* Since the new functions were not implemented yet, force Main to use protocol ver 1. */2112 mData.mProtocolVersion = 1;2113 #else2114 /*2115 * Try querying the guest control protocol version running on the guest.2116 * This is done using the Guest Additions version2117 */2118 ComObjPtr<Guest> pGuest = mData.mParent;2119 Assert(!pGuest.isNull());2120 2121 uint32_t uVerAdditions = pGuest->getAdditionsVersion();2122 mData.mProtocolVersion = ( VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions) >= 42123 && VBOX_FULL_VERSION_GET_MINOR(uVerAdditions) >= 2) /** @todo What's about v5.0 ? */2124 ? 2 /* Guest control 2.0. */2125 : 1; /* Legacy guest control (VBox < 4.2). */2126 /* Build revision is ignored. */2127 2128 /* Tell the user but don't bitch too often. */2129 static short s_gctrlLegacyWarning = 0;2130 if (s_gctrlLegacyWarning++ < 3) /** @todo Find a bit nicer text. */2131 LogRel((tr("Warning: Guest Additions are older (%ld.%ld) than host capabilities for guest control, please upgrade them. Using protocol version %ld now\n"),2132 VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions), VBOX_FULL_VERSION_GET_MINOR(uVerAdditions), mData.mProtocolVersion));2133 #endif2134 return VINF_SUCCESS;2135 }2136 2137 // implementation of public methods2138 /////////////////////////////////////////////////////////////////////////////2139 2140 STDMETHODIMP GuestSession::Close(void)2141 {2142 #ifndef VBOX_WITH_GUEST_CONTROL2143 ReturnComNotImplemented();2144 #else2145 LogFlowThisFuncEnter();2146 2147 uninit();2148 2149 LogFlowFuncLeaveRC(S_OK);2150 return S_OK;2151 #endif /* VBOX_WITH_GUEST_CONTROL */2152 }2153 2154 STDMETHODIMP GuestSession::CopyFrom(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)2155 {2156 #ifndef VBOX_WITH_GUEST_CONTROL2157 ReturnComNotImplemented();2158 #else2159 CheckComArgStrNotEmptyOrNull(aSource);2160 CheckComArgStrNotEmptyOrNull(aDest);2161 CheckComArgOutPointerValid(aProgress);2162 2163 LogFlowThisFuncEnter();2164 2165 if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))2166 return setError(E_INVALIDARG, tr("No source specified"));2167 if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))2168 return setError(E_INVALIDARG, tr("No destination specified"));2169 2170 AutoCaller autoCaller(this);2171 if (FAILED(autoCaller.rc())) return autoCaller.rc();2172 2173 uint32_t fFlags = CopyFileFlag_None;2174 if (aFlags)2175 {2176 com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));2177 for (size_t i = 0; i < flags.size(); i++)2178 fFlags |= flags[i];2179 }2180 2181 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);2182 2183 HRESULT hr = S_OK;2184 2185 ComObjPtr<Progress> pProgress;2186 SessionTaskCopyFrom *pTask = new SessionTaskCopyFrom(this /* GuestSession */,2187 Utf8Str(aSource), Utf8Str(aDest), fFlags);2188 AssertPtrReturn(pTask, VERR_NO_MEMORY);2189 int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from guest to \"%ls\" on the host"), aSource, aDest),2190 pTask, pProgress);2191 if (RT_SUCCESS(rc))2192 {2193 /* Return progress to the caller. */2194 hr = pProgress.queryInterfaceTo(aProgress);2195 }2196 else2197 hr = setError(VBOX_E_IPRT_ERROR,2198 tr("Starting task for copying file \"%ls\" from guest to \"%ls\" on the host failed: %Rrc"), rc);2199 return hr;2200 #endif /* VBOX_WITH_GUEST_CONTROL */2201 }2202 2203 STDMETHODIMP GuestSession::CopyTo(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)2204 {2205 #ifndef VBOX_WITH_GUEST_CONTROL2206 ReturnComNotImplemented();2207 #else2208 CheckComArgStrNotEmptyOrNull(aSource);2209 CheckComArgStrNotEmptyOrNull(aDest);2210 CheckComArgOutPointerValid(aProgress);2211 2212 LogFlowThisFuncEnter();2213 2214 if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))2215 return setError(E_INVALIDARG, tr("No source specified"));2216 if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))2217 return setError(E_INVALIDARG, tr("No destination specified"));2218 2219 AutoCaller autoCaller(this);2220 if (FAILED(autoCaller.rc())) return autoCaller.rc();2221 2222 uint32_t fFlags = CopyFileFlag_None;2223 if (aFlags)2224 {2225 com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));2226 for (size_t i = 0; i < flags.size(); i++)2227 fFlags |= flags[i];2228 }2229 2230 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);2231 2232 HRESULT hr = S_OK;2233 2234 ComObjPtr<Progress> pProgress;2235 SessionTaskCopyTo *pTask = new SessionTaskCopyTo(this /* GuestSession */,2236 Utf8Str(aSource), Utf8Str(aDest), fFlags);2237 AssertPtrReturn(pTask, VERR_NO_MEMORY);2238 int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from host to \"%ls\" on the guest"), aSource, aDest),2239 pTask, pProgress);2240 if (RT_SUCCESS(rc))2241 {2242 /* Return progress to the caller. */2243 hr = pProgress.queryInterfaceTo(aProgress);2244 }2245 else2246 hr = setError(VBOX_E_IPRT_ERROR,2247 tr("Starting task for copying file \"%ls\" from host to \"%ls\" on the guest failed: %Rrc"), rc);2248 return hr;2249 #endif /* VBOX_WITH_GUEST_CONTROL */2250 }2251 2252 STDMETHODIMP GuestSession::DirectoryCreate(IN_BSTR aPath, ULONG aMode,2253 ComSafeArrayIn(DirectoryCreateFlag_T, aFlags))2254 {2255 #ifndef VBOX_WITH_GUEST_CONTROL2256 ReturnComNotImplemented();2257 #else2258 LogFlowThisFuncEnter();2259 2260 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))2261 return setError(E_INVALIDARG, tr("No directory to create specified"));2262 2263 AutoCaller autoCaller(this);2264 if (FAILED(autoCaller.rc())) return autoCaller.rc();2265 2266 uint32_t fFlags = DirectoryCreateFlag_None;2267 if (aFlags)2268 {2269 com::SafeArray<DirectoryCreateFlag_T> flags(ComSafeArrayInArg(aFlags));2270 for (size_t i = 0; i < flags.size(); i++)2271 fFlags |= flags[i];2272 2273 if (fFlags)2274 {2275 if (!(fFlags & DirectoryCreateFlag_Parents))2276 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), fFlags);2277 }2278 }2279 2280 HRESULT hr = S_OK;2281 2282 ComObjPtr <GuestDirectory> pDirectory;2283 int rc = directoryCreateInternal(Utf8Str(aPath), (uint32_t)aMode, fFlags);2284 if (RT_FAILURE(rc))2285 {2286 switch (rc)2287 {2288 case VERR_INVALID_PARAMETER:2289 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Invalid parameters given"));2290 break;2291 2292 case VERR_BROKEN_PIPE:2293 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Unexpectedly aborted"));2294 break;2295 2296 case VERR_CANT_CREATE:2297 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Could not create directory"));2298 break;2299 2300 default:2301 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);2302 break;2303 }2304 }2305 2306 return hr;2307 #endif /* VBOX_WITH_GUEST_CONTROL */2308 }2309 2310 STDMETHODIMP GuestSession::DirectoryCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, BSTR *aDirectory)2311 {2312 #ifndef VBOX_WITH_GUEST_CONTROL2313 ReturnComNotImplemented();2314 #else2315 LogFlowThisFuncEnter();2316 2317 if (RT_UNLIKELY((aTemplate) == NULL || *(aTemplate) == '\0'))2318 return setError(E_INVALIDARG, tr("No file to remove specified"));2319 2320 AutoCaller autoCaller(this);2321 if (FAILED(autoCaller.rc())) return autoCaller.rc();2322 2323 int rc = VINF_SUCCESS;2324 2325 try /* Can this be done without exceptions? */2326 {2327 Utf8Str strName;2328 if (RT_FAILURE(objectCreateTempInternal(Utf8Str(aTemplate),2329 Utf8Str(aPath),2330 true, strName, &rc)))2331 return E_FAIL;2332 HRESULT hrc = rc == VERR_INVALID_PARAMETER ? E_INVALIDARG2333 : rc == VERR_NOT_SUPPORTED ? VBOX_E_NOT_SUPPORTED2334 : RT_FAILURE(rc) ? VBOX_E_IPRT_ERROR2335 : S_OK;2336 if (FAILED(hrc))2337 return setError(hrc, tr("Temporary directory creation failed: %Rrc"),2338 rc);2339 strName.cloneTo(aDirectory);2340 return S_OK;2341 }2342 catch (...)2343 {2344 return E_OUTOFMEMORY;2345 }2346 #endif /* VBOX_WITH_GUEST_CONTROL */2347 }2348 2349 STDMETHODIMP GuestSession::DirectoryExists(IN_BSTR aPath, BOOL *aExists)2350 {2351 #ifndef VBOX_WITH_GUEST_CONTROL2352 ReturnComNotImplemented();2353 #else2354 LogFlowThisFuncEnter();2355 2356 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))2357 return setError(E_INVALIDARG, tr("No directory to check existence for specified"));2358 CheckComArgOutPointerValid(aExists);2359 2360 AutoCaller autoCaller(this);2361 if (FAILED(autoCaller.rc())) return autoCaller.rc();2362 2363 HRESULT hr = S_OK;2364 2365 GuestFsObjData objData;2366 int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);2367 if (RT_SUCCESS(rc))2368 {2369 *aExists = objData.mType == FsObjType_Directory;2370 }2371 else2372 {2373 switch (rc)2374 {2375 /** @todo Add more errors here! */2376 2377 default:2378 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence failed: %Rrc"), rc);2379 break;2380 }2381 }2382 2383 return hr;2384 #endif /* VBOX_WITH_GUEST_CONTROL */2385 }2386 2387 STDMETHODIMP GuestSession::DirectoryOpen(IN_BSTR aPath, IN_BSTR aFilter, ComSafeArrayIn(DirectoryOpenFlag_T, aFlags), IGuestDirectory **aDirectory)2388 {2389 #ifndef VBOX_WITH_GUEST_CONTROL2390 ReturnComNotImplemented();2391 #else2392 LogFlowThisFuncEnter();2393 2394 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))2395 return setError(E_INVALIDARG, tr("No directory to open specified"));2396 if (RT_UNLIKELY((aFilter) != NULL && *(aFilter) != '\0'))2397 return setError(E_INVALIDARG, tr("Directory filters not implemented yet"));2398 2399 CheckComArgOutPointerValid(aDirectory);2400 2401 AutoCaller autoCaller(this);2402 if (FAILED(autoCaller.rc())) return autoCaller.rc();2403 2404 uint32_t fFlags = DirectoryOpenFlag_None;2405 if (aFlags)2406 {2407 com::SafeArray<DirectoryOpenFlag_T> flags(ComSafeArrayInArg(aFlags));2408 for (size_t i = 0; i < flags.size(); i++)2409 fFlags |= flags[i];2410 2411 if (fFlags)2412 return setError(E_INVALIDARG, tr("Open flags (%#x) not implemented yet"), fFlags);2413 }2414 2415 HRESULT hr = S_OK;2416 2417 ComObjPtr <GuestDirectory> pDirectory;2418 int rc = directoryOpenInternal(Utf8Str(aPath), Utf8Str(aFilter), fFlags, pDirectory);2419 if (RT_SUCCESS(rc))2420 {2421 if (aDirectory)2422 {2423 /* Return directory object to the caller. */2424 hr = pDirectory.queryInterfaceTo(aDirectory);2425 }2426 else2427 {2428 rc = directoryClose(pDirectory);2429 if (RT_FAILURE(rc))2430 hr = setError(VBOX_E_IPRT_ERROR, tr("Unable to close directory object, rc=%Rrc"), rc);2431 }2432 }2433 else2434 {2435 switch (rc)2436 {2437 case VERR_INVALID_PARAMETER:2438 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Invalid parameters given"));2439 break;2440 2441 case VERR_BROKEN_PIPE:2442 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Unexpectedly aborted"));2443 break;2444 2445 default:2446 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: %Rrc"), rc);2447 break;2448 }2449 }2450 2451 return hr;2452 #endif /* VBOX_WITH_GUEST_CONTROL */2453 }2454 2455 STDMETHODIMP GuestSession::DirectoryQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)2456 {2457 #ifndef VBOX_WITH_GUEST_CONTROL2458 ReturnComNotImplemented();2459 #else2460 LogFlowThisFuncEnter();2461 2462 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))2463 return setError(E_INVALIDARG, tr("No directory to query information for specified"));2464 CheckComArgOutPointerValid(aInfo);2465 2466 AutoCaller autoCaller(this);2467 if (FAILED(autoCaller.rc())) return autoCaller.rc();2468 2469 HRESULT hr = S_OK;2470 2471 GuestFsObjData objData;2472 int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData);2473 if (RT_SUCCESS(rc))2474 {2475 if (objData.mType == FsObjType_Directory)2476 {2477 ComObjPtr<GuestFsObjInfo> pFsObjInfo;2478 hr = pFsObjInfo.createObject();2479 if (FAILED(hr))2480 return VERR_COM_UNEXPECTED;2481 2482 rc = pFsObjInfo->init(objData);2483 if (RT_SUCCESS(rc))2484 hr = pFsObjInfo.queryInterfaceTo(aInfo);2485 }2486 }2487 2488 if (RT_FAILURE(rc))2489 {2490 switch (rc)2491 {2492 /** @todo Add more errors here! */2493 2494 case VERR_NOT_A_DIRECTORY:2495 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a directory"));2496 break;2497 2498 default:2499 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information failed: %Rrc"), rc);2500 break;2501 }2502 }2503 2504 return hr;2505 #endif /* VBOX_WITH_GUEST_CONTROL */2506 }2507 2508 STDMETHODIMP GuestSession::DirectoryRemove(IN_BSTR aPath)2509 {2510 #ifndef VBOX_WITH_GUEST_CONTROL2511 ReturnComNotImplemented();2512 #else2513 LogFlowThisFuncEnter();2514 2515 AutoCaller autoCaller(this);2516 if (FAILED(autoCaller.rc())) return autoCaller.rc();2517 2518 ReturnComNotImplemented();2519 #endif /* VBOX_WITH_GUEST_CONTROL */2520 }2521 2522 STDMETHODIMP GuestSession::DirectoryRemoveRecursive(IN_BSTR aPath, ComSafeArrayIn(DirectoryRemoveRecFlag_T, aFlags), IProgress **aProgress)2523 {2524 #ifndef VBOX_WITH_GUEST_CONTROL2525 ReturnComNotImplemented();2526 #else2527 LogFlowThisFuncEnter();2528 2529 AutoCaller autoCaller(this);2530 if (FAILED(autoCaller.rc())) return autoCaller.rc();2531 2532 ReturnComNotImplemented();2533 #endif /* VBOX_WITH_GUEST_CONTROL */2534 }2535 2536 STDMETHODIMP GuestSession::DirectoryRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))2537 {2538 #ifndef VBOX_WITH_GUEST_CONTROL2539 ReturnComNotImplemented();2540 #else2541 LogFlowThisFuncEnter();2542 2543 AutoCaller autoCaller(this);2544 if (FAILED(autoCaller.rc())) return autoCaller.rc();2545 2546 ReturnComNotImplemented();2547 #endif /* VBOX_WITH_GUEST_CONTROL */2548 }2549 2550 STDMETHODIMP GuestSession::DirectorySetACL(IN_BSTR aPath, IN_BSTR aACL)2551 {2552 #ifndef VBOX_WITH_GUEST_CONTROL2553 ReturnComNotImplemented();2554 #else2555 LogFlowThisFuncEnter();2556 2557 AutoCaller autoCaller(this);2558 if (FAILED(autoCaller.rc())) return autoCaller.rc();2559 2560 ReturnComNotImplemented();2561 #endif /* VBOX_WITH_GUEST_CONTROL */2562 }2563 2564 STDMETHODIMP GuestSession::EnvironmentClear(void)2565 {2566 #ifndef VBOX_WITH_GUEST_CONTROL2567 ReturnComNotImplemented();2568 #else2569 LogFlowThisFuncEnter();2570 2571 AutoCaller autoCaller(this);2572 if (FAILED(autoCaller.rc())) return autoCaller.rc();2573 2574 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);2575 2576 mData.mEnvironment.Clear();2577 2578 LogFlowFuncLeaveRC(S_OK);2579 return S_OK;2580 #endif /* VBOX_WITH_GUEST_CONTROL */2581 }2582 2583 STDMETHODIMP GuestSession::EnvironmentGet(IN_BSTR aName, BSTR *aValue)2584 {2585 #ifndef VBOX_WITH_GUEST_CONTROL2586 ReturnComNotImplemented();2587 #else2588 LogFlowThisFuncEnter();2589 2590 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))2591 return setError(E_INVALIDARG, tr("No value name specified"));2592 2593 CheckComArgOutPointerValid(aValue);2594 2595 AutoCaller autoCaller(this);2596 if (FAILED(autoCaller.rc())) return autoCaller.rc();2597 2598 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);2599 2600 Bstr strValue(mData.mEnvironment.Get(Utf8Str(aName)));2601 strValue.cloneTo(aValue);2602 2603 LogFlowFuncLeaveRC(S_OK);2604 return S_OK;2605 #endif /* VBOX_WITH_GUEST_CONTROL */2606 }2607 2608 STDMETHODIMP GuestSession::EnvironmentSet(IN_BSTR aName, IN_BSTR aValue)2609 {2610 #ifndef VBOX_WITH_GUEST_CONTROL2611 ReturnComNotImplemented();2612 #else2613 LogFlowThisFuncEnter();2614 2615 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))2616 return setError(E_INVALIDARG, tr("No value name specified"));2617 2618 AutoCaller autoCaller(this);2619 if (FAILED(autoCaller.rc())) return autoCaller.rc();2620 2621 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);2622 2623 int rc = mData.mEnvironment.Set(Utf8Str(aName), Utf8Str(aValue));2624 2625 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;2626 LogFlowFuncLeaveRC(hr);2627 return hr;2628 #endif /* VBOX_WITH_GUEST_CONTROL */2629 }2630 2631 STDMETHODIMP GuestSession::EnvironmentUnset(IN_BSTR aName)2632 {2633 #ifndef VBOX_WITH_GUEST_CONTROL2634 ReturnComNotImplemented();2635 #else2636 LogFlowThisFuncEnter();2637 2638 AutoCaller autoCaller(this);2639 if (FAILED(autoCaller.rc())) return autoCaller.rc();2640 2641 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);2642 2643 mData.mEnvironment.Unset(Utf8Str(aName));2644 2645 LogFlowFuncLeaveRC(S_OK);2646 return S_OK;2647 #endif /* VBOX_WITH_GUEST_CONTROL */2648 }2649 2650 STDMETHODIMP GuestSession::FileCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, IGuestFile **aFile)2651 {2652 #ifndef VBOX_WITH_GUEST_CONTROL2653 ReturnComNotImplemented();2654 #else2655 LogFlowThisFuncEnter();2656 2657 AutoCaller autoCaller(this);2658 if (FAILED(autoCaller.rc())) return autoCaller.rc();2659 2660 ReturnComNotImplemented();2661 #endif /* VBOX_WITH_GUEST_CONTROL */2662 }2663 2664 STDMETHODIMP GuestSession::FileExists(IN_BSTR aPath, BOOL *aExists)2665 {2666 #ifndef VBOX_WITH_GUEST_CONTROL2667 ReturnComNotImplemented();2668 #else2669 LogFlowThisFuncEnter();2670 2671 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))2672 return setError(E_INVALIDARG, tr("No file to check existence for specified"));2673 CheckComArgOutPointerValid(aExists);2674 2675 AutoCaller autoCaller(this);2676 if (FAILED(autoCaller.rc())) return autoCaller.rc();2677 2678 HRESULT hr = S_OK;2679 2680 GuestFsObjData objData;2681 int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);2682 if (RT_SUCCESS(rc))2683 {2684 *aExists = objData.mType == FsObjType_File;2685 }2686 else2687 {2688 switch (rc)2689 {2690 /** @todo Add more errors here! */2691 2692 default:2693 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file existence failed: %Rrc"), rc);2694 break;2695 }2696 }2697 2698 return hr;2699 #endif /* VBOX_WITH_GUEST_CONTROL */2700 }2701 2702 STDMETHODIMP GuestSession::FileRemove(IN_BSTR aPath)2703 {2704 #ifndef VBOX_WITH_GUEST_CONTROL2705 ReturnComNotImplemented();2706 #else2707 LogFlowThisFuncEnter();2708 2709 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))2710 return setError(E_INVALIDARG, tr("No file to remove specified"));2711 2712 AutoCaller autoCaller(this);2713 if (FAILED(autoCaller.rc())) return autoCaller.rc();2714 2715 try /* Can this be done without exceptions? */2716 {2717 int rc2;2718 int rc = fileRemoveInternal(Utf8Str(aPath), &rc2);2719 if (RT_FAILURE((rc)))2720 return setError(E_FAIL,2721 tr("Internal error deleting file: %Rrc"), rc);2722 else if (RT_FAILURE((rc2)))2723 return setError(VBOX_E_IPRT_ERROR,2724 tr("File deletion on guest returned: %Rrc"), rc2);2725 }2726 catch (...)2727 {2728 return E_OUTOFMEMORY;2729 }2730 return S_OK;2731 #endif /* VBOX_WITH_GUEST_CONTROL */2732 }2733 2734 STDMETHODIMP GuestSession::FileOpen(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, ULONG aCreationMode, LONG64 aOffset, IGuestFile **aFile)2735 {2736 #ifndef VBOX_WITH_GUEST_CONTROL2737 ReturnComNotImplemented();2738 #else2739 LogFlowThisFuncEnter();2740 2741 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))2742 return setError(E_INVALIDARG, tr("No file to open specified"));2743 if (RT_UNLIKELY((aOpenMode) == NULL || *(aOpenMode) == '\0'))2744 return setError(E_INVALIDARG, tr("No open mode specified"));2745 if (RT_UNLIKELY((aDisposition) == NULL || *(aDisposition) == '\0'))2746 return setError(E_INVALIDARG, tr("No disposition mode specified"));2747 2748 CheckComArgOutPointerValid(aFile);2749 2750 AutoCaller autoCaller(this);2751 if (FAILED(autoCaller.rc())) return autoCaller.rc();2752 2753 /** @todo Validate open mode. */2754 /** @todo Validate disposition mode. */2755 2756 /** @todo Validate creation mode. */2757 uint32_t uCreationMode = 0;2758 2759 HRESULT hr = S_OK;2760 2761 ComObjPtr <GuestFile> pFile;2762 int rc = fileOpenInternal(Utf8Str(aPath), Utf8Str(aOpenMode), Utf8Str(aDisposition),2763 aCreationMode, aOffset, pFile);2764 if (RT_SUCCESS(rc))2765 {2766 /* Return directory object to the caller. */2767 hr = pFile.queryInterfaceTo(aFile);2768 }2769 else2770 {2771 switch (rc)2772 {2773 /** @todo Add more error info! */2774 2775 default:2776 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);2777 break;2778 }2779 }2780 2781 return hr;2782 #endif /* VBOX_WITH_GUEST_CONTROL */2783 }2784 2785 STDMETHODIMP GuestSession::FileQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)2786 {2787 #ifndef VBOX_WITH_GUEST_CONTROL2788 ReturnComNotImplemented();2789 #else2790 LogFlowThisFuncEnter();2791 2792 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))2793 return setError(E_INVALIDARG, tr("No file to query information for specified"));2794 CheckComArgOutPointerValid(aInfo);2795 2796 AutoCaller autoCaller(this);2797 if (FAILED(autoCaller.rc())) return autoCaller.rc();2798 2799 HRESULT hr = S_OK;2800 2801 GuestFsObjData objData;2802 int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);2803 if (RT_SUCCESS(rc))2804 {2805 ComObjPtr<GuestFsObjInfo> pFsObjInfo;2806 hr = pFsObjInfo.createObject();2807 if (FAILED(hr))2808 return VERR_COM_UNEXPECTED;2809 2810 rc = pFsObjInfo->init(objData);2811 if (RT_SUCCESS(rc))2812 hr = pFsObjInfo.queryInterfaceTo(aInfo);2813 }2814 2815 if (RT_FAILURE(rc))2816 {2817 switch (rc)2818 {2819 /** @todo Add more errors here! */2820 2821 case VERR_NOT_A_FILE:2822 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a file"));2823 break;2824 2825 default:2826 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), rc);2827 break;2828 }2829 }2830 2831 return hr;2832 #endif /* VBOX_WITH_GUEST_CONTROL */2833 }2834 2835 STDMETHODIMP GuestSession::FileQuerySize(IN_BSTR aPath, LONG64 *aSize)2836 {2837 #ifndef VBOX_WITH_GUEST_CONTROL2838 ReturnComNotImplemented();2839 #else2840 LogFlowThisFuncEnter();2841 2842 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))2843 return setError(E_INVALIDARG, tr("No file to query size for specified"));2844 CheckComArgOutPointerValid(aSize);2845 2846 AutoCaller autoCaller(this);2847 if (FAILED(autoCaller.rc())) return autoCaller.rc();2848 2849 HRESULT hr = S_OK;2850 2851 int64_t llSize;2852 int rc = fileQuerySizeInternal(Utf8Str(aPath), &llSize);2853 if (RT_SUCCESS(rc))2854 {2855 *aSize = llSize;2856 }2857 else2858 {2859 switch (rc)2860 {2861 /** @todo Add more errors here! */2862 2863 default:2864 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), rc);2865 break;2866 }2867 }2868 2869 return hr;2870 #endif /* VBOX_WITH_GUEST_CONTROL */2871 }2872 2873 STDMETHODIMP GuestSession::FileRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))2874 {2875 #ifndef VBOX_WITH_GUEST_CONTROL2876 ReturnComNotImplemented();2877 #else2878 LogFlowThisFuncEnter();2879 2880 AutoCaller autoCaller(this);2881 if (FAILED(autoCaller.rc())) return autoCaller.rc();2882 2883 ReturnComNotImplemented();2884 #endif /* VBOX_WITH_GUEST_CONTROL */2885 }2886 2887 STDMETHODIMP GuestSession::FileSetACL(IN_BSTR aPath, IN_BSTR aACL)2888 {2889 #ifndef VBOX_WITH_GUEST_CONTROL2890 ReturnComNotImplemented();2891 #else2892 LogFlowThisFuncEnter();2893 2894 AutoCaller autoCaller(this);2895 if (FAILED(autoCaller.rc())) return autoCaller.rc();2896 2897 ReturnComNotImplemented();2898 #endif /* VBOX_WITH_GUEST_CONTROL */2899 }2900 2901 STDMETHODIMP GuestSession::ProcessCreate(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),2902 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS, IGuestProcess **aProcess)2903 {2904 #ifndef VBOX_WITH_GUEST_CONTROL2905 ReturnComNotImplemented();2906 #else2907 LogFlowThisFuncEnter();2908 2909 com::SafeArray<LONG> affinity;2910 2911 HRESULT hr = ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),2912 ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess);2913 return hr;2914 #endif /* VBOX_WITH_GUEST_CONTROL */2915 }2916 2917 STDMETHODIMP GuestSession::ProcessCreateEx(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),2918 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS,2919 ProcessPriority_T aPriority, ComSafeArrayIn(LONG, aAffinity),2920 IGuestProcess **aProcess)2921 {2922 #ifndef VBOX_WITH_GUEST_CONTROL2923 ReturnComNotImplemented();2924 #else2925 LogFlowThisFuncEnter();2926 2927 if (RT_UNLIKELY((aCommand) == NULL || *(aCommand) == '\0'))2928 return setError(E_INVALIDARG, tr("No command to execute specified"));2929 CheckComArgOutPointerValid(aProcess);2930 2931 AutoCaller autoCaller(this);2932 if (FAILED(autoCaller.rc())) return autoCaller.rc();2933 2934 GuestProcessStartupInfo procInfo;2935 procInfo.mCommand = Utf8Str(aCommand);2936 2937 if (aArguments)2938 {2939 com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments));2940 for (size_t i = 0; i < arguments.size(); i++)2941 procInfo.mArguments.push_back(Utf8Str(arguments[i]));2942 }2943 2944 int rc = VINF_SUCCESS;2945 2946 /*2947 * Create the process environment:2948 * - Apply the session environment in a first step, and2949 * - Apply environment variables specified by this call to2950 * have the chance of overwriting/deleting session entries.2951 */2952 procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */2953 2954 if (aEnvironment)2955 {2956 com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aEnvironment));2957 for (size_t i = 0; i < environment.size() && RT_SUCCESS(rc); i++)2958 rc = procInfo.mEnvironment.Set(Utf8Str(environment[i]));2959 }2960 2961 HRESULT hr = S_OK;2962 2963 if (RT_SUCCESS(rc))2964 {2965 if (aFlags)2966 {2967 com::SafeArray<ProcessCreateFlag_T> flags(ComSafeArrayInArg(aFlags));2968 for (size_t i = 0; i < flags.size(); i++)2969 procInfo.mFlags |= flags[i];2970 }2971 2972 procInfo.mTimeoutMS = aTimeoutMS;2973 2974 if (aAffinity)2975 {2976 com::SafeArray<LONG> affinity(ComSafeArrayInArg(aAffinity));2977 for (size_t i = 0; i < affinity.size(); i++)2978 procInfo.mAffinity[i] = affinity[i]; /** @todo Really necessary? Later. */2979 }2980 2981 procInfo.mPriority = aPriority;2982 2983 ComObjPtr<GuestProcess> pProcess;2984 rc = processCreateExInteral(procInfo, pProcess);2985 if (RT_SUCCESS(rc))2986 {2987 /* Return guest session to the caller. */2988 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);2989 if (FAILED(hr2))2990 rc = VERR_COM_OBJECT_NOT_FOUND;2991 2992 if (RT_SUCCESS(rc))2993 rc = pProcess->startProcessAsync();2994 }2995 }2996 2997 if (RT_FAILURE(rc))2998 {2999 switch (rc)3000 {3001 case VERR_MAX_PROCS_REACHED:3002 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest processes per session (%ld) reached"),3003 VBOX_GUESTCTRL_MAX_PROCESSES);3004 break;3005 3006 /** @todo Add more errors here. */3007 3008 default:3009 hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest process, rc=%Rrc"), rc);3010 break;3011 }3012 }3013 3014 LogFlowFuncLeaveRC(rc);3015 return hr;3016 #endif /* VBOX_WITH_GUEST_CONTROL */3017 }3018 3019 STDMETHODIMP GuestSession::ProcessGet(ULONG aPID, IGuestProcess **aProcess)3020 {3021 #ifndef VBOX_WITH_GUEST_CONTROL3022 ReturnComNotImplemented();3023 #else3024 LogFlowThisFunc(("aPID=%RU32\n", aPID));3025 3026 CheckComArgOutPointerValid(aProcess);3027 if (aPID == 0)3028 return setError(E_INVALIDARG, tr("No valid process ID (PID) specified"));3029 3030 AutoCaller autoCaller(this);3031 if (FAILED(autoCaller.rc())) return autoCaller.rc();3032 3033 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);3034 3035 HRESULT hr = S_OK;3036 3037 ComObjPtr<GuestProcess> pProcess;3038 int rc = processGetByPID(aPID, &pProcess);3039 if (RT_FAILURE(rc))3040 hr = setError(E_INVALIDARG, tr("No process with PID %RU32 found"), aPID);3041 3042 /* This will set (*aProcess) to NULL if pProgress is NULL. */3043 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);3044 if (SUCCEEDED(hr))3045 hr = hr2;3046 3047 LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", *aProcess, hr));3048 return hr;3049 #endif /* VBOX_WITH_GUEST_CONTROL */3050 }3051 3052 STDMETHODIMP GuestSession::SymlinkCreate(IN_BSTR aSource, IN_BSTR aTarget, SymlinkType_T aType)3053 {3054 #ifndef VBOX_WITH_GUEST_CONTROL3055 ReturnComNotImplemented();3056 #else3057 LogFlowThisFuncEnter();3058 3059 AutoCaller autoCaller(this);3060 if (FAILED(autoCaller.rc())) return autoCaller.rc();3061 3062 ReturnComNotImplemented();3063 #endif /* VBOX_WITH_GUEST_CONTROL */3064 }3065 3066 STDMETHODIMP GuestSession::SymlinkExists(IN_BSTR aSymlink, BOOL *aExists)3067 {3068 #ifndef VBOX_WITH_GUEST_CONTROL3069 ReturnComNotImplemented();3070 #else3071 LogFlowThisFuncEnter();3072 3073 AutoCaller autoCaller(this);3074 if (FAILED(autoCaller.rc())) return autoCaller.rc();3075 3076 ReturnComNotImplemented();3077 #endif /* VBOX_WITH_GUEST_CONTROL */3078 }3079 3080 STDMETHODIMP GuestSession::SymlinkRead(IN_BSTR aSymlink, ComSafeArrayIn(SymlinkReadFlag_T, aFlags), BSTR *aTarget)3081 {3082 #ifndef VBOX_WITH_GUEST_CONTROL3083 ReturnComNotImplemented();3084 #else3085 LogFlowThisFuncEnter();3086 3087 AutoCaller autoCaller(this);3088 if (FAILED(autoCaller.rc())) return autoCaller.rc();3089 3090 ReturnComNotImplemented();3091 #endif /* VBOX_WITH_GUEST_CONTROL */3092 }3093 3094 STDMETHODIMP GuestSession::SymlinkRemoveDirectory(IN_BSTR aPath)3095 {3096 #ifndef VBOX_WITH_GUEST_CONTROL3097 ReturnComNotImplemented();3098 #else3099 LogFlowThisFuncEnter();3100 3101 AutoCaller autoCaller(this);3102 if (FAILED(autoCaller.rc())) return autoCaller.rc();3103 3104 ReturnComNotImplemented();3105 #endif /* VBOX_WITH_GUEST_CONTROL */3106 }3107 3108 STDMETHODIMP GuestSession::SymlinkRemoveFile(IN_BSTR aFile)3109 {3110 #ifndef VBOX_WITH_GUEST_CONTROL3111 ReturnComNotImplemented();3112 #else3113 LogFlowThisFuncEnter();3114 3115 AutoCaller autoCaller(this);3116 if (FAILED(autoCaller.rc())) return autoCaller.rc();3117 3118 ReturnComNotImplemented();3119 #endif /* VBOX_WITH_GUEST_CONTROL */3120 }3121
Note:
See TracChangeset
for help on using the changeset viewer.