VirtualBox

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

Last change on this file since 47781 was 47781, checked in by vboxsync, 11 years ago

Main/GuestSessionImpl.cpp: IGuestFile is not supported on older Guest Additions; handle more OOM situations.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 93.7 KB
Line 
1
2/* $Id: GuestSessionImpl.cpp 47781 2013-08-16 07:24:53Z vboxsync $ */
3/** @file
4 * VirtualBox Main - Guest session handling.
5 */
6
7/*
8 * Copyright (C) 2012-2013 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#include "VirtualBoxErrorInfoImpl.h"
27
28#include "Global.h"
29#include "AutoCaller.h"
30#include "ProgressImpl.h"
31#include "VBoxEvents.h"
32#include "VMMDev.h"
33
34#include <memory> /* For auto_ptr. */
35
36#include <iprt/cpp/utils.h> /* For unconst(). */
37#include <iprt/env.h>
38#include <iprt/file.h> /* For CopyTo/From. */
39
40#include <VBox/com/array.h>
41#include <VBox/com/listeners.h>
42#include <VBox/version.h>
43
44#ifdef LOG_GROUP
45 #undef LOG_GROUP
46#endif
47#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
48#include <VBox/log.h>
49
50
51/**
52 * Base class representing an internal
53 * asynchronous session task.
54 */
55class GuestSessionTaskInternal
56{
57public:
58
59 GuestSessionTaskInternal(GuestSession *pSession)
60 : mSession(pSession),
61 mRC(VINF_SUCCESS) { }
62
63 virtual ~GuestSessionTaskInternal(void) { }
64
65 int rc(void) const { return mRC; }
66 bool isOk(void) const { return RT_SUCCESS(mRC); }
67 const ComObjPtr<GuestSession> &Session(void) const { return mSession; }
68
69protected:
70
71 const ComObjPtr<GuestSession> mSession;
72 int mRC;
73};
74
75/**
76 * Class for asynchronously opening a guest session.
77 */
78class GuestSessionTaskInternalOpen : public GuestSessionTaskInternal
79{
80public:
81
82 GuestSessionTaskInternalOpen(GuestSession *pSession)
83 : GuestSessionTaskInternal(pSession) { }
84};
85
86/**
87 * Internal listener class to serve events in an
88 * active manner, e.g. without polling delays.
89 */
90class GuestSessionListener
91{
92public:
93
94 GuestSessionListener(void)
95 {
96 }
97
98 HRESULT init(GuestSession *pSession)
99 {
100 mSession = pSession;
101 return S_OK;
102 }
103
104 void uninit(void)
105 {
106 mSession.setNull();
107 }
108
109 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
110 {
111 switch (aType)
112 {
113 case VBoxEventType_OnGuestSessionStateChanged:
114 {
115 Assert(!mSession.isNull());
116 int rc2 = mSession->signalWaitEvents(aType, aEvent);
117#ifdef DEBUG_andy
118 LogFlowFunc(("Signalling events of type=%ld, session=%p resulted in rc=%Rrc\n",
119 aType, mSession, rc2));
120#endif
121 break;
122 }
123
124 default:
125 AssertMsgFailed(("Unhandled event %ld\n", aType));
126 break;
127 }
128
129 return S_OK;
130 }
131
132private:
133
134 ComObjPtr<GuestSession> mSession;
135};
136typedef ListenerImpl<GuestSessionListener, GuestSession*> GuestSessionListenerImpl;
137
138VBOX_LISTENER_DECLARE(GuestSessionListenerImpl)
139
140// constructor / destructor
141/////////////////////////////////////////////////////////////////////////////
142
143DEFINE_EMPTY_CTOR_DTOR(GuestSession)
144
145HRESULT GuestSession::FinalConstruct(void)
146{
147 LogFlowThisFunc(("\n"));
148 return BaseFinalConstruct();
149}
150
151void GuestSession::FinalRelease(void)
152{
153 LogFlowThisFuncEnter();
154 uninit();
155 BaseFinalRelease();
156 LogFlowThisFuncLeave();
157}
158
159// public initializer/uninitializer for internal purposes only
160/////////////////////////////////////////////////////////////////////////////
161
162/**
163 * Initializes a guest session but does *not* open in on the guest side
164 * yet. This needs to be done via the openSession() / openSessionAsync calls.
165 *
166 * @return IPRT status code.
167 ** @todo Docs!
168 */
169int GuestSession::init(Guest *pGuest, const GuestSessionStartupInfo &ssInfo,
170 const GuestCredentials &guestCreds)
171{
172 LogFlowThisFunc(("pGuest=%p, ssInfo=%p, guestCreds=%p\n",
173 pGuest, &ssInfo, &guestCreds));
174
175 /* Enclose the state transition NotReady->InInit->Ready. */
176 AutoInitSpan autoInitSpan(this);
177 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
178
179#ifndef VBOX_WITH_GUEST_CONTROL
180 autoInitSpan.setSucceeded();
181 return VINF_SUCCESS;
182#else
183 AssertPtrReturn(pGuest, VERR_INVALID_POINTER);
184
185 mParent = pGuest;
186
187 /* Copy over startup info. */
188 /** @todo Use an overloaded copy operator. Later. */
189 mData.mSession.mID = ssInfo.mID;
190 mData.mSession.mIsInternal = ssInfo.mIsInternal;
191 mData.mSession.mName = ssInfo.mName;
192 mData.mSession.mOpenFlags = ssInfo.mOpenFlags;
193 mData.mSession.mOpenTimeoutMS = ssInfo.mOpenTimeoutMS;
194
195 /** @todo Use an overloaded copy operator. Later. */
196 mData.mCredentials.mUser = guestCreds.mUser;
197 mData.mCredentials.mPassword = guestCreds.mPassword;
198 mData.mCredentials.mDomain = guestCreds.mDomain;
199
200 mData.mRC = VINF_SUCCESS;
201 mData.mStatus = GuestSessionStatus_Undefined;
202 mData.mNumObjects = 0;
203
204 HRESULT hr;
205
206 int rc = queryInfo();
207 if (RT_SUCCESS(rc))
208 {
209 hr = unconst(mEventSource).createObject();
210 if (FAILED(hr))
211 rc = VERR_NO_MEMORY;
212 else
213 {
214 hr = mEventSource->init(static_cast<IGuestSession*>(this));
215 if (FAILED(hr))
216 rc = VERR_COM_UNEXPECTED;
217 }
218 }
219
220 if (RT_SUCCESS(rc))
221 {
222 try
223 {
224 GuestSessionListener *pListener = new GuestSessionListener();
225 ComObjPtr<GuestSessionListenerImpl> thisListener;
226 hr = thisListener.createObject();
227 if (SUCCEEDED(hr))
228 hr = thisListener->init(pListener, this);
229
230 if (SUCCEEDED(hr))
231 {
232 com::SafeArray <VBoxEventType_T> eventTypes;
233 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
234 hr = mEventSource->RegisterListener(thisListener,
235 ComSafeArrayAsInParam(eventTypes),
236 TRUE /* Active listener */);
237 if (SUCCEEDED(hr))
238 {
239 mLocalListener = thisListener;
240
241 rc = RTCritSectInit(&mWaitEventCritSect);
242 AssertRC(rc);
243 }
244 else
245 rc = VERR_COM_UNEXPECTED;
246 }
247 else
248 rc = VERR_COM_UNEXPECTED;
249 }
250 catch(std::bad_alloc &)
251 {
252 rc = VERR_NO_MEMORY;
253 }
254 }
255
256 if (RT_SUCCESS(rc))
257 {
258 /* Confirm a successful initialization when it's the case. */
259 autoInitSpan.setSucceeded();
260 }
261 else
262 autoInitSpan.setFailed();
263
264 LogFlowThisFunc(("mName=%s, mID=%RU32, mIsInternal=%RTbool, rc=%Rrc\n",
265 mData.mSession.mName.c_str(), mData.mSession.mID, mData.mSession.mIsInternal, rc));
266 return rc;
267#endif /* VBOX_WITH_GUEST_CONTROL */
268}
269
270/**
271 * Uninitializes the instance.
272 * Called from FinalRelease().
273 */
274void GuestSession::uninit(void)
275{
276 LogFlowThisFuncEnter();
277
278 /* Enclose the state transition Ready->InUninit->NotReady. */
279 AutoUninitSpan autoUninitSpan(this);
280 if (autoUninitSpan.uninitDone())
281 return;
282
283 int rc = VINF_SUCCESS;
284
285#ifdef VBOX_WITH_GUEST_CONTROL
286 LogFlowThisFunc(("Closing directories (%RU64 total)\n",
287 mData.mDirectories.size()));
288 for (SessionDirectories::iterator itDirs = mData.mDirectories.begin();
289 itDirs != mData.mDirectories.end(); ++itDirs)
290 {
291 (*itDirs)->Release();
292 }
293 mData.mDirectories.clear();
294
295 LogFlowThisFunc(("Closing files (%RU64 total)\n",
296 mData.mFiles.size()));
297 for (SessionFiles::iterator itFiles = mData.mFiles.begin();
298 itFiles != mData.mFiles.end(); ++itFiles)
299 {
300 itFiles->second->Release();
301 }
302 mData.mFiles.clear();
303
304 LogFlowThisFunc(("Closing processes (%RU64 total)\n",
305 mData.mProcesses.size()));
306 for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();
307 itProcs != mData.mProcesses.end(); ++itProcs)
308 {
309 itProcs->second->Release();
310 }
311 mData.mProcesses.clear();
312
313 LogFlowThisFunc(("mNumObjects=%RU32\n", mData.mNumObjects));
314
315 baseUninit();
316
317 mEventSource->UnregisterListener(mLocalListener);
318 unconst(mEventSource).setNull();
319
320#endif /* VBOX_WITH_GUEST_CONTROL */
321 LogFlowFuncLeaveRC(rc);
322}
323
324// implementation of public getters/setters for attributes
325/////////////////////////////////////////////////////////////////////////////
326
327STDMETHODIMP GuestSession::COMGETTER(User)(BSTR *aUser)
328{
329#ifndef VBOX_WITH_GUEST_CONTROL
330 ReturnComNotImplemented();
331#else
332 LogFlowThisFuncEnter();
333
334 CheckComArgOutPointerValid(aUser);
335
336 AutoCaller autoCaller(this);
337 if (FAILED(autoCaller.rc())) return autoCaller.rc();
338
339 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
340
341 mData.mCredentials.mUser.cloneTo(aUser);
342
343 LogFlowThisFuncLeave();
344 return S_OK;
345#endif /* VBOX_WITH_GUEST_CONTROL */
346}
347
348STDMETHODIMP GuestSession::COMGETTER(Domain)(BSTR *aDomain)
349{
350#ifndef VBOX_WITH_GUEST_CONTROL
351 ReturnComNotImplemented();
352#else
353 LogFlowThisFuncEnter();
354
355 CheckComArgOutPointerValid(aDomain);
356
357 AutoCaller autoCaller(this);
358 if (FAILED(autoCaller.rc())) return autoCaller.rc();
359
360 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
361
362 mData.mCredentials.mDomain.cloneTo(aDomain);
363
364 LogFlowThisFuncLeave();
365 return S_OK;
366#endif /* VBOX_WITH_GUEST_CONTROL */
367}
368
369STDMETHODIMP GuestSession::COMGETTER(Name)(BSTR *aName)
370{
371#ifndef VBOX_WITH_GUEST_CONTROL
372 ReturnComNotImplemented();
373#else
374 LogFlowThisFuncEnter();
375
376 CheckComArgOutPointerValid(aName);
377
378 AutoCaller autoCaller(this);
379 if (FAILED(autoCaller.rc())) return autoCaller.rc();
380
381 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
382
383 mData.mSession.mName.cloneTo(aName);
384
385 LogFlowThisFuncLeave();
386 return S_OK;
387#endif /* VBOX_WITH_GUEST_CONTROL */
388}
389
390STDMETHODIMP GuestSession::COMGETTER(Id)(ULONG *aId)
391{
392#ifndef VBOX_WITH_GUEST_CONTROL
393 ReturnComNotImplemented();
394#else
395 LogFlowThisFuncEnter();
396
397 CheckComArgOutPointerValid(aId);
398
399 AutoCaller autoCaller(this);
400 if (FAILED(autoCaller.rc())) return autoCaller.rc();
401
402 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
403
404 *aId = mData.mSession.mID;
405
406 LogFlowThisFuncLeave();
407 return S_OK;
408#endif /* VBOX_WITH_GUEST_CONTROL */
409}
410
411STDMETHODIMP GuestSession::COMGETTER(Status)(GuestSessionStatus_T *aStatus)
412{
413#ifndef VBOX_WITH_GUEST_CONTROL
414 ReturnComNotImplemented();
415#else
416 LogFlowThisFuncEnter();
417
418 CheckComArgOutPointerValid(aStatus);
419
420 AutoCaller autoCaller(this);
421 if (FAILED(autoCaller.rc())) return autoCaller.rc();
422
423 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
424
425 *aStatus = mData.mStatus;
426
427 LogFlowThisFuncLeave();
428 return S_OK;
429#endif /* VBOX_WITH_GUEST_CONTROL */
430}
431
432STDMETHODIMP GuestSession::COMGETTER(Timeout)(ULONG *aTimeout)
433{
434#ifndef VBOX_WITH_GUEST_CONTROL
435 ReturnComNotImplemented();
436#else
437 LogFlowThisFuncEnter();
438
439 CheckComArgOutPointerValid(aTimeout);
440
441 AutoCaller autoCaller(this);
442 if (FAILED(autoCaller.rc())) return autoCaller.rc();
443
444 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
445
446 *aTimeout = mData.mTimeout;
447
448 LogFlowThisFuncLeave();
449 return S_OK;
450#endif /* VBOX_WITH_GUEST_CONTROL */
451}
452
453STDMETHODIMP GuestSession::COMSETTER(Timeout)(ULONG aTimeout)
454{
455#ifndef VBOX_WITH_GUEST_CONTROL
456 ReturnComNotImplemented();
457#else
458 LogFlowThisFuncEnter();
459
460 AutoCaller autoCaller(this);
461 if (FAILED(autoCaller.rc())) return autoCaller.rc();
462
463 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
464
465 mData.mTimeout = aTimeout;
466
467 LogFlowThisFuncLeave();
468 return S_OK;
469#endif /* VBOX_WITH_GUEST_CONTROL */
470}
471
472STDMETHODIMP GuestSession::COMGETTER(ProtocolVersion)(ULONG *aVersion)
473{
474#ifndef VBOX_WITH_GUEST_CONTROL
475 ReturnComNotImplemented();
476#else
477 LogFlowThisFuncEnter();
478
479 CheckComArgOutPointerValid(aVersion);
480
481 AutoCaller autoCaller(this);
482 if (FAILED(autoCaller.rc())) return autoCaller.rc();
483
484 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
485
486 *aVersion = mData.mProtocolVersion;
487
488 LogFlowThisFuncLeave();
489 return S_OK;
490#endif /* VBOX_WITH_GUEST_CONTROL */
491}
492
493STDMETHODIMP GuestSession::COMGETTER(Environment)(ComSafeArrayOut(BSTR, aEnvironment))
494{
495#ifndef VBOX_WITH_GUEST_CONTROL
496 ReturnComNotImplemented();
497#else
498 LogFlowThisFuncEnter();
499
500 CheckComArgOutSafeArrayPointerValid(aEnvironment);
501
502 AutoCaller autoCaller(this);
503 if (FAILED(autoCaller.rc())) return autoCaller.rc();
504
505 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
506
507 size_t cEnvVars = mData.mEnvironment.Size();
508 LogFlowThisFunc(("[%s]: cEnvVars=%RU32\n",
509 mData.mSession.mName.c_str(), cEnvVars));
510 com::SafeArray<BSTR> environment(cEnvVars);
511
512 for (size_t i = 0; i < cEnvVars; i++)
513 {
514 Bstr strEnv(mData.mEnvironment.Get(i));
515 strEnv.cloneTo(&environment[i]);
516 }
517 environment.detachTo(ComSafeArrayOutArg(aEnvironment));
518
519 LogFlowThisFuncLeave();
520 return S_OK;
521#endif /* VBOX_WITH_GUEST_CONTROL */
522}
523
524STDMETHODIMP GuestSession::COMSETTER(Environment)(ComSafeArrayIn(IN_BSTR, aValues))
525{
526#ifndef VBOX_WITH_GUEST_CONTROL
527 ReturnComNotImplemented();
528#else
529 LogFlowThisFuncEnter();
530
531 AutoCaller autoCaller(this);
532 if (FAILED(autoCaller.rc())) return autoCaller.rc();
533
534 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
535
536 com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aValues));
537
538 int rc = VINF_SUCCESS;
539 for (size_t i = 0; i < environment.size() && RT_SUCCESS(rc); i++)
540 {
541 Utf8Str strEnv(environment[i]);
542 if (!strEnv.isEmpty()) /* Silently skip empty entries. */
543 rc = mData.mEnvironment.Set(strEnv);
544 }
545
546 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
547 LogFlowFuncLeaveRC(hr);
548 return hr;
549#endif /* VBOX_WITH_GUEST_CONTROL */
550}
551
552STDMETHODIMP GuestSession::COMGETTER(Processes)(ComSafeArrayOut(IGuestProcess *, aProcesses))
553{
554#ifndef VBOX_WITH_GUEST_CONTROL
555 ReturnComNotImplemented();
556#else
557 LogFlowThisFuncEnter();
558
559 CheckComArgOutSafeArrayPointerValid(aProcesses);
560
561 AutoCaller autoCaller(this);
562 if (FAILED(autoCaller.rc())) return autoCaller.rc();
563
564 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
565
566 SafeIfaceArray<IGuestProcess> collection(mData.mProcesses);
567 collection.detachTo(ComSafeArrayOutArg(aProcesses));
568
569 LogFlowFunc(("mProcesses=%zu\n", collection.size()));
570 return S_OK;
571#endif /* VBOX_WITH_GUEST_CONTROL */
572}
573
574STDMETHODIMP GuestSession::COMGETTER(Directories)(ComSafeArrayOut(IGuestDirectory *, aDirectories))
575{
576#ifndef VBOX_WITH_GUEST_CONTROL
577 ReturnComNotImplemented();
578#else
579 LogFlowThisFuncEnter();
580
581 CheckComArgOutSafeArrayPointerValid(aDirectories);
582
583 AutoCaller autoCaller(this);
584 if (FAILED(autoCaller.rc())) return autoCaller.rc();
585
586 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
587
588 SafeIfaceArray<IGuestDirectory> collection(mData.mDirectories);
589 collection.detachTo(ComSafeArrayOutArg(aDirectories));
590
591 LogFlowFunc(("mDirectories=%zu\n", collection.size()));
592 return S_OK;
593#endif /* VBOX_WITH_GUEST_CONTROL */
594}
595
596STDMETHODIMP GuestSession::COMGETTER(Files)(ComSafeArrayOut(IGuestFile *, aFiles))
597{
598#ifndef VBOX_WITH_GUEST_CONTROL
599 ReturnComNotImplemented();
600#else
601 LogFlowThisFuncEnter();
602
603 CheckComArgOutSafeArrayPointerValid(aFiles);
604
605 AutoCaller autoCaller(this);
606 if (FAILED(autoCaller.rc())) return autoCaller.rc();
607
608 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
609
610 SafeIfaceArray<IGuestFile> collection(mData.mFiles);
611 collection.detachTo(ComSafeArrayOutArg(aFiles));
612
613 LogFlowFunc(("mFiles=%zu\n", collection.size()));
614 return S_OK;
615#endif /* VBOX_WITH_GUEST_CONTROL */
616}
617
618STDMETHODIMP GuestSession::COMGETTER(EventSource)(IEventSource ** aEventSource)
619{
620#ifndef VBOX_WITH_GUEST_CONTROL
621 ReturnComNotImplemented();
622#else
623 LogFlowThisFuncEnter();
624
625 CheckComArgOutPointerValid(aEventSource);
626
627 AutoCaller autoCaller(this);
628 if (FAILED(autoCaller.rc())) return autoCaller.rc();
629
630 // no need to lock - lifetime constant
631 mEventSource.queryInterfaceTo(aEventSource);
632
633 LogFlowThisFuncLeave();
634 return S_OK;
635#endif /* VBOX_WITH_GUEST_CONTROL */
636}
637
638// private methods
639///////////////////////////////////////////////////////////////////////////////
640
641int GuestSession::closeSession(uint32_t uFlags, uint32_t uTimeoutMS, int *pGuestRc)
642{
643 LogFlowThisFunc(("uFlags=%x, uTimeoutMS=%RU32\n", uFlags, uTimeoutMS));
644
645 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
646
647 /* Guest Additions < 4.3 don't support closing dedicated
648 guest sessions, skip. */
649 if (mData.mProtocolVersion < 2)
650 {
651 LogFlowThisFunc(("Installed Guest Additions don't support closing dedicated sessions, skipping\n"));
652 return VINF_SUCCESS;
653 }
654
655 /** @todo uFlags validation. */
656
657 if (mData.mStatus != GuestSessionStatus_Started)
658 {
659 LogFlowThisFunc(("Session ID=%RU32 not started (anymore), status now is: %ld\n",
660 mData.mSession.mID, mData.mStatus));
661 return VINF_SUCCESS;
662 }
663
664 int vrc;
665
666 GuestWaitEvent *pEvent = NULL;
667 std::list < VBoxEventType_T > eventTypes;
668 try
669 {
670 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
671
672 vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */,
673 eventTypes, &pEvent);
674 }
675 catch (std::bad_alloc)
676 {
677 vrc = VERR_NO_MEMORY;
678 }
679
680 if (RT_FAILURE(vrc))
681 return vrc;
682
683 LogFlowThisFunc(("Sending closing request to guest session ID=%RU32, uFlags=%x\n",
684 mData.mSession.mID, uFlags));
685
686 VBOXHGCMSVCPARM paParms[4];
687 int i = 0;
688 paParms[i++].setUInt32(pEvent->ContextID());
689 paParms[i++].setUInt32(uFlags);
690
691 alock.release(); /* Drop the write lock before waiting. */
692
693 vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms);
694 if (RT_SUCCESS(vrc))
695 vrc = waitForStatusChange(pEvent, GuestSessionWaitForFlag_Terminate, uTimeoutMS,
696 NULL /* Session status */, pGuestRc);
697
698 unregisterWaitEvent(pEvent);
699
700 LogFlowFuncLeaveRC(vrc);
701 return vrc;
702}
703
704int GuestSession::directoryRemoveFromList(GuestDirectory *pDirectory)
705{
706 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
707
708 for (SessionDirectories::iterator itDirs = mData.mDirectories.begin();
709 itDirs != mData.mDirectories.end(); ++itDirs)
710 {
711 if (pDirectory == (*itDirs))
712 {
713 Bstr strName;
714 HRESULT hr = (*itDirs)->COMGETTER(DirectoryName)(strName.asOutParam());
715 ComAssertComRC(hr);
716
717 Assert(mData.mDirectories.size());
718 LogFlowFunc(("Removing directory \"%s\" (Session: %RU32) (now total %ld directories)\n",
719 Utf8Str(strName).c_str(), mData.mSession.mID, mData.mDirectories.size() - 1));
720
721 mData.mDirectories.erase(itDirs);
722 return VINF_SUCCESS;
723 }
724 }
725
726 return VERR_NOT_FOUND;
727}
728
729int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags, int *pGuestRc)
730{
731 /* pGuestRc is optional. */
732
733 LogFlowThisFunc(("strPath=%s, uMode=%x, uFlags=%x\n",
734 strPath.c_str(), uMode, uFlags));
735
736 GuestProcessStartupInfo procInfo;
737 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
738 procInfo.mFlags = ProcessCreateFlag_Hidden;
739
740 int vrc = VINF_SUCCESS;
741
742 /* Construct arguments. */
743 if (uFlags & DirectoryCreateFlag_Parents)
744 procInfo.mArguments.push_back(Utf8Str("--parents")); /* We also want to create the parent directories. */
745 if (uMode)
746 {
747 procInfo.mArguments.push_back(Utf8Str("--mode")); /* Set the creation mode. */
748
749 char szMode[16];
750 if (RTStrPrintf(szMode, sizeof(szMode), "%o", uMode))
751 {
752 procInfo.mArguments.push_back(Utf8Str(szMode));
753 }
754 else
755 vrc = VERR_BUFFER_OVERFLOW;
756 }
757 procInfo.mArguments.push_back(strPath); /* The directory we want to create. */
758
759 if (RT_SUCCESS(vrc))
760 {
761 int guestRc;
762 GuestProcessTool procTool;
763 vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
764 if (RT_SUCCESS(vrc))
765 {
766 if (RT_SUCCESS(guestRc))
767 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
768 }
769
770 if (RT_SUCCESS(vrc))
771 {
772 if (RT_SUCCESS(guestRc))
773 guestRc = procTool.TerminatedOk(NULL /* Exit code */);
774 }
775
776 if ( vrc == VERR_GSTCTL_GUEST_ERROR
777 && pGuestRc)
778 {
779 *pGuestRc = guestRc;
780 }
781 }
782
783 LogFlowFuncLeaveRC(vrc);
784 return vrc;
785}
786
787int GuestSession::directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
788{
789 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
790
791 int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc);
792 if (RT_SUCCESS(vrc))
793 {
794 vrc = objData.mType == FsObjType_Directory
795 ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
796 }
797
798 LogFlowFuncLeaveRC(vrc);
799 return vrc;
800}
801
802int GuestSession::objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath,
803 bool fDirectory, const Utf8Str &strName, int *pGuestRc)
804{
805 GuestProcessStartupInfo procInfo;
806 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
807 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
808 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
809 if (fDirectory)
810 procInfo.mArguments.push_back(Utf8Str("-d"));
811 if (strPath.length()) /* Otherwise use /tmp or equivalent. */
812 {
813 procInfo.mArguments.push_back(Utf8Str("-t"));
814 procInfo.mArguments.push_back(strPath);
815 }
816 procInfo.mArguments.push_back(strTemplate);
817
818 GuestProcessTool procTool; int guestRc;
819 int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
820 if (RT_SUCCESS(vrc))
821 {
822 if (RT_SUCCESS(guestRc))
823 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
824 }
825
826 if (RT_SUCCESS(vrc))
827 {
828 if (RT_SUCCESS(guestRc))
829 guestRc = procTool.TerminatedOk(NULL /* Exit code */);
830 }
831
832 if ( vrc == VERR_GSTCTL_GUEST_ERROR
833 && pGuestRc)
834 {
835 *pGuestRc = guestRc;
836 }
837
838 LogFlowFuncLeaveRC(vrc);
839 return vrc;
840}
841
842int GuestSession::directoryOpenInternal(const Utf8Str &strPath, const Utf8Str &strFilter,
843 uint32_t uFlags, ComObjPtr<GuestDirectory> &pDirectory)
844{
845 LogFlowThisFunc(("strPath=%s, strPath=%s, uFlags=%x\n",
846 strPath.c_str(), strFilter.c_str(), uFlags));
847
848 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
849
850 /* Create the directory object. */
851 HRESULT hr = pDirectory.createObject();
852 if (FAILED(hr))
853 return VERR_COM_UNEXPECTED;
854
855 int vrc = pDirectory->init(this /* Parent */,
856 strPath, strFilter, uFlags);
857 if (RT_FAILURE(vrc))
858 return vrc;
859
860 /* Add the created directory to our vector. */
861 mData.mDirectories.push_back(pDirectory);
862
863 LogFlowFunc(("Added new directory \"%s\" (Session: %RU32)\n",
864 strPath.c_str(), mData.mSession.mID));
865
866 LogFlowFuncLeaveRC(vrc);
867 return vrc;
868}
869
870int GuestSession::dispatchToFile(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
871{
872 LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
873
874 AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
875 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
876
877 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
878
879 uint32_t uFileID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID);
880#ifdef DEBUG
881 LogFlowFunc(("uFileID=%RU32 (%RU32 total)\n",
882 uFileID, mData.mFiles.size()));
883#endif
884 int rc;
885 SessionFiles::const_iterator itFile
886 = mData.mFiles.find(uFileID);
887 if (itFile != mData.mFiles.end())
888 {
889 ComObjPtr<GuestFile> pFile(itFile->second);
890 Assert(!pFile.isNull());
891
892 alock.release();
893
894 rc = pFile->callbackDispatcher(pCtxCb, pSvcCb);
895 }
896 else
897 rc = VERR_NOT_FOUND;
898
899 LogFlowFuncLeaveRC(rc);
900 return rc;
901}
902
903int GuestSession::dispatchToProcess(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
904{
905 LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
906
907 AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
908 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
909
910 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
911
912 uint32_t uProcessID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID);
913#ifdef DEBUG
914 LogFlowFunc(("uProcessID=%RU32 (%RU32 total)\n",
915 uProcessID, mData.mProcesses.size()));
916#endif
917 int rc;
918 SessionProcesses::const_iterator itProc
919 = mData.mProcesses.find(uProcessID);
920 if (itProc != mData.mProcesses.end())
921 {
922 ComObjPtr<GuestProcess> pProcess(itProc->second);
923 Assert(!pProcess.isNull());
924
925 /* Set protocol version so that pSvcCb can
926 * be interpreted right. */
927 pCtxCb->uProtocol = mData.mProtocolVersion;
928
929 alock.release();
930 rc = pProcess->callbackDispatcher(pCtxCb, pSvcCb);
931 }
932 else
933 rc = VERR_NOT_FOUND;
934
935 LogFlowFuncLeaveRC(rc);
936 return rc;
937}
938
939int GuestSession::dispatchToThis(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
940{
941 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
942 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
943
944 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
945
946#ifdef DEBUG
947 LogFlowThisFunc(("sessionID=%RU32, CID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
948 mData.mSession.mID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
949#endif
950
951 int rc = VINF_SUCCESS;
952 switch (pCbCtx->uFunction)
953 {
954 case GUEST_DISCONNECTED:
955 /** @todo Handle closing all guest objects. */
956 break;
957
958 case GUEST_SESSION_NOTIFY:
959 {
960 rc = onSessionStatusChange(pCbCtx, pSvcCb);
961 break;
962 }
963
964 default:
965 /* Silently skip unknown callbacks. */
966 rc = VERR_NOT_SUPPORTED;
967 break;
968 }
969
970 LogFlowFuncLeaveRC(rc);
971 return rc;
972}
973
974inline bool GuestSession::fileExists(uint32_t uFileID, ComObjPtr<GuestFile> *pFile)
975{
976 SessionFiles::const_iterator it = mData.mFiles.find(uFileID);
977 if (it != mData.mFiles.end())
978 {
979 if (pFile)
980 *pFile = it->second;
981 return true;
982 }
983 return false;
984}
985
986int GuestSession::fileRemoveFromList(GuestFile *pFile)
987{
988 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
989
990 for (SessionFiles::iterator itFiles = mData.mFiles.begin();
991 itFiles != mData.mFiles.end(); ++itFiles)
992 {
993 if (pFile == itFiles->second)
994 {
995 /* Make sure to consume the pointer before the one of thfe
996 * iterator gets released. */
997 ComObjPtr<GuestFile> pCurFile = pFile;
998
999 Bstr strName;
1000 HRESULT hr = pCurFile->COMGETTER(FileName)(strName.asOutParam());
1001 ComAssertComRC(hr);
1002
1003 Assert(mData.mNumObjects);
1004 LogFlowThisFunc(("Removing guest file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n",
1005 Utf8Str(strName).c_str(), mData.mSession.mID, mData.mFiles.size() - 1, mData.mNumObjects - 1));
1006
1007 itFiles->second->Release();
1008
1009 mData.mFiles.erase(itFiles);
1010 mData.mNumObjects--;
1011
1012 alock.release(); /* Release lock before firing off event. */
1013
1014 fireGuestFileRegisteredEvent(mEventSource, this, pCurFile,
1015 false /* Unregistered */);
1016 return VINF_SUCCESS;
1017 }
1018 }
1019
1020 return VERR_NOT_FOUND;
1021}
1022
1023int GuestSession::fileRemoveInternal(const Utf8Str &strPath, int *pGuestRc)
1024{
1025 GuestProcessStartupInfo procInfo;
1026 GuestProcessStream streamOut;
1027
1028 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_RM);
1029 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
1030 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
1031 procInfo.mArguments.push_back(strPath); /* The file we want to remove. */
1032
1033 GuestProcessTool procTool; int guestRc;
1034 int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
1035 if (RT_SUCCESS(vrc))
1036 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
1037
1038 if (RT_SUCCESS(vrc))
1039 {
1040 if (RT_SUCCESS(guestRc))
1041 guestRc = procTool.TerminatedOk(NULL /* Exit code */);
1042 }
1043
1044 if ( vrc == VERR_GSTCTL_GUEST_ERROR
1045 && pGuestRc)
1046 {
1047 *pGuestRc = guestRc;
1048 }
1049
1050 LogFlowFuncLeaveRC(vrc);
1051 return vrc;
1052}
1053
1054int GuestSession::fileOpenInternal(const GuestFileOpenInfo &openInfo, ComObjPtr<GuestFile> &pFile, int *pGuestRc)
1055{
1056 LogFlowThisFunc(("strPath=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%x, iOffset=%RI64\n",
1057 openInfo.mFileName.c_str(), openInfo.mOpenMode.c_str(), openInfo.mDisposition.c_str(),
1058 openInfo.mCreationMode, openInfo.mInitialOffset));
1059
1060 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1061
1062 /* Guest Additions < 4.3 don't support handling
1063 guest files, skip. */
1064 if (mData.mProtocolVersion < 2)
1065 {
1066 LogFlowThisFunc(("Installed Guest Additions don't support handling guest files, skipping\n"));
1067 return VERR_NOT_SUPPORTED;
1068 }
1069
1070 int rc = VERR_MAX_PROCS_REACHED;
1071 if (mData.mNumObjects >= VBOX_GUESTCTRL_MAX_OBJECTS)
1072 return rc;
1073
1074 /* Create a new (host-based) file ID and assign it. */
1075 uint32_t uNewFileID = 0;
1076 ULONG uTries = 0;
1077
1078 for (;;)
1079 {
1080 /* Is the file ID already used? */
1081 if (!fileExists(uNewFileID, NULL /* pProgress */))
1082 {
1083 /* Callback with context ID was not found. This means
1084 * we can use this context ID for our new callback we want
1085 * to add below. */
1086 rc = VINF_SUCCESS;
1087 break;
1088 }
1089 uNewFileID++;
1090 if (uNewFileID == VBOX_GUESTCTRL_MAX_OBJECTS)
1091 uNewFileID = 0;
1092
1093 if (++uTries == UINT32_MAX)
1094 break; /* Don't try too hard. */
1095 }
1096
1097 if (RT_FAILURE(rc))
1098 return rc;
1099
1100 /* Create the directory object. */
1101 HRESULT hr = pFile.createObject();
1102 if (FAILED(hr))
1103 return VERR_COM_UNEXPECTED;
1104
1105 Console *pConsole = mParent->getConsole();
1106 AssertPtr(pConsole);
1107
1108 rc = pFile->init(pConsole, this /* GuestSession */,
1109 uNewFileID, openInfo);
1110 if (RT_FAILURE(rc))
1111 return rc;
1112
1113 int guestRc;
1114 rc = pFile->openFile(&guestRc);
1115 if (RT_SUCCESS(rc))
1116 {
1117 try
1118 {
1119 /* Add the created file to our vector. */
1120 mData.mFiles[uNewFileID] = pFile;
1121 mData.mNumObjects++;
1122 Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS);
1123
1124 LogFlowFunc(("Added new guest file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n",
1125 openInfo.mFileName.c_str(), mData.mSession.mID, mData.mFiles.size(), mData.mNumObjects));
1126
1127 alock.release(); /* Release lock before firing off event. */
1128
1129 fireGuestFileRegisteredEvent(mEventSource, this, pFile,
1130 true /* Registered */);
1131 if (pGuestRc)
1132 *pGuestRc = guestRc;
1133 }
1134 catch (std::bad_alloc &)
1135 {
1136 rc = VERR_NO_MEMORY;
1137 }
1138 }
1139
1140 LogFlowFuncLeaveRC(rc);
1141 return rc;
1142}
1143
1144int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
1145{
1146 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
1147
1148 int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc);
1149 if (RT_SUCCESS(vrc))
1150 {
1151 vrc = objData.mType == FsObjType_File
1152 ? VINF_SUCCESS : VERR_NOT_A_FILE;
1153 }
1154
1155 LogFlowFuncLeaveRC(vrc);
1156 return vrc;
1157}
1158
1159int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize, int *pGuestRc)
1160{
1161 AssertPtrReturn(pllSize, VERR_INVALID_POINTER);
1162
1163 GuestFsObjData objData;
1164 int vrc = fileQueryInfoInternal(strPath, objData, pGuestRc);
1165 if (RT_SUCCESS(vrc))
1166 *pllSize = objData.mObjectSize;
1167
1168 return vrc;
1169}
1170
1171int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
1172{
1173 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
1174
1175 /** @todo Merge this with IGuestFile::queryInfo(). */
1176 GuestProcessStartupInfo procInfo;
1177 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT);
1178 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
1179
1180 /* Construct arguments. */
1181 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
1182 procInfo.mArguments.push_back(strPath);
1183
1184 GuestProcessTool procTool; int guestRc;
1185 int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
1186 if (RT_SUCCESS(vrc))
1187 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
1188 if (RT_SUCCESS(vrc))
1189 {
1190 guestRc = procTool.TerminatedOk(NULL /* Exit code */);
1191 if (RT_SUCCESS(guestRc))
1192 {
1193 GuestProcessStreamBlock curBlock;
1194 vrc = procTool.GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, curBlock);
1195 /** @todo Check for more / validate blocks! */
1196 if (RT_SUCCESS(vrc))
1197 vrc = objData.FromStat(curBlock);
1198 }
1199 }
1200
1201 if ( vrc == VERR_GSTCTL_GUEST_ERROR
1202 && pGuestRc)
1203 {
1204 *pGuestRc = guestRc;
1205 }
1206
1207 LogFlowFuncLeaveRC(vrc);
1208 return vrc;
1209}
1210
1211const GuestCredentials& GuestSession::getCredentials(void)
1212{
1213 return mData.mCredentials;
1214}
1215
1216const GuestEnvironment& GuestSession::getEnvironment(void)
1217{
1218 return mData.mEnvironment;
1219}
1220
1221Utf8Str GuestSession::getName(void)
1222{
1223 return mData.mSession.mName;
1224}
1225
1226/* static */
1227Utf8Str GuestSession::guestErrorToString(int guestRc)
1228{
1229 Utf8Str strError;
1230
1231 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
1232 switch (guestRc)
1233 {
1234 case VERR_INVALID_VM_HANDLE:
1235 strError += Utf8StrFmt(tr("VMM device is not available (is the VM running?)"));
1236 break;
1237
1238 case VERR_HGCM_SERVICE_NOT_FOUND:
1239 strError += Utf8StrFmt(tr("The guest execution service is not available"));
1240 break;
1241
1242 case VERR_AUTHENTICATION_FAILURE:
1243 strError += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
1244 break;
1245
1246 case VERR_TIMEOUT:
1247 strError += Utf8StrFmt(tr("The guest did not respond within time"));
1248 break;
1249
1250 case VERR_CANCELLED:
1251 strError += Utf8StrFmt(tr("The session operation was canceled"));
1252 break;
1253
1254 case VERR_PERMISSION_DENIED:
1255 strError += Utf8StrFmt(tr("Invalid user/password credentials"));
1256 break;
1257
1258 case VERR_MAX_PROCS_REACHED:
1259 strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached"));
1260 break;
1261
1262 case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */
1263 strError += Utf8StrFmt(tr("Unable to retrieve requested information"));
1264 break;
1265
1266 case VERR_NOT_FOUND:
1267 strError += Utf8StrFmt(tr("The guest execution service is not ready (yet)"));
1268 break;
1269
1270 default:
1271 strError += Utf8StrFmt("%Rrc", guestRc);
1272 break;
1273 }
1274
1275 return strError;
1276}
1277
1278/**
1279 * Checks if this session is ready state where it can handle
1280 * all session-bound actions (like guest processes, guest files).
1281 * Only used by official API methods. Will set an external
1282 * error when not ready.
1283 */
1284HRESULT GuestSession::isReadyExternal(void)
1285{
1286 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1287
1288 /** @todo Be a bit more informative. */
1289 if (mData.mStatus != GuestSessionStatus_Started)
1290 return setError(E_UNEXPECTED, tr("Session is not in started state"));
1291
1292 return S_OK;
1293}
1294
1295/** No locking! */
1296int GuestSession::onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
1297{
1298 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
1299 /* pCallback is optional. */
1300 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
1301
1302 if (pSvcCbData->mParms < 3)
1303 return VERR_INVALID_PARAMETER;
1304
1305 CALLBACKDATA_SESSION_NOTIFY dataCb;
1306 /* pSvcCb->mpaParms[0] always contains the context ID. */
1307 pSvcCbData->mpaParms[1].getUInt32(&dataCb.uType);
1308 pSvcCbData->mpaParms[2].getUInt32(&dataCb.uResult);
1309
1310 LogFlowThisFunc(("ID=%RU32, uType=%RU32, guestRc=%Rrc\n",
1311 mData.mSession.mID, dataCb.uType, dataCb.uResult));
1312
1313 int vrc = VINF_SUCCESS;
1314
1315 GuestSessionStatus_T sessionStatus = GuestSessionStatus_Undefined;
1316
1317 int guestRc = dataCb.uResult; /** @todo uint32_t vs. int. */
1318 switch (dataCb.uType)
1319 {
1320 case GUEST_SESSION_NOTIFYTYPE_ERROR:
1321 sessionStatus = GuestSessionStatus_Error;
1322 break;
1323
1324 case GUEST_SESSION_NOTIFYTYPE_STARTED:
1325 sessionStatus = GuestSessionStatus_Started;
1326 break;
1327
1328 case GUEST_SESSION_NOTIFYTYPE_TEN:
1329 case GUEST_SESSION_NOTIFYTYPE_TES:
1330 case GUEST_SESSION_NOTIFYTYPE_TEA:
1331 sessionStatus = GuestSessionStatus_Terminated;
1332 break;
1333
1334 case GUEST_SESSION_NOTIFYTYPE_TOK:
1335 sessionStatus = GuestSessionStatus_TimedOutKilled;
1336 break;
1337
1338 case GUEST_SESSION_NOTIFYTYPE_TOA:
1339 sessionStatus = GuestSessionStatus_TimedOutAbnormally;
1340 break;
1341
1342 case GUEST_SESSION_NOTIFYTYPE_DWN:
1343 sessionStatus = GuestSessionStatus_Down;
1344 break;
1345
1346 case GUEST_SESSION_NOTIFYTYPE_UNDEFINED:
1347 default:
1348 vrc = VERR_NOT_SUPPORTED;
1349 break;
1350 }
1351
1352 if (RT_SUCCESS(vrc))
1353 {
1354 if (RT_FAILURE(guestRc))
1355 sessionStatus = GuestSessionStatus_Error;
1356 }
1357
1358 /* Set the session status. */
1359 if (RT_SUCCESS(vrc))
1360 vrc = setSessionStatus(sessionStatus, guestRc);
1361
1362 LogFlowThisFunc(("ID=%RU32, guestRc=%Rrc\n", mData.mSession.mID, guestRc));
1363
1364 LogFlowFuncLeaveRC(vrc);
1365 return vrc;
1366}
1367
1368int GuestSession::startSessionInternal(int *pGuestRc)
1369{
1370 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1371
1372 LogFlowThisFunc(("mID=%RU32, mName=%s, uProtocolVersion=%RU32, openFlags=%x, openTimeoutMS=%RU32\n",
1373 mData.mSession.mID, mData.mSession.mName.c_str(), mData.mProtocolVersion,
1374 mData.mSession.mOpenFlags, mData.mSession.mOpenTimeoutMS));
1375
1376 /* Guest Additions < 4.3 don't support opening dedicated
1377 guest sessions. Simply return success here. */
1378 if (mData.mProtocolVersion < 2)
1379 {
1380 mData.mStatus = GuestSessionStatus_Started;
1381
1382 LogFlowThisFunc(("Installed Guest Additions don't support opening dedicated sessions, skipping\n"));
1383 return VINF_SUCCESS;
1384 }
1385
1386 if (mData.mStatus != GuestSessionStatus_Undefined)
1387 return VINF_SUCCESS;
1388
1389 /** @todo mData.mSession.uFlags validation. */
1390
1391 /* Set current session status. */
1392 mData.mStatus = GuestSessionStatus_Starting;
1393
1394 int vrc;
1395
1396 GuestWaitEvent *pEvent = NULL;
1397 std::list < VBoxEventType_T > eventTypes;
1398 try
1399 {
1400 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
1401
1402 vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */,
1403 eventTypes, &pEvent);
1404 }
1405 catch (std::bad_alloc)
1406 {
1407 vrc = VERR_NO_MEMORY;
1408 }
1409
1410 if (RT_FAILURE(vrc))
1411 return vrc;
1412
1413 VBOXHGCMSVCPARM paParms[8];
1414
1415 int i = 0;
1416 paParms[i++].setUInt32(pEvent->ContextID());
1417 paParms[i++].setUInt32(mData.mProtocolVersion);
1418 paParms[i++].setPointer((void*)mData.mCredentials.mUser.c_str(),
1419 (ULONG)mData.mCredentials.mUser.length() + 1);
1420 paParms[i++].setPointer((void*)mData.mCredentials.mPassword.c_str(),
1421 (ULONG)mData.mCredentials.mPassword.length() + 1);
1422 paParms[i++].setPointer((void*)mData.mCredentials.mDomain.c_str(),
1423 (ULONG)mData.mCredentials.mDomain.length() + 1);
1424 paParms[i++].setUInt32(mData.mSession.mOpenFlags);
1425
1426 alock.release(); /* Drop write lock before sending. */
1427
1428 vrc = sendCommand(HOST_SESSION_CREATE, i, paParms);
1429 if (RT_SUCCESS(vrc))
1430 vrc = waitForStatusChange(pEvent, GuestSessionWaitForFlag_Start,
1431 30 * 1000 /* 30s timeout */,
1432 NULL /* Session status */, pGuestRc);
1433
1434 unregisterWaitEvent(pEvent);
1435
1436 LogFlowFuncLeaveRC(vrc);
1437 return vrc;
1438}
1439
1440int GuestSession::startSessionAsync(void)
1441{
1442 LogFlowThisFuncEnter();
1443
1444 int vrc;
1445
1446 try
1447 {
1448 /* Asynchronously open the session on the guest by kicking off a
1449 * worker thread. */
1450 std::auto_ptr<GuestSessionTaskInternalOpen> pTask(new GuestSessionTaskInternalOpen(this));
1451 AssertReturn(pTask->isOk(), pTask->rc());
1452
1453 vrc = RTThreadCreate(NULL, GuestSession::startSessionThread,
1454 (void *)pTask.get(), 0,
1455 RTTHREADTYPE_MAIN_WORKER, 0,
1456 "gctlSesStart");
1457 if (RT_SUCCESS(vrc))
1458 {
1459 /* pTask is now owned by openSessionThread(), so release it. */
1460 pTask.release();
1461 }
1462 }
1463 catch(std::bad_alloc &)
1464 {
1465 vrc = VERR_NO_MEMORY;
1466 }
1467
1468 LogFlowFuncLeaveRC(vrc);
1469 return vrc;
1470}
1471
1472/* static */
1473DECLCALLBACK(int) GuestSession::startSessionThread(RTTHREAD Thread, void *pvUser)
1474{
1475 LogFlowFunc(("pvUser=%p\n", pvUser));
1476
1477 std::auto_ptr<GuestSessionTaskInternalOpen> pTask(static_cast<GuestSessionTaskInternalOpen*>(pvUser));
1478 AssertPtr(pTask.get());
1479
1480 const ComObjPtr<GuestSession> pSession(pTask->Session());
1481 Assert(!pSession.isNull());
1482
1483 AutoCaller autoCaller(pSession);
1484 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1485
1486 int vrc = pSession->startSessionInternal(NULL /* Guest rc, ignored */);
1487 /* Nothing to do here anymore. */
1488
1489 LogFlowFuncLeaveRC(vrc);
1490 return vrc;
1491}
1492
1493int GuestSession::processRemoveFromList(GuestProcess *pProcess)
1494{
1495 AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
1496
1497 LogFlowThisFunc(("pProcess=%p\n", pProcess));
1498
1499 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1500
1501 int rc = VERR_NOT_FOUND;
1502
1503 ULONG uPID;
1504 HRESULT hr = pProcess->COMGETTER(PID)(&uPID);
1505 ComAssertComRC(hr);
1506
1507 LogFlowFunc(("Closing process (PID=%RU32) ...\n", uPID));
1508
1509 SessionProcesses::iterator itProcs = mData.mProcesses.begin();
1510 while (itProcs != mData.mProcesses.end())
1511 {
1512 if (pProcess == itProcs->second)
1513 {
1514 /* Make sure to consume the pointer before the one of thfe
1515 * iterator gets released. */
1516 ComObjPtr<GuestProcess> pCurProcess = pProcess;
1517
1518 hr = pCurProcess->COMGETTER(PID)(&uPID);
1519 ComAssertComRC(hr);
1520
1521 Assert(mData.mNumObjects);
1522 LogFlowFunc(("Removing process ID=%RU32 (Session: %RU32), guest PID=%RU32 (now total %ld processes, %ld objects)\n",
1523 pProcess->getObjectID(), mData.mSession.mID, uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1));
1524
1525 pProcess->cancelWaitEvents();
1526 pProcess->Release();
1527
1528 mData.mProcesses.erase(itProcs);
1529 mData.mNumObjects--;
1530
1531 alock.release(); /* Release lock before firing off event. */
1532
1533 fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, pCurProcess,
1534 uPID, false /* Process unregistered */);
1535 rc = VINF_SUCCESS;
1536 break;
1537 }
1538
1539 itProcs++;
1540 }
1541
1542 LogFlowFuncLeaveRC(rc);
1543 return rc;
1544}
1545
1546/**
1547 * Creates but does *not* start the process yet. See GuestProcess::startProcess() or
1548 * GuestProcess::startProcessAsync() for that.
1549 *
1550 * @return IPRT status code.
1551 * @param procInfo
1552 * @param pProcess
1553 */
1554int GuestSession::processCreateExInteral(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
1555{
1556 LogFlowFunc(("mCmd=%s, mFlags=%x, mTimeoutMS=%RU32\n",
1557 procInfo.mCommand.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));
1558#ifdef DEBUG
1559 if (procInfo.mArguments.size())
1560 {
1561 LogFlowFunc(("Arguments:"));
1562 ProcessArguments::const_iterator it = procInfo.mArguments.begin();
1563 while (it != procInfo.mArguments.end())
1564 {
1565 LogFlow((" %s", (*it).c_str()));
1566 it++;
1567 }
1568 LogFlow(("\n"));
1569 }
1570#endif
1571
1572 /* Validate flags. */
1573 if (procInfo.mFlags)
1574 {
1575 if ( !(procInfo.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
1576 && !(procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1577 && !(procInfo.mFlags & ProcessCreateFlag_Hidden)
1578 && !(procInfo.mFlags & ProcessCreateFlag_NoProfile)
1579 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1580 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdErr))
1581 {
1582 return VERR_INVALID_PARAMETER;
1583 }
1584 }
1585
1586 if ( (procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1587 && ( (procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1588 || (procInfo.mFlags & ProcessCreateFlag_WaitForStdErr)
1589 )
1590 )
1591 {
1592 return VERR_INVALID_PARAMETER;
1593 }
1594
1595 /* Adjust timeout. If set to 0, we define
1596 * an infinite timeout. */
1597 if (procInfo.mTimeoutMS == 0)
1598 procInfo.mTimeoutMS = UINT32_MAX;
1599
1600 /** @tood Implement process priority + affinity. */
1601
1602 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1603
1604 int rc = VERR_MAX_PROCS_REACHED;
1605 if (mData.mNumObjects >= VBOX_GUESTCTRL_MAX_OBJECTS)
1606 return rc;
1607
1608 /* Create a new (host-based) process ID and assign it. */
1609 uint32_t uNewProcessID = 0;
1610 ULONG uTries = 0;
1611
1612 for (;;)
1613 {
1614 /* Is the context ID already used? */
1615 if (!processExists(uNewProcessID, NULL /* pProgress */))
1616 {
1617 /* Callback with context ID was not found. This means
1618 * we can use this context ID for our new callback we want
1619 * to add below. */
1620 rc = VINF_SUCCESS;
1621 break;
1622 }
1623 uNewProcessID++;
1624 if (uNewProcessID == VBOX_GUESTCTRL_MAX_OBJECTS)
1625 uNewProcessID = 0;
1626
1627 if (++uTries == VBOX_GUESTCTRL_MAX_OBJECTS)
1628 break; /* Don't try too hard. */
1629 }
1630
1631 if (RT_FAILURE(rc))
1632 return rc;
1633
1634 /* Create the process object. */
1635 HRESULT hr = pProcess.createObject();
1636 if (FAILED(hr))
1637 return VERR_COM_UNEXPECTED;
1638
1639 rc = pProcess->init(mParent->getConsole() /* Console */, this /* Session */,
1640 uNewProcessID, procInfo);
1641 if (RT_FAILURE(rc))
1642 return rc;
1643
1644 /* Add the created process to our map. */
1645 try
1646 {
1647 mData.mProcesses[uNewProcessID] = pProcess;
1648 mData.mNumObjects++;
1649 Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS);
1650
1651 LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes, %ld objects)\n",
1652 mData.mSession.mID, uNewProcessID, mData.mProcesses.size(), mData.mNumObjects));
1653
1654 fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, pProcess,
1655 0 /* PID */, true /* Process registered */);
1656 }
1657 catch (std::bad_alloc &)
1658 {
1659 rc = VERR_NO_MEMORY;
1660 }
1661
1662 return rc;
1663}
1664
1665inline bool GuestSession::processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess)
1666{
1667 SessionProcesses::const_iterator it = mData.mProcesses.find(uProcessID);
1668 if (it != mData.mProcesses.end())
1669 {
1670 if (pProcess)
1671 *pProcess = it->second;
1672 return true;
1673 }
1674 return false;
1675}
1676
1677inline int GuestSession::processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess)
1678{
1679 AssertReturn(uPID, false);
1680 /* pProcess is optional. */
1681
1682 SessionProcesses::iterator itProcs = mData.mProcesses.begin();
1683 for (; itProcs != mData.mProcesses.end(); itProcs++)
1684 {
1685 ComObjPtr<GuestProcess> pCurProc = itProcs->second;
1686 AutoCaller procCaller(pCurProc);
1687 if (procCaller.rc())
1688 return VERR_COM_INVALID_OBJECT_STATE;
1689
1690 ULONG uCurPID;
1691 HRESULT hr = pCurProc->COMGETTER(PID)(&uCurPID);
1692 ComAssertComRC(hr);
1693
1694 if (uCurPID == uPID)
1695 {
1696 if (pProcess)
1697 *pProcess = pCurProc;
1698 return VINF_SUCCESS;
1699 }
1700 }
1701
1702 return VERR_NOT_FOUND;
1703}
1704
1705int GuestSession::sendCommand(uint32_t uFunction,
1706 uint32_t uParms, PVBOXHGCMSVCPARM paParms)
1707{
1708 LogFlowThisFuncEnter();
1709
1710#ifndef VBOX_GUESTCTRL_TEST_CASE
1711 ComObjPtr<Console> pConsole = mParent->getConsole();
1712 Assert(!pConsole.isNull());
1713
1714 /* Forward the information to the VMM device. */
1715 VMMDev *pVMMDev = pConsole->getVMMDev();
1716 AssertPtr(pVMMDev);
1717
1718 LogFlowThisFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms));
1719 int vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, uParms, paParms);
1720 if (RT_FAILURE(vrc))
1721 {
1722 /** @todo What to do here? */
1723 }
1724#else
1725 /* Not needed within testcases. */
1726 int vrc = VINF_SUCCESS;
1727#endif
1728 LogFlowFuncLeaveRC(vrc);
1729 return vrc;
1730}
1731
1732/* static */
1733HRESULT GuestSession::setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
1734{
1735 AssertPtr(pInterface);
1736 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
1737
1738 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestSession::guestErrorToString(guestRc).c_str());
1739}
1740
1741/* Does not do locking; caller is responsible for that! */
1742int GuestSession::setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc)
1743{
1744 LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, sessionRc=%Rrc\n",
1745 mData.mStatus, sessionStatus, sessionRc));
1746
1747 if (sessionStatus == GuestSessionStatus_Error)
1748 {
1749 AssertMsg(RT_FAILURE(sessionRc), ("Guest rc must be an error (%Rrc)\n", sessionRc));
1750 /* Do not allow overwriting an already set error. If this happens
1751 * this means we forgot some error checking/locking somewhere. */
1752 AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));
1753 }
1754 else
1755 AssertMsg(RT_SUCCESS(sessionRc), ("Guest rc must not be an error (%Rrc)\n", sessionRc));
1756
1757 if (mData.mStatus != sessionStatus)
1758 {
1759 mData.mStatus = sessionStatus;
1760 mData.mRC = sessionRc;
1761
1762 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
1763 HRESULT hr = errorInfo.createObject();
1764 ComAssertComRC(hr);
1765 int rc2 = errorInfo->initEx(VBOX_E_IPRT_ERROR, sessionRc,
1766 COM_IIDOF(IGuestSession), getComponentName(),
1767 guestErrorToString(sessionRc));
1768 AssertRC(rc2);
1769
1770 fireGuestSessionStateChangedEvent(mEventSource, this,
1771 mData.mSession.mID, sessionStatus, errorInfo);
1772 }
1773
1774 return VINF_SUCCESS;
1775}
1776
1777int GuestSession::signalWaiters(GuestSessionWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */)
1778{
1779 /*LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n",
1780 enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));*/
1781
1782 /* Note: No write locking here -- already done in the caller. */
1783
1784 int vrc = VINF_SUCCESS;
1785 /*if (mData.mWaitEvent)
1786 vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);*/
1787 LogFlowFuncLeaveRC(vrc);
1788 return vrc;
1789}
1790
1791int GuestSession::startTaskAsync(const Utf8Str &strTaskDesc,
1792 GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress)
1793{
1794 LogFlowThisFunc(("strTaskDesc=%s, pTask=%p\n", strTaskDesc.c_str(), pTask));
1795
1796 AssertPtrReturn(pTask, VERR_INVALID_POINTER);
1797
1798 /* Create the progress object. */
1799 HRESULT hr = pProgress.createObject();
1800 if (FAILED(hr))
1801 return VERR_COM_UNEXPECTED;
1802
1803 hr = pProgress->init(static_cast<IGuestSession*>(this),
1804 Bstr(strTaskDesc).raw(),
1805 TRUE /* aCancelable */);
1806 if (FAILED(hr))
1807 return VERR_COM_UNEXPECTED;
1808
1809 /* Initialize our worker task. */
1810 std::auto_ptr<GuestSessionTask> task(pTask);
1811
1812 int rc = task->RunAsync(strTaskDesc, pProgress);
1813 if (RT_FAILURE(rc))
1814 return rc;
1815
1816 /* Don't destruct on success. */
1817 task.release();
1818
1819 LogFlowFuncLeaveRC(rc);
1820 return rc;
1821}
1822
1823/**
1824 * Queries/collects information prior to establishing a guest session.
1825 * This is necessary to know which guest control protocol version to use,
1826 * among other things (later).
1827 *
1828 * @return IPRT status code.
1829 */
1830int GuestSession::queryInfo(void)
1831{
1832 /*
1833 * Try querying the guest control protocol version running on the guest.
1834 * This is done using the Guest Additions version
1835 */
1836 ComObjPtr<Guest> pGuest = mParent;
1837 Assert(!pGuest.isNull());
1838
1839 uint32_t uVerAdditions = pGuest->getAdditionsVersion();
1840 uint32_t uVBoxMajor = VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions);
1841 uint32_t uVBoxMinor = VBOX_FULL_VERSION_GET_MINOR(uVerAdditions);
1842
1843#ifdef DEBUG_andy
1844 /* Hardcode the to-used protocol version; nice for testing side effects. */
1845 mData.mProtocolVersion = 2;
1846#else
1847 mData.mProtocolVersion = (
1848 /* VBox 5.0 and up. */
1849 uVBoxMajor >= 5
1850 /* VBox 4.3 and up. */
1851 || (uVBoxMajor == 4 && uVBoxMinor >= 3))
1852 ? 2 /* Guest control 2.0. */
1853 : 1; /* Legacy guest control (VBox < 4.3). */
1854 /* Build revision is ignored. */
1855#endif
1856
1857 LogFlowThisFunc(("uVerAdditions=%RU32 (%RU32.%RU32), mProtocolVersion=%RU32\n",
1858 uVerAdditions, uVBoxMajor, uVBoxMinor, mData.mProtocolVersion));
1859
1860 /* Tell the user but don't bitch too often. */
1861 static short s_gctrlLegacyWarning = 0;
1862 if ( mData.mProtocolVersion < 2
1863 && s_gctrlLegacyWarning++ < 3) /** @todo Find a bit nicer text. */
1864 LogRel((tr("Warning: Guest Additions are older (%ld.%ld) than host capabilities for guest control, please upgrade them. Using protocol version %ld now\n"),
1865 uVBoxMajor, uVBoxMinor, mData.mProtocolVersion));
1866
1867 return VINF_SUCCESS;
1868}
1869
1870int GuestSession::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestSessionWaitResult_T &waitResult, int *pGuestRc)
1871{
1872 LogFlowThisFuncEnter();
1873
1874 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
1875
1876 /*LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",
1877 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));*/
1878
1879 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1880
1881 /* Did some error occur before? Then skip waiting and return. */
1882 if (mData.mStatus == GuestSessionStatus_Error)
1883 {
1884 waitResult = GuestSessionWaitResult_Error;
1885 AssertMsg(RT_FAILURE(mData.mRC), ("No error rc (%Rrc) set when guest session indicated an error\n", mData.mRC));
1886 if (pGuestRc)
1887 *pGuestRc = mData.mRC; /* Return last set error. */
1888 return VERR_GSTCTL_GUEST_ERROR;
1889 }
1890
1891 /* Guest Additions < 4.3 don't support session handling, skip. */
1892 if (mData.mProtocolVersion < 2)
1893 {
1894 waitResult = GuestSessionWaitResult_WaitFlagNotSupported;
1895
1896 LogFlowThisFunc(("Installed Guest Additions don't support waiting for dedicated sessions, skipping\n"));
1897 return VINF_SUCCESS;
1898 }
1899
1900 waitResult = GuestSessionWaitResult_None;
1901 if (fWaitFlags & GuestSessionWaitForFlag_Terminate)
1902 {
1903 switch (mData.mStatus)
1904 {
1905 case GuestSessionStatus_Terminated:
1906 case GuestSessionStatus_Down:
1907 waitResult = GuestSessionWaitResult_Terminate;
1908 break;
1909
1910 case GuestSessionStatus_TimedOutKilled:
1911 case GuestSessionStatus_TimedOutAbnormally:
1912 waitResult = GuestSessionWaitResult_Timeout;
1913 break;
1914
1915 case GuestSessionStatus_Error:
1916 /* Handled above. */
1917 break;
1918
1919 case GuestSessionStatus_Started:
1920 waitResult = GuestSessionWaitResult_Start;
1921 break;
1922
1923 case GuestSessionStatus_Undefined:
1924 case GuestSessionStatus_Starting:
1925 /* Do the waiting below. */
1926 break;
1927
1928 default:
1929 AssertMsgFailed(("Unhandled session status %ld\n", mData.mStatus));
1930 return VERR_NOT_IMPLEMENTED;
1931 }
1932 }
1933 else if (fWaitFlags & GuestSessionWaitForFlag_Start)
1934 {
1935 switch (mData.mStatus)
1936 {
1937 case GuestSessionStatus_Started:
1938 case GuestSessionStatus_Terminating:
1939 case GuestSessionStatus_Terminated:
1940 case GuestSessionStatus_Down:
1941 waitResult = GuestSessionWaitResult_Start;
1942 break;
1943
1944 case GuestSessionStatus_Error:
1945 waitResult = GuestSessionWaitResult_Error;
1946 break;
1947
1948 case GuestSessionStatus_TimedOutKilled:
1949 case GuestSessionStatus_TimedOutAbnormally:
1950 waitResult = GuestSessionWaitResult_Timeout;
1951 break;
1952
1953 case GuestSessionStatus_Undefined:
1954 case GuestSessionStatus_Starting:
1955 /* Do the waiting below. */
1956 break;
1957
1958 default:
1959 AssertMsgFailed(("Unhandled session status %ld\n", mData.mStatus));
1960 return VERR_NOT_IMPLEMENTED;
1961 }
1962 }
1963
1964 LogFlowThisFunc(("sessionStatus=%ld, sessionRc=%Rrc, waitResult=%ld\n",
1965 mData.mStatus, mData.mRC, waitResult));
1966
1967 /* No waiting needed? Return immediately using the last set error. */
1968 if (waitResult != GuestSessionWaitResult_None)
1969 {
1970 if (pGuestRc)
1971 *pGuestRc = mData.mRC; /* Return last set error (if any). */
1972 return RT_SUCCESS(mData.mRC) ? VINF_SUCCESS : VERR_GSTCTL_GUEST_ERROR;
1973 }
1974
1975 int vrc;
1976
1977 GuestWaitEvent *pEvent = NULL;
1978 std::list < VBoxEventType_T > eventTypes;
1979 try
1980 {
1981 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
1982
1983 vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */,
1984 eventTypes, &pEvent);
1985 }
1986 catch (std::bad_alloc)
1987 {
1988 vrc = VERR_NO_MEMORY;
1989 }
1990
1991 if (RT_FAILURE(vrc))
1992 return vrc;
1993
1994 alock.release(); /* Release lock before waiting. */
1995
1996 GuestSessionStatus_T sessionStatus;
1997 vrc = waitForStatusChange(pEvent, fWaitFlags,
1998 uTimeoutMS, &sessionStatus, pGuestRc);
1999 if (RT_SUCCESS(vrc))
2000 {
2001 switch (sessionStatus)
2002 {
2003 case GuestSessionStatus_Started:
2004 waitResult = GuestSessionWaitResult_Start;
2005 break;
2006
2007 case GuestSessionStatus_Terminated:
2008 waitResult = GuestSessionWaitResult_Terminate;
2009 break;
2010
2011 case GuestSessionStatus_TimedOutKilled:
2012 case GuestSessionStatus_TimedOutAbnormally:
2013 waitResult = GuestSessionWaitResult_Timeout;
2014 break;
2015
2016 case GuestSessionStatus_Down:
2017 waitResult = GuestSessionWaitResult_Terminate;
2018 break;
2019
2020 case GuestSessionStatus_Error:
2021 waitResult = GuestSessionWaitResult_Error;
2022 break;
2023
2024 default:
2025 waitResult = GuestSessionWaitResult_Status;
2026 break;
2027 }
2028 }
2029
2030 unregisterWaitEvent(pEvent);
2031
2032 LogFlowFuncLeaveRC(vrc);
2033 return vrc;
2034}
2035
2036int GuestSession::waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS,
2037 GuestSessionStatus_T *pSessionStatus, int *pGuestRc)
2038{
2039 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2040
2041 VBoxEventType_T evtType;
2042 ComPtr<IEvent> pIEvent;
2043 int vrc = waitForEvent(pEvent, uTimeoutMS,
2044 &evtType, pIEvent.asOutParam());
2045 if (RT_SUCCESS(vrc))
2046 {
2047 Assert(evtType == VBoxEventType_OnGuestSessionStateChanged);
2048
2049 ComPtr<IGuestSessionStateChangedEvent> pChangedEvent = pIEvent;
2050 Assert(!pChangedEvent.isNull());
2051
2052 GuestSessionStatus_T sessionStatus;
2053 pChangedEvent->COMGETTER(Status)(&sessionStatus);
2054 if (pSessionStatus)
2055 *pSessionStatus = sessionStatus;
2056
2057 ComPtr<IVirtualBoxErrorInfo> errorInfo;
2058 HRESULT hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam());
2059 ComAssertComRC(hr);
2060
2061 LONG lGuestRc;
2062 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
2063 ComAssertComRC(hr);
2064 if (RT_FAILURE((int)lGuestRc))
2065 vrc = VERR_GSTCTL_GUEST_ERROR;
2066 if (pGuestRc)
2067 *pGuestRc = (int)lGuestRc;
2068
2069 LogFlowThisFunc(("Status changed event for session ID=%RU32, new status is: %ld (%Rrc)\n",
2070 mData.mSession.mID, sessionStatus,
2071 RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc));
2072 }
2073
2074 LogFlowFuncLeaveRC(vrc);
2075 return vrc;
2076}
2077
2078// implementation of public methods
2079/////////////////////////////////////////////////////////////////////////////
2080
2081STDMETHODIMP GuestSession::Close(void)
2082{
2083#ifndef VBOX_WITH_GUEST_CONTROL
2084 ReturnComNotImplemented();
2085#else
2086 LogFlowThisFuncEnter();
2087
2088 AutoCaller autoCaller(this);
2089 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2090
2091 /* Close session on guest. */
2092 int guestRc = VINF_SUCCESS;
2093 int rc = closeSession(0 /* Flags */, 30 * 1000 /* Timeout */,
2094 &guestRc);
2095 /* On failure don't return here, instead do all the cleanup
2096 * work first and then return an error. */
2097
2098 /* Remove ourselves from the session list. */
2099 int rc2 = mParent->sessionRemove(this);
2100 if (RT_SUCCESS(rc))
2101 rc = rc2;
2102
2103 LogFlowThisFunc(("Returning rc=%Rrc, guestRc=%Rrc\n",
2104 rc, guestRc));
2105 if (RT_FAILURE(rc))
2106 {
2107 if (rc == VERR_GSTCTL_GUEST_ERROR)
2108 return GuestSession::setErrorExternal(this, guestRc);
2109
2110 return setError(VBOX_E_IPRT_ERROR,
2111 tr("Closing guest session failed with %Rrc"), rc);
2112 }
2113
2114 return S_OK;
2115#endif /* VBOX_WITH_GUEST_CONTROL */
2116}
2117
2118STDMETHODIMP GuestSession::CopyFrom(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
2119{
2120#ifndef VBOX_WITH_GUEST_CONTROL
2121 ReturnComNotImplemented();
2122#else
2123 CheckComArgStrNotEmptyOrNull(aSource);
2124 CheckComArgStrNotEmptyOrNull(aDest);
2125 CheckComArgOutPointerValid(aProgress);
2126
2127 LogFlowThisFuncEnter();
2128
2129 if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
2130 return setError(E_INVALIDARG, tr("No source specified"));
2131 if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
2132 return setError(E_INVALIDARG, tr("No destination specified"));
2133
2134 AutoCaller autoCaller(this);
2135 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2136
2137 uint32_t fFlags = CopyFileFlag_None;
2138 if (aFlags)
2139 {
2140 com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
2141 for (size_t i = 0; i < flags.size(); i++)
2142 fFlags |= flags[i];
2143 }
2144
2145 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2146
2147 HRESULT hr = S_OK;
2148
2149 try
2150 {
2151 ComObjPtr<Progress> pProgress;
2152 SessionTaskCopyFrom *pTask = new SessionTaskCopyFrom(this /* GuestSession */,
2153 Utf8Str(aSource), Utf8Str(aDest), fFlags);
2154 int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from guest to \"%ls\" on the host"), aSource, aDest),
2155 pTask, pProgress);
2156 if (RT_SUCCESS(rc))
2157 {
2158 /* Return progress to the caller. */
2159 hr = pProgress.queryInterfaceTo(aProgress);
2160 }
2161 else
2162 hr = setError(VBOX_E_IPRT_ERROR,
2163 tr("Starting task for copying file \"%ls\" from guest to \"%ls\" on the host failed: %Rrc"), rc);
2164 }
2165 catch(std::bad_alloc &)
2166 {
2167 hr = E_OUTOFMEMORY;
2168 }
2169
2170 return hr;
2171#endif /* VBOX_WITH_GUEST_CONTROL */
2172}
2173
2174STDMETHODIMP GuestSession::CopyTo(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
2175{
2176#ifndef VBOX_WITH_GUEST_CONTROL
2177 ReturnComNotImplemented();
2178#else
2179 CheckComArgStrNotEmptyOrNull(aSource);
2180 CheckComArgStrNotEmptyOrNull(aDest);
2181 CheckComArgOutPointerValid(aProgress);
2182
2183 LogFlowThisFuncEnter();
2184
2185 if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
2186 return setError(E_INVALIDARG, tr("No source specified"));
2187 if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
2188 return setError(E_INVALIDARG, tr("No destination specified"));
2189
2190 AutoCaller autoCaller(this);
2191 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2192
2193 uint32_t fFlags = CopyFileFlag_None;
2194 if (aFlags)
2195 {
2196 com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
2197 for (size_t i = 0; i < flags.size(); i++)
2198 fFlags |= flags[i];
2199 }
2200
2201 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2202
2203 HRESULT hr = S_OK;
2204
2205 try
2206 {
2207 ComObjPtr<Progress> pProgress;
2208 SessionTaskCopyTo *pTask = new SessionTaskCopyTo(this /* GuestSession */,
2209 Utf8Str(aSource), Utf8Str(aDest), fFlags);
2210 AssertPtrReturn(pTask, E_OUTOFMEMORY);
2211 int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from host to \"%ls\" on the guest"), aSource, aDest),
2212 pTask, pProgress);
2213 if (RT_SUCCESS(rc))
2214 {
2215 /* Return progress to the caller. */
2216 hr = pProgress.queryInterfaceTo(aProgress);
2217 }
2218 else
2219 hr = setError(VBOX_E_IPRT_ERROR,
2220 tr("Starting task for copying file \"%ls\" from host to \"%ls\" on the guest failed: %Rrc"), rc);
2221 }
2222 catch(std::bad_alloc &)
2223 {
2224 hr = E_OUTOFMEMORY;
2225 }
2226
2227 return hr;
2228#endif /* VBOX_WITH_GUEST_CONTROL */
2229}
2230
2231STDMETHODIMP GuestSession::DirectoryCreate(IN_BSTR aPath, ULONG aMode,
2232 ComSafeArrayIn(DirectoryCreateFlag_T, aFlags))
2233{
2234#ifndef VBOX_WITH_GUEST_CONTROL
2235 ReturnComNotImplemented();
2236#else
2237 LogFlowThisFuncEnter();
2238
2239 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2240 return setError(E_INVALIDARG, tr("No directory to create specified"));
2241
2242 AutoCaller autoCaller(this);
2243 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2244
2245 uint32_t fFlags = DirectoryCreateFlag_None;
2246 if (aFlags)
2247 {
2248 com::SafeArray<DirectoryCreateFlag_T> flags(ComSafeArrayInArg(aFlags));
2249 for (size_t i = 0; i < flags.size(); i++)
2250 fFlags |= flags[i];
2251
2252 if (fFlags)
2253 {
2254 if (!(fFlags & DirectoryCreateFlag_Parents))
2255 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), fFlags);
2256 }
2257 }
2258
2259 HRESULT hr = S_OK;
2260
2261 ComObjPtr <GuestDirectory> pDirectory; int guestRc;
2262 int rc = directoryCreateInternal(Utf8Str(aPath), (uint32_t)aMode, fFlags, &guestRc);
2263 if (RT_FAILURE(rc))
2264 {
2265 switch (rc)
2266 {
2267 case VERR_GSTCTL_GUEST_ERROR:
2268 hr = GuestProcess::setErrorExternal(this, guestRc);
2269 break;
2270
2271 case VERR_INVALID_PARAMETER:
2272 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Invalid parameters given"));
2273 break;
2274
2275 case VERR_BROKEN_PIPE:
2276 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Unexpectedly aborted"));
2277 break;
2278
2279 case VERR_CANT_CREATE:
2280 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Could not create directory"));
2281 break;
2282
2283 default:
2284 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
2285 break;
2286 }
2287 }
2288
2289 return hr;
2290#endif /* VBOX_WITH_GUEST_CONTROL */
2291}
2292
2293STDMETHODIMP GuestSession::DirectoryCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, BSTR *aDirectory)
2294{
2295#ifndef VBOX_WITH_GUEST_CONTROL
2296 ReturnComNotImplemented();
2297#else
2298 LogFlowThisFuncEnter();
2299
2300 if (RT_UNLIKELY((aTemplate) == NULL || *(aTemplate) == '\0'))
2301 return setError(E_INVALIDARG, tr("No template specified"));
2302 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2303 return setError(E_INVALIDARG, tr("No directory name specified"));
2304 CheckComArgOutPointerValid(aDirectory);
2305
2306 AutoCaller autoCaller(this);
2307 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2308
2309 HRESULT hr = S_OK;
2310
2311 Utf8Str strName; int guestRc;
2312 int rc = objectCreateTempInternal(Utf8Str(aTemplate),
2313 Utf8Str(aPath),
2314 true /* Directory */, strName, &guestRc);
2315 if (RT_SUCCESS(rc))
2316 {
2317 strName.cloneTo(aDirectory);
2318 }
2319 else
2320 {
2321 switch (rc)
2322 {
2323 case VERR_GSTCTL_GUEST_ERROR:
2324 hr = GuestProcess::setErrorExternal(this, guestRc);
2325 break;
2326
2327 default:
2328 hr = setError(VBOX_E_IPRT_ERROR, tr("Temporary directory creation \"%s\" with template \"%s\" failed: %Rrc"),
2329 Utf8Str(aPath).c_str(), Utf8Str(aTemplate).c_str(), rc);
2330 break;
2331 }
2332 }
2333
2334 return hr;
2335#endif /* VBOX_WITH_GUEST_CONTROL */
2336}
2337
2338STDMETHODIMP GuestSession::DirectoryExists(IN_BSTR aPath, BOOL *aExists)
2339{
2340#ifndef VBOX_WITH_GUEST_CONTROL
2341 ReturnComNotImplemented();
2342#else
2343 LogFlowThisFuncEnter();
2344
2345 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2346 return setError(E_INVALIDARG, tr("No directory to check existence for specified"));
2347 CheckComArgOutPointerValid(aExists);
2348
2349 AutoCaller autoCaller(this);
2350 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2351
2352 HRESULT hr = S_OK;
2353
2354 GuestFsObjData objData; int guestRc;
2355 int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
2356 if (RT_SUCCESS(rc))
2357 {
2358 *aExists = objData.mType == FsObjType_Directory;
2359 }
2360 else
2361 {
2362 switch (rc)
2363 {
2364 case VERR_GSTCTL_GUEST_ERROR:
2365 hr = GuestProcess::setErrorExternal(this, guestRc);
2366 break;
2367
2368 default:
2369 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence \"%s\" failed: %Rrc"),
2370 Utf8Str(aPath).c_str(), rc);
2371 break;
2372 }
2373 }
2374
2375 return hr;
2376#endif /* VBOX_WITH_GUEST_CONTROL */
2377}
2378
2379STDMETHODIMP GuestSession::DirectoryOpen(IN_BSTR aPath, IN_BSTR aFilter, ComSafeArrayIn(DirectoryOpenFlag_T, aFlags), IGuestDirectory **aDirectory)
2380{
2381#ifndef VBOX_WITH_GUEST_CONTROL
2382 ReturnComNotImplemented();
2383#else
2384 LogFlowThisFuncEnter();
2385
2386 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2387 return setError(E_INVALIDARG, tr("No directory to open specified"));
2388 if (RT_UNLIKELY((aFilter) != NULL && *(aFilter) != '\0'))
2389 return setError(E_INVALIDARG, tr("Directory filters are not implemented yet"));
2390 CheckComArgOutPointerValid(aDirectory);
2391
2392 AutoCaller autoCaller(this);
2393 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2394
2395 uint32_t fFlags = DirectoryOpenFlag_None;
2396 if (aFlags)
2397 {
2398 com::SafeArray<DirectoryOpenFlag_T> flags(ComSafeArrayInArg(aFlags));
2399 for (size_t i = 0; i < flags.size(); i++)
2400 fFlags |= flags[i];
2401
2402 if (fFlags)
2403 return setError(E_INVALIDARG, tr("Open flags (%#x) not implemented yet"), fFlags);
2404 }
2405
2406 HRESULT hr = S_OK;
2407
2408 ComObjPtr <GuestDirectory> pDirectory;
2409 int rc = directoryOpenInternal(Utf8Str(aPath), Utf8Str(aFilter), fFlags, pDirectory);
2410 if (RT_SUCCESS(rc))
2411 {
2412 /* Return directory object to the caller. */
2413 hr = pDirectory.queryInterfaceTo(aDirectory);
2414 }
2415 else
2416 {
2417 switch (rc)
2418 {
2419 case VERR_INVALID_PARAMETER:
2420 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed; invalid parameters given",
2421 Utf8Str(aPath).c_str()));
2422 break;
2423
2424 default:
2425 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed: %Rrc"),
2426 Utf8Str(aPath).c_str(),rc);
2427 break;
2428 }
2429 }
2430
2431 return hr;
2432#endif /* VBOX_WITH_GUEST_CONTROL */
2433}
2434
2435STDMETHODIMP GuestSession::DirectoryQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
2436{
2437#ifndef VBOX_WITH_GUEST_CONTROL
2438 ReturnComNotImplemented();
2439#else
2440 LogFlowThisFuncEnter();
2441
2442 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2443 return setError(E_INVALIDARG, tr("No directory to query information for specified"));
2444 CheckComArgOutPointerValid(aInfo);
2445
2446 AutoCaller autoCaller(this);
2447 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2448
2449 HRESULT hr = S_OK;
2450
2451 GuestFsObjData objData; int guestRc;
2452 int vrc = directoryQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
2453 if (RT_SUCCESS(vrc))
2454 {
2455 if (objData.mType == FsObjType_Directory)
2456 {
2457 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
2458 hr = pFsObjInfo.createObject();
2459 if (FAILED(hr)) return hr;
2460
2461 vrc = pFsObjInfo->init(objData);
2462 if (RT_SUCCESS(vrc))
2463 {
2464 hr = pFsObjInfo.queryInterfaceTo(aInfo);
2465 if (FAILED(hr)) return hr;
2466 }
2467 }
2468 }
2469
2470 if (RT_FAILURE(vrc))
2471 {
2472 switch (vrc)
2473 {
2474 case VERR_GSTCTL_GUEST_ERROR:
2475 hr = GuestProcess::setErrorExternal(this, guestRc);
2476 break;
2477
2478 case VERR_NOT_A_DIRECTORY:
2479 hr = setError(VBOX_E_IPRT_ERROR, tr("Element \"%s\" exists but is not a directory",
2480 Utf8Str(aPath).c_str()));
2481 break;
2482
2483 default:
2484 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information for \"%s\" failed: %Rrc"),
2485 Utf8Str(aPath).c_str(), vrc);
2486 break;
2487 }
2488 }
2489
2490 return hr;
2491#endif /* VBOX_WITH_GUEST_CONTROL */
2492}
2493
2494STDMETHODIMP GuestSession::DirectoryRemove(IN_BSTR aPath)
2495{
2496#ifndef VBOX_WITH_GUEST_CONTROL
2497 ReturnComNotImplemented();
2498#else
2499 LogFlowThisFuncEnter();
2500
2501 AutoCaller autoCaller(this);
2502 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2503
2504 ReturnComNotImplemented();
2505#endif /* VBOX_WITH_GUEST_CONTROL */
2506}
2507
2508STDMETHODIMP GuestSession::DirectoryRemoveRecursive(IN_BSTR aPath, ComSafeArrayIn(DirectoryRemoveRecFlag_T, aFlags), IProgress **aProgress)
2509{
2510#ifndef VBOX_WITH_GUEST_CONTROL
2511 ReturnComNotImplemented();
2512#else
2513 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
2522STDMETHODIMP GuestSession::DirectoryRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
2523{
2524#ifndef VBOX_WITH_GUEST_CONTROL
2525 ReturnComNotImplemented();
2526#else
2527 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
2536STDMETHODIMP GuestSession::DirectorySetACL(IN_BSTR aPath, IN_BSTR aACL)
2537{
2538#ifndef VBOX_WITH_GUEST_CONTROL
2539 ReturnComNotImplemented();
2540#else
2541 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
2550STDMETHODIMP GuestSession::EnvironmentClear(void)
2551{
2552#ifndef VBOX_WITH_GUEST_CONTROL
2553 ReturnComNotImplemented();
2554#else
2555 LogFlowThisFuncEnter();
2556
2557 AutoCaller autoCaller(this);
2558 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2559
2560 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2561
2562 mData.mEnvironment.Clear();
2563
2564 LogFlowThisFuncLeave();
2565 return S_OK;
2566#endif /* VBOX_WITH_GUEST_CONTROL */
2567}
2568
2569STDMETHODIMP GuestSession::EnvironmentGet(IN_BSTR aName, BSTR *aValue)
2570{
2571#ifndef VBOX_WITH_GUEST_CONTROL
2572 ReturnComNotImplemented();
2573#else
2574 LogFlowThisFuncEnter();
2575
2576 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
2577 return setError(E_INVALIDARG, tr("No value name specified"));
2578
2579 CheckComArgOutPointerValid(aValue);
2580
2581 AutoCaller autoCaller(this);
2582 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2583
2584 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2585
2586 Bstr strValue(mData.mEnvironment.Get(Utf8Str(aName)));
2587 strValue.cloneTo(aValue);
2588
2589 LogFlowThisFuncLeave();
2590 return S_OK;
2591#endif /* VBOX_WITH_GUEST_CONTROL */
2592}
2593
2594STDMETHODIMP GuestSession::EnvironmentSet(IN_BSTR aName, IN_BSTR aValue)
2595{
2596#ifndef VBOX_WITH_GUEST_CONTROL
2597 ReturnComNotImplemented();
2598#else
2599 LogFlowThisFuncEnter();
2600
2601 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
2602 return setError(E_INVALIDARG, tr("No value name specified"));
2603
2604 AutoCaller autoCaller(this);
2605 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2606
2607 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2608
2609 int rc = mData.mEnvironment.Set(Utf8Str(aName), Utf8Str(aValue));
2610
2611 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
2612 LogFlowFuncLeaveRC(hr);
2613 return hr;
2614#endif /* VBOX_WITH_GUEST_CONTROL */
2615}
2616
2617STDMETHODIMP GuestSession::EnvironmentUnset(IN_BSTR aName)
2618{
2619#ifndef VBOX_WITH_GUEST_CONTROL
2620 ReturnComNotImplemented();
2621#else
2622 LogFlowThisFuncEnter();
2623
2624 AutoCaller autoCaller(this);
2625 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2626
2627 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2628
2629 mData.mEnvironment.Unset(Utf8Str(aName));
2630
2631 LogFlowThisFuncLeave();
2632 return S_OK;
2633#endif /* VBOX_WITH_GUEST_CONTROL */
2634}
2635
2636STDMETHODIMP GuestSession::FileCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, IGuestFile **aFile)
2637{
2638#ifndef VBOX_WITH_GUEST_CONTROL
2639 ReturnComNotImplemented();
2640#else
2641 LogFlowThisFuncEnter();
2642
2643 AutoCaller autoCaller(this);
2644 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2645
2646 ReturnComNotImplemented();
2647#endif /* VBOX_WITH_GUEST_CONTROL */
2648}
2649
2650STDMETHODIMP GuestSession::FileExists(IN_BSTR aPath, BOOL *aExists)
2651{
2652#ifndef VBOX_WITH_GUEST_CONTROL
2653 ReturnComNotImplemented();
2654#else
2655 LogFlowThisFuncEnter();
2656
2657 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2658 return setError(E_INVALIDARG, tr("No file to check existence for specified"));
2659 CheckComArgOutPointerValid(aExists);
2660
2661 AutoCaller autoCaller(this);
2662 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2663
2664 GuestFsObjData objData; int guestRc;
2665 int vrc = fileQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
2666 if (RT_SUCCESS(vrc))
2667 {
2668 *aExists = TRUE;
2669 return S_OK;
2670 }
2671
2672 HRESULT hr = S_OK;
2673
2674 switch (vrc)
2675 {
2676 case VERR_GSTCTL_GUEST_ERROR:
2677 hr = GuestProcess::setErrorExternal(this, guestRc);
2678 break;
2679
2680 case VERR_NOT_A_FILE:
2681 *aExists = FALSE;
2682 break;
2683
2684 default:
2685 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information for \"%s\" failed: %Rrc"),
2686 Utf8Str(aPath).c_str(), vrc);
2687 break;
2688 }
2689
2690 return hr;
2691#endif /* VBOX_WITH_GUEST_CONTROL */
2692}
2693
2694STDMETHODIMP GuestSession::FileRemove(IN_BSTR aPath)
2695{
2696#ifndef VBOX_WITH_GUEST_CONTROL
2697 ReturnComNotImplemented();
2698#else
2699 LogFlowThisFuncEnter();
2700
2701 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2702 return setError(E_INVALIDARG, tr("No file to remove specified"));
2703
2704 AutoCaller autoCaller(this);
2705 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2706
2707 HRESULT hr = S_OK;
2708
2709 int guestRc;
2710 int vrc = fileRemoveInternal(Utf8Str(aPath), &guestRc);
2711 if (RT_FAILURE(vrc))
2712 {
2713 switch (vrc)
2714 {
2715 case VERR_GSTCTL_GUEST_ERROR:
2716 hr = GuestProcess::setErrorExternal(this, guestRc);
2717 break;
2718
2719 default:
2720 hr = setError(VBOX_E_IPRT_ERROR, tr("Removing file \"%s\" failed: %Rrc"),
2721 Utf8Str(aPath).c_str(), vrc);
2722 break;
2723 }
2724 }
2725
2726 return hr;
2727#endif /* VBOX_WITH_GUEST_CONTROL */
2728}
2729
2730STDMETHODIMP GuestSession::FileOpen(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, ULONG aCreationMode, LONG64 aOffset, IGuestFile **aFile)
2731{
2732#ifndef VBOX_WITH_GUEST_CONTROL
2733 ReturnComNotImplemented();
2734#else
2735 LogFlowThisFuncEnter();
2736
2737 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2738 return setError(E_INVALIDARG, tr("No file to open specified"));
2739 if (RT_UNLIKELY((aOpenMode) == NULL || *(aOpenMode) == '\0'))
2740 return setError(E_INVALIDARG, tr("No open mode specified"));
2741 if (RT_UNLIKELY((aDisposition) == NULL || *(aDisposition) == '\0'))
2742 return setError(E_INVALIDARG, tr("No disposition mode specified"));
2743
2744 CheckComArgOutPointerValid(aFile);
2745
2746 AutoCaller autoCaller(this);
2747 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2748
2749 HRESULT hr = isReadyExternal();
2750 if (FAILED(hr))
2751 return hr;
2752
2753 /** @todo Validate open mode. */
2754 /** @todo Validate disposition mode. */
2755
2756 /** @todo Validate creation mode. */
2757 uint32_t uCreationMode = 0;
2758
2759 GuestFileOpenInfo openInfo;
2760 openInfo.mFileName = Utf8Str(aPath);
2761 openInfo.mOpenMode = Utf8Str(aOpenMode);
2762 openInfo.mDisposition = Utf8Str(aDisposition);
2763 openInfo.mCreationMode = aCreationMode;
2764 openInfo.mInitialOffset = aOffset;
2765
2766 ComObjPtr <GuestFile> pFile; int guestRc;
2767 int vrc = fileOpenInternal(openInfo, pFile, &guestRc);
2768 if (RT_SUCCESS(vrc))
2769 {
2770 /* Return directory object to the caller. */
2771 hr = pFile.queryInterfaceTo(aFile);
2772 }
2773 else
2774 {
2775 switch (vrc)
2776 {
2777 case VERR_NOT_SUPPORTED:
2778 hr = setError(VBOX_E_IPRT_ERROR,
2779 tr("Handling guest files not supported by installed Guest Additions"));
2780 break;
2781
2782 case VERR_GSTCTL_GUEST_ERROR:
2783 hr = GuestFile::setErrorExternal(this, guestRc);
2784 break;
2785
2786 default:
2787 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening guest file \"%s\" failed: %Rrc"),
2788 Utf8Str(aPath).c_str(), vrc);
2789 break;
2790 }
2791 }
2792
2793 return hr;
2794#endif /* VBOX_WITH_GUEST_CONTROL */
2795}
2796
2797STDMETHODIMP GuestSession::FileQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
2798{
2799#ifndef VBOX_WITH_GUEST_CONTROL
2800 ReturnComNotImplemented();
2801#else
2802 LogFlowThisFuncEnter();
2803
2804 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2805 return setError(E_INVALIDARG, tr("No file to query information for specified"));
2806 CheckComArgOutPointerValid(aInfo);
2807
2808 AutoCaller autoCaller(this);
2809 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2810
2811 HRESULT hr = S_OK;
2812
2813 GuestFsObjData objData; int guestRc;
2814 int vrc = fileQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
2815 if (RT_SUCCESS(vrc))
2816 {
2817 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
2818 hr = pFsObjInfo.createObject();
2819 if (FAILED(hr)) return hr;
2820
2821 vrc = pFsObjInfo->init(objData);
2822 if (RT_SUCCESS(vrc))
2823 {
2824 hr = pFsObjInfo.queryInterfaceTo(aInfo);
2825 if (FAILED(hr)) return hr;
2826 }
2827 }
2828
2829 if (RT_FAILURE(vrc))
2830 {
2831 switch (vrc)
2832 {
2833 case VERR_GSTCTL_GUEST_ERROR:
2834 hr = GuestProcess::setErrorExternal(this, guestRc);
2835 break;
2836
2837 case VERR_NOT_A_FILE:
2838 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a file"));
2839 break;
2840
2841 default:
2842 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), vrc);
2843 break;
2844 }
2845 }
2846
2847 return hr;
2848#endif /* VBOX_WITH_GUEST_CONTROL */
2849}
2850
2851STDMETHODIMP GuestSession::FileQuerySize(IN_BSTR aPath, LONG64 *aSize)
2852{
2853#ifndef VBOX_WITH_GUEST_CONTROL
2854 ReturnComNotImplemented();
2855#else
2856 LogFlowThisFuncEnter();
2857
2858 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2859 return setError(E_INVALIDARG, tr("No file to query size for specified"));
2860 CheckComArgOutPointerValid(aSize);
2861
2862 AutoCaller autoCaller(this);
2863 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2864
2865 HRESULT hr = S_OK;
2866
2867 int64_t llSize; int guestRc;
2868 int vrc = fileQuerySizeInternal(Utf8Str(aPath), &llSize, &guestRc);
2869 if (RT_SUCCESS(vrc))
2870 {
2871 *aSize = llSize;
2872 }
2873 else
2874 {
2875 switch (vrc)
2876 {
2877 case VERR_GSTCTL_GUEST_ERROR:
2878 hr = GuestProcess::setErrorExternal(this, guestRc);
2879 break;
2880
2881 default:
2882 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), vrc);
2883 break;
2884 }
2885 }
2886
2887 return hr;
2888#endif /* VBOX_WITH_GUEST_CONTROL */
2889}
2890
2891STDMETHODIMP GuestSession::FileRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
2892{
2893#ifndef VBOX_WITH_GUEST_CONTROL
2894 ReturnComNotImplemented();
2895#else
2896 LogFlowThisFuncEnter();
2897
2898 AutoCaller autoCaller(this);
2899 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2900
2901 ReturnComNotImplemented();
2902#endif /* VBOX_WITH_GUEST_CONTROL */
2903}
2904
2905STDMETHODIMP GuestSession::FileSetACL(IN_BSTR aPath, IN_BSTR aACL)
2906{
2907#ifndef VBOX_WITH_GUEST_CONTROL
2908 ReturnComNotImplemented();
2909#else
2910 LogFlowThisFuncEnter();
2911
2912 AutoCaller autoCaller(this);
2913 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2914
2915 ReturnComNotImplemented();
2916#endif /* VBOX_WITH_GUEST_CONTROL */
2917}
2918
2919STDMETHODIMP GuestSession::ProcessCreate(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
2920 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS, IGuestProcess **aProcess)
2921{
2922#ifndef VBOX_WITH_GUEST_CONTROL
2923 ReturnComNotImplemented();
2924#else
2925 LogFlowThisFuncEnter();
2926
2927 com::SafeArray<LONG> affinityIgnored;
2928
2929 return ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),
2930 ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinityIgnored), aProcess);
2931#endif /* VBOX_WITH_GUEST_CONTROL */
2932}
2933
2934STDMETHODIMP GuestSession::ProcessCreateEx(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
2935 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS,
2936 ProcessPriority_T aPriority, ComSafeArrayIn(LONG, aAffinity),
2937 IGuestProcess **aProcess)
2938{
2939#ifndef VBOX_WITH_GUEST_CONTROL
2940 ReturnComNotImplemented();
2941#else
2942 LogFlowThisFuncEnter();
2943
2944 if (RT_UNLIKELY((aCommand) == NULL || *(aCommand) == '\0'))
2945 return setError(E_INVALIDARG, tr("No command to execute specified"));
2946 CheckComArgOutPointerValid(aProcess);
2947
2948 AutoCaller autoCaller(this);
2949 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2950
2951 HRESULT hr = isReadyExternal();
2952 if (FAILED(hr))
2953 return hr;
2954
2955 GuestProcessStartupInfo procInfo;
2956 procInfo.mCommand = Utf8Str(aCommand);
2957
2958 if (aArguments)
2959 {
2960 com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments));
2961 for (size_t i = 0; i < arguments.size(); i++)
2962 procInfo.mArguments.push_back(Utf8Str(arguments[i]));
2963 }
2964
2965 int rc = VINF_SUCCESS;
2966
2967 /*
2968 * Create the process environment:
2969 * - Apply the session environment in a first step, and
2970 * - Apply environment variables specified by this call to
2971 * have the chance of overwriting/deleting session entries.
2972 */
2973 procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
2974
2975 if (aEnvironment)
2976 {
2977 com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aEnvironment));
2978 for (size_t i = 0; i < environment.size() && RT_SUCCESS(rc); i++)
2979 rc = procInfo.mEnvironment.Set(Utf8Str(environment[i]));
2980 }
2981
2982 if (RT_SUCCESS(rc))
2983 {
2984 if (aFlags)
2985 {
2986 com::SafeArray<ProcessCreateFlag_T> flags(ComSafeArrayInArg(aFlags));
2987 for (size_t i = 0; i < flags.size(); i++)
2988 procInfo.mFlags |= flags[i];
2989 }
2990
2991 procInfo.mTimeoutMS = aTimeoutMS;
2992
2993 if (aAffinity)
2994 {
2995 com::SafeArray<LONG> affinity(ComSafeArrayInArg(aAffinity));
2996 for (size_t i = 0; i < affinity.size(); i++)
2997 {
2998 if (affinity[i])
2999 procInfo.mAffinity |= (uint64_t)1 << i;
3000 }
3001 }
3002
3003 procInfo.mPriority = aPriority;
3004
3005 ComObjPtr<GuestProcess> pProcess;
3006 rc = processCreateExInteral(procInfo, pProcess);
3007 if (RT_SUCCESS(rc))
3008 {
3009 /* Return guest session to the caller. */
3010 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
3011 if (FAILED(hr2))
3012 rc = VERR_COM_OBJECT_NOT_FOUND;
3013
3014 if (RT_SUCCESS(rc))
3015 rc = pProcess->startProcessAsync();
3016 }
3017 }
3018
3019 if (RT_FAILURE(rc))
3020 {
3021 switch (rc)
3022 {
3023 case VERR_MAX_PROCS_REACHED:
3024 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest processes per session (%ld) reached"),
3025 VBOX_GUESTCTRL_MAX_OBJECTS);
3026 break;
3027
3028 /** @todo Add more errors here. */
3029
3030 default:
3031 hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest process, rc=%Rrc"), rc);
3032 break;
3033 }
3034 }
3035
3036 LogFlowFuncLeaveRC(rc);
3037 return hr;
3038#endif /* VBOX_WITH_GUEST_CONTROL */
3039}
3040
3041STDMETHODIMP GuestSession::ProcessGet(ULONG aPID, IGuestProcess **aProcess)
3042{
3043#ifndef VBOX_WITH_GUEST_CONTROL
3044 ReturnComNotImplemented();
3045#else
3046 LogFlowThisFunc(("aPID=%RU32\n", aPID));
3047
3048 CheckComArgOutPointerValid(aProcess);
3049 if (aPID == 0)
3050 return setError(E_INVALIDARG, tr("No valid process ID (PID) specified"));
3051
3052 AutoCaller autoCaller(this);
3053 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3054
3055 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
3056
3057 HRESULT hr = S_OK;
3058
3059 ComObjPtr<GuestProcess> pProcess;
3060 int rc = processGetByPID(aPID, &pProcess);
3061 if (RT_FAILURE(rc))
3062 hr = setError(E_INVALIDARG, tr("No process with PID %RU32 found"), aPID);
3063
3064 /* This will set (*aProcess) to NULL if pProgress is NULL. */
3065 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
3066 if (SUCCEEDED(hr))
3067 hr = hr2;
3068
3069 LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", *aProcess, hr));
3070 return hr;
3071#endif /* VBOX_WITH_GUEST_CONTROL */
3072}
3073
3074STDMETHODIMP GuestSession::SymlinkCreate(IN_BSTR aSource, IN_BSTR aTarget, SymlinkType_T aType)
3075{
3076#ifndef VBOX_WITH_GUEST_CONTROL
3077 ReturnComNotImplemented();
3078#else
3079 LogFlowThisFuncEnter();
3080
3081 AutoCaller autoCaller(this);
3082 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3083
3084 ReturnComNotImplemented();
3085#endif /* VBOX_WITH_GUEST_CONTROL */
3086}
3087
3088STDMETHODIMP GuestSession::SymlinkExists(IN_BSTR aSymlink, BOOL *aExists)
3089{
3090#ifndef VBOX_WITH_GUEST_CONTROL
3091 ReturnComNotImplemented();
3092#else
3093 LogFlowThisFuncEnter();
3094
3095 AutoCaller autoCaller(this);
3096 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3097
3098 ReturnComNotImplemented();
3099#endif /* VBOX_WITH_GUEST_CONTROL */
3100}
3101
3102STDMETHODIMP GuestSession::SymlinkRead(IN_BSTR aSymlink, ComSafeArrayIn(SymlinkReadFlag_T, aFlags), BSTR *aTarget)
3103{
3104#ifndef VBOX_WITH_GUEST_CONTROL
3105 ReturnComNotImplemented();
3106#else
3107 LogFlowThisFuncEnter();
3108
3109 AutoCaller autoCaller(this);
3110 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3111
3112 ReturnComNotImplemented();
3113#endif /* VBOX_WITH_GUEST_CONTROL */
3114}
3115
3116STDMETHODIMP GuestSession::SymlinkRemoveDirectory(IN_BSTR aPath)
3117{
3118#ifndef VBOX_WITH_GUEST_CONTROL
3119 ReturnComNotImplemented();
3120#else
3121 LogFlowThisFuncEnter();
3122
3123 AutoCaller autoCaller(this);
3124 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3125
3126 ReturnComNotImplemented();
3127#endif /* VBOX_WITH_GUEST_CONTROL */
3128}
3129
3130STDMETHODIMP GuestSession::SymlinkRemoveFile(IN_BSTR aFile)
3131{
3132#ifndef VBOX_WITH_GUEST_CONTROL
3133 ReturnComNotImplemented();
3134#else
3135 LogFlowThisFuncEnter();
3136
3137 AutoCaller autoCaller(this);
3138 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3139
3140 ReturnComNotImplemented();
3141#endif /* VBOX_WITH_GUEST_CONTROL */
3142}
3143
3144STDMETHODIMP GuestSession::WaitFor(ULONG aWaitFlags, ULONG aTimeoutMS, GuestSessionWaitResult_T *aReason)
3145{
3146#ifndef VBOX_WITH_GUEST_CONTROL
3147 ReturnComNotImplemented();
3148#else
3149 LogFlowThisFuncEnter();
3150
3151 CheckComArgOutPointerValid(aReason);
3152
3153 AutoCaller autoCaller(this);
3154 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3155
3156 /*
3157 * Note: Do not hold any locks here while waiting!
3158 */
3159 HRESULT hr = S_OK;
3160
3161 int guestRc; GuestSessionWaitResult_T waitResult;
3162 int vrc = waitFor(aWaitFlags, aTimeoutMS, waitResult, &guestRc);
3163 if (RT_SUCCESS(vrc))
3164 {
3165 *aReason = waitResult;
3166 }
3167 else
3168 {
3169 switch (vrc)
3170 {
3171 case VERR_GSTCTL_GUEST_ERROR:
3172 hr = GuestSession::setErrorExternal(this, guestRc);
3173 break;
3174
3175 case VERR_TIMEOUT:
3176 *aReason = GuestSessionWaitResult_Timeout;
3177 break;
3178
3179 default:
3180 {
3181 const char *pszSessionName = mData.mSession.mName.c_str();
3182 hr = setError(VBOX_E_IPRT_ERROR,
3183 tr("Waiting for guest session \"%s\" failed: %Rrc"),
3184 pszSessionName ? pszSessionName : tr("Unnamed"), vrc);
3185 break;
3186 }
3187 }
3188 }
3189
3190 LogFlowFuncLeaveRC(vrc);
3191 return hr;
3192#endif /* VBOX_WITH_GUEST_CONTROL */
3193}
3194
3195STDMETHODIMP GuestSession::WaitForArray(ComSafeArrayIn(GuestSessionWaitForFlag_T, aFlags), ULONG aTimeoutMS, GuestSessionWaitResult_T *aReason)
3196{
3197#ifndef VBOX_WITH_GUEST_CONTROL
3198 ReturnComNotImplemented();
3199#else
3200 LogFlowThisFuncEnter();
3201
3202 CheckComArgOutPointerValid(aReason);
3203
3204 AutoCaller autoCaller(this);
3205 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3206
3207 /*
3208 * Note: Do not hold any locks here while waiting!
3209 */
3210 uint32_t fWaitFor = GuestSessionWaitForFlag_None;
3211 com::SafeArray<GuestSessionWaitForFlag_T> flags(ComSafeArrayInArg(aFlags));
3212 for (size_t i = 0; i < flags.size(); i++)
3213 fWaitFor |= flags[i];
3214
3215 return WaitFor(fWaitFor, aTimeoutMS, aReason);
3216#endif /* VBOX_WITH_GUEST_CONTROL */
3217}
3218
Note: See TracBrowser for help on using the repository browser.

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