VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp@ 42702

Last change on this file since 42702 was 42702, checked in by vboxsync, 13 years ago

Main/GuestSession: build fix (please review).

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

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