VirtualBox

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

Last change on this file since 55614 was 55614, checked in by vboxsync, 10 years ago

Forgot to add the '-L' option to the vbox_stat invocation. Added '--' to the vbox_stat, vbox_mkdir, vbox_mktemp, and vbox_rm invocation so we don't get confused by file/dir names like '--version' and '-h'.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 115.5 KB
Line 
1/* $Id: GuestSessionImpl.cpp 55614 2015-05-03 04:25:24Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Guest session handling.
4 */
5
6/*
7 * Copyright (C) 2012-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include "GuestImpl.h"
23#include "GuestSessionImpl.h"
24#include "GuestCtrlImplPrivate.h"
25#include "VirtualBoxErrorInfoImpl.h"
26
27#include "Global.h"
28#include "AutoCaller.h"
29#include "ProgressImpl.h"
30#include "VBoxEvents.h"
31#include "VMMDev.h"
32
33#include <memory> /* For auto_ptr. */
34
35#include <iprt/cpp/utils.h> /* For unconst(). */
36#include <iprt/env.h>
37#include <iprt/file.h> /* For CopyTo/From. */
38
39#include <VBox/com/array.h>
40#include <VBox/com/listeners.h>
41#include <VBox/version.h>
42
43#ifdef LOG_GROUP
44 #undef LOG_GROUP
45#endif
46#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
47#include <VBox/log.h>
48
49
50/**
51 * Base class representing an internal
52 * asynchronous session task.
53 */
54class GuestSessionTaskInternal
55{
56public:
57
58 GuestSessionTaskInternal(GuestSession *pSession)
59 : mSession(pSession),
60 mRC(VINF_SUCCESS) { }
61
62 virtual ~GuestSessionTaskInternal(void) { }
63
64 int rc(void) const { return mRC; }
65 bool isOk(void) const { return RT_SUCCESS(mRC); }
66 const ComObjPtr<GuestSession> &Session(void) const { return mSession; }
67
68protected:
69
70 const ComObjPtr<GuestSession> mSession;
71 int mRC;
72};
73
74/**
75 * Class for asynchronously opening a guest session.
76 */
77class GuestSessionTaskInternalOpen : public GuestSessionTaskInternal
78{
79public:
80
81 GuestSessionTaskInternalOpen(GuestSession *pSession)
82 : GuestSessionTaskInternal(pSession) { }
83};
84
85/**
86 * Internal listener class to serve events in an
87 * active manner, e.g. without polling delays.
88 */
89class GuestSessionListener
90{
91public:
92
93 GuestSessionListener(void)
94 {
95 }
96
97 HRESULT init(GuestSession *pSession)
98 {
99 AssertPtrReturn(pSession, E_POINTER);
100 mSession = pSession;
101 return S_OK;
102 }
103
104 void uninit(void)
105 {
106 mSession = NULL;
107 }
108
109 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
110 {
111 switch (aType)
112 {
113 case VBoxEventType_OnGuestSessionStateChanged:
114 {
115 AssertPtrReturn(mSession, E_POINTER);
116 int rc2 = mSession->signalWaitEvent(aType, aEvent);
117#ifdef DEBUG_andy
118 LogFlowFunc(("Signalling events of type=%RU32, session=%p resulted in rc=%Rrc\n",
119 aType, mSession, rc2));
120#endif
121 break;
122 }
123
124 default:
125 AssertMsgFailed(("Unhandled event %RU32\n", aType));
126 break;
127 }
128
129 return S_OK;
130 }
131
132private:
133
134 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 LogFlowThisFuncEnter();
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 /*
186 * Initialize our data members from the input.
187 */
188 mParent = pGuest;
189
190 /* Copy over startup info. */
191 /** @todo Use an overloaded copy operator. Later. */
192 mData.mSession.mID = ssInfo.mID;
193 mData.mSession.mIsInternal = ssInfo.mIsInternal;
194 mData.mSession.mName = ssInfo.mName;
195 mData.mSession.mOpenFlags = ssInfo.mOpenFlags;
196 mData.mSession.mOpenTimeoutMS = ssInfo.mOpenTimeoutMS;
197
198 /** @todo Use an overloaded copy operator. Later. */
199 mData.mCredentials.mUser = guestCreds.mUser;
200 mData.mCredentials.mPassword = guestCreds.mPassword;
201 mData.mCredentials.mDomain = guestCreds.mDomain;
202
203 /* Initialize the remainder of the data. */
204 mData.mRC = VINF_SUCCESS;
205 mData.mStatus = GuestSessionStatus_Undefined;
206 mData.mNumObjects = 0;
207 mData.mpBaseEnvironment = NULL;
208 int rc = mData.mEnvironmentChanges.initChangeRecord();
209 if (RT_SUCCESS(rc))
210 {
211 rc = RTCritSectInit(&mWaitEventCritSect);
212 AssertRC(rc);
213 }
214 if (RT_SUCCESS(rc))
215 rc = i_determineProtocolVersion();
216 if (RT_SUCCESS(rc))
217 {
218 /*
219 * <Replace this if you figure out what the code is doing.>
220 */
221 HRESULT hr = unconst(mEventSource).createObject();
222 if (SUCCEEDED(hr))
223 hr = mEventSource->init();
224 if (SUCCEEDED(hr))
225 {
226 try
227 {
228 GuestSessionListener *pListener = new GuestSessionListener();
229 ComObjPtr<GuestSessionListenerImpl> thisListener;
230 hr = thisListener.createObject();
231 if (SUCCEEDED(hr))
232 hr = thisListener->init(pListener, this);
233 if (SUCCEEDED(hr))
234 {
235 com::SafeArray <VBoxEventType_T> eventTypes;
236 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
237 hr = mEventSource->RegisterListener(thisListener,
238 ComSafeArrayAsInParam(eventTypes),
239 TRUE /* Active listener */);
240 if (SUCCEEDED(hr))
241 {
242 mLocalListener = thisListener;
243
244 /*
245 * Mark this object as operational and return success.
246 */
247 autoInitSpan.setSucceeded();
248 LogFlowThisFunc(("mName=%s mID=%RU32 mIsInternal=%RTbool rc=VINF_SUCCESS\n",
249 mData.mSession.mName.c_str(), mData.mSession.mID, mData.mSession.mIsInternal));
250 return VINF_SUCCESS;
251 }
252 }
253 }
254 catch (std::bad_alloc &)
255 {
256 hr = E_OUTOFMEMORY;
257 }
258 }
259 rc = Global::vboxStatusCodeFromCOM(hr);
260 }
261
262 autoInitSpan.setFailed();
263 LogThisFunc(("Failed! mName=%s mID=%RU32 mIsInternal=%RTbool => rc=%Rrc\n",
264 mData.mSession.mName.c_str(), mData.mSession.mID, mData.mSession.mIsInternal, rc));
265 return rc;
266#endif /* VBOX_WITH_GUEST_CONTROL */
267}
268
269/**
270 * Uninitializes the instance.
271 * Called from FinalRelease().
272 */
273void GuestSession::uninit(void)
274{
275 /* Enclose the state transition Ready->InUninit->NotReady. */
276 AutoUninitSpan autoUninitSpan(this);
277 if (autoUninitSpan.uninitDone())
278 return;
279
280 LogFlowThisFuncEnter();
281
282 int rc = VINF_SUCCESS;
283
284#ifdef VBOX_WITH_GUEST_CONTROL
285 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
286
287 LogFlowThisFunc(("Closing directories (%zu total)\n",
288 mData.mDirectories.size()));
289 for (SessionDirectories::iterator itDirs = mData.mDirectories.begin();
290 itDirs != mData.mDirectories.end(); ++itDirs)
291 {
292 Assert(mData.mNumObjects);
293 mData.mNumObjects--;
294 itDirs->second->i_onRemove();
295 itDirs->second->uninit();
296 }
297 mData.mDirectories.clear();
298
299 LogFlowThisFunc(("Closing files (%zu total)\n",
300 mData.mFiles.size()));
301 for (SessionFiles::iterator itFiles = mData.mFiles.begin();
302 itFiles != mData.mFiles.end(); ++itFiles)
303 {
304 Assert(mData.mNumObjects);
305 mData.mNumObjects--;
306 itFiles->second->i_onRemove();
307 itFiles->second->uninit();
308 }
309 mData.mFiles.clear();
310
311 LogFlowThisFunc(("Closing processes (%zu total)\n",
312 mData.mProcesses.size()));
313 for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();
314 itProcs != mData.mProcesses.end(); ++itProcs)
315 {
316 Assert(mData.mNumObjects);
317 mData.mNumObjects--;
318 itProcs->second->i_onRemove();
319 itProcs->second->uninit();
320 }
321 mData.mProcesses.clear();
322
323 mData.mEnvironmentChanges.reset();
324
325 if (mData.mpBaseEnvironment)
326 {
327 mData.mpBaseEnvironment->releaseConst();
328 mData.mpBaseEnvironment = NULL;
329 }
330
331 AssertMsg(mData.mNumObjects == 0,
332 ("mNumObjects=%RU32 when it should be 0\n", mData.mNumObjects));
333
334 baseUninit();
335#endif /* VBOX_WITH_GUEST_CONTROL */
336 LogFlowFuncLeaveRC(rc);
337}
338
339// implementation of public getters/setters for attributes
340/////////////////////////////////////////////////////////////////////////////
341
342HRESULT GuestSession::getUser(com::Utf8Str &aUser)
343{
344#ifndef VBOX_WITH_GUEST_CONTROL
345 ReturnComNotImplemented();
346#else
347
348 LogFlowThisFuncEnter();
349
350 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
351
352 aUser = mData.mCredentials.mUser;
353
354 LogFlowThisFuncLeave();
355 return S_OK;
356#endif /* VBOX_WITH_GUEST_CONTROL */
357}
358
359HRESULT GuestSession::getDomain(com::Utf8Str &aDomain)
360{
361#ifndef VBOX_WITH_GUEST_CONTROL
362 ReturnComNotImplemented();
363#else
364 LogFlowThisFuncEnter();
365
366 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
367
368 aDomain = mData.mCredentials.mDomain;
369
370 LogFlowThisFuncLeave();
371 return S_OK;
372#endif /* VBOX_WITH_GUEST_CONTROL */
373}
374
375HRESULT GuestSession::getName(com::Utf8Str &aName)
376{
377#ifndef VBOX_WITH_GUEST_CONTROL
378 ReturnComNotImplemented();
379#else
380 LogFlowThisFuncEnter();
381
382 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
383
384 aName = mData.mSession.mName;
385
386 LogFlowThisFuncLeave();
387 return S_OK;
388#endif /* VBOX_WITH_GUEST_CONTROL */
389}
390
391HRESULT GuestSession::getId(ULONG *aId)
392{
393#ifndef VBOX_WITH_GUEST_CONTROL
394 ReturnComNotImplemented();
395#else
396 LogFlowThisFuncEnter();
397
398 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
399
400 *aId = mData.mSession.mID;
401
402 LogFlowThisFuncLeave();
403 return S_OK;
404#endif /* VBOX_WITH_GUEST_CONTROL */
405}
406
407HRESULT GuestSession::getStatus(GuestSessionStatus_T *aStatus)
408{
409#ifndef VBOX_WITH_GUEST_CONTROL
410 ReturnComNotImplemented();
411#else
412 LogFlowThisFuncEnter();
413
414 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
415
416 *aStatus = mData.mStatus;
417
418 LogFlowThisFuncLeave();
419 return S_OK;
420#endif /* VBOX_WITH_GUEST_CONTROL */
421}
422
423HRESULT GuestSession::getTimeout(ULONG *aTimeout)
424{
425#ifndef VBOX_WITH_GUEST_CONTROL
426 ReturnComNotImplemented();
427#else
428 LogFlowThisFuncEnter();
429
430 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
431
432 *aTimeout = mData.mTimeout;
433
434 LogFlowThisFuncLeave();
435 return S_OK;
436#endif /* VBOX_WITH_GUEST_CONTROL */
437}
438
439HRESULT GuestSession::setTimeout(ULONG aTimeout)
440{
441#ifndef VBOX_WITH_GUEST_CONTROL
442 ReturnComNotImplemented();
443#else
444 LogFlowThisFuncEnter();
445
446 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
447
448 mData.mTimeout = aTimeout;
449
450 LogFlowThisFuncLeave();
451 return S_OK;
452#endif /* VBOX_WITH_GUEST_CONTROL */
453}
454
455HRESULT GuestSession::getProtocolVersion(ULONG *aProtocolVersion)
456{
457#ifndef VBOX_WITH_GUEST_CONTROL
458 ReturnComNotImplemented();
459#else
460 LogFlowThisFuncEnter();
461
462 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
463
464 *aProtocolVersion = mData.mProtocolVersion;
465
466 LogFlowThisFuncLeave();
467 return S_OK;
468#endif /* VBOX_WITH_GUEST_CONTROL */
469}
470
471HRESULT GuestSession::getEnvironmentChanges(std::vector<com::Utf8Str> &aEnvironmentChanges)
472{
473#ifndef VBOX_WITH_GUEST_CONTROL
474 ReturnComNotImplemented();
475#else
476 LogFlowThisFuncEnter();
477
478 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
479
480 int vrc = mData.mEnvironmentChanges.queryPutEnvArray(&aEnvironmentChanges);
481
482 LogFlowFuncLeaveRC(vrc);
483 return Global::vboxStatusCodeToCOM(vrc);
484#endif /* VBOX_WITH_GUEST_CONTROL */
485}
486
487HRESULT GuestSession::setEnvironmentChanges(const std::vector<com::Utf8Str> &aEnvironmentChanges)
488{
489#ifndef VBOX_WITH_GUEST_CONTROL
490 ReturnComNotImplemented();
491#else
492 LogFlowThisFuncEnter();
493
494 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
495
496 mData.mEnvironmentChanges.reset();
497 int vrc = mData.mEnvironmentChanges.applyPutEnvArray(aEnvironmentChanges);
498
499 LogFlowFuncLeaveRC(vrc);
500 return Global::vboxStatusCodeToCOM(vrc);
501#endif /* VBOX_WITH_GUEST_CONTROL */
502}
503
504HRESULT GuestSession::getEnvironmentBase(std::vector<com::Utf8Str> &aEnvironmentBase)
505{
506#ifndef VBOX_WITH_GUEST_CONTROL
507 ReturnComNotImplemented();
508#else
509 LogFlowThisFuncEnter();
510
511 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
512 HRESULT hrc;
513 if (mData.mpBaseEnvironment)
514 {
515 int vrc = mData.mpBaseEnvironment->queryPutEnvArray(&aEnvironmentBase);
516 hrc = Global::vboxStatusCodeToCOM(vrc);
517 }
518 else if (mData.mProtocolVersion < 99999)
519 hrc = setError(VBOX_E_NOT_SUPPORTED, tr("The base environment feature is not supported by the guest additions"));
520 else
521 hrc = setError(VBOX_E_INVALID_OBJECT_STATE, tr("The base environment has not yet been reported by the guest"));
522
523 LogFlowFuncLeave();
524 return hrc;
525#endif /* VBOX_WITH_GUEST_CONTROL */
526}
527
528HRESULT GuestSession::getProcesses(std::vector<ComPtr<IGuestProcess> > &aProcesses)
529{
530#ifndef VBOX_WITH_GUEST_CONTROL
531 ReturnComNotImplemented();
532#else
533 LogFlowThisFuncEnter();
534
535 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
536
537 aProcesses.resize(mData.mProcesses.size());
538 size_t i = 0;
539 for(SessionProcesses::iterator it = mData.mProcesses.begin();
540 it != mData.mProcesses.end();
541 ++it, ++i)
542 {
543 it->second.queryInterfaceTo(aProcesses[i].asOutParam());
544 }
545
546 LogFlowFunc(("mProcesses=%zu\n", aProcesses.size()));
547 return S_OK;
548#endif /* VBOX_WITH_GUEST_CONTROL */
549}
550
551HRESULT GuestSession::getPathStyle(PathStyle_T *aPathStyle)
552{
553#ifndef VBOX_WITH_GUEST_CONTROL
554 ReturnComNotImplemented();
555#else
556 VBOXOSTYPE enmOsType = mParent->i_getGuestOSType();
557 if ( enmOsType < VBOXOSTYPE_DOS)
558 {
559 *aPathStyle = PathStyle_Unknown;
560 LogFlowFunc(("returns PathStyle_Unknown\n"));
561 }
562 else if (enmOsType < VBOXOSTYPE_Linux)
563 {
564 *aPathStyle = PathStyle_DOS;
565 LogFlowFunc(("returns PathStyle_DOS\n"));
566 }
567 else
568 {
569 *aPathStyle = PathStyle_UNIX;
570 LogFlowFunc(("returns PathStyle_UNIX\n"));
571 }
572 return S_OK;
573#endif
574}
575
576HRESULT GuestSession::getDirectories(std::vector<ComPtr<IGuestDirectory> > &aDirectories)
577{
578#ifndef VBOX_WITH_GUEST_CONTROL
579 ReturnComNotImplemented();
580#else
581 LogFlowThisFuncEnter();
582
583 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
584
585 aDirectories.resize(mData.mDirectories.size());
586 size_t i = 0;
587 for(SessionDirectories::iterator it = mData.mDirectories.begin();
588 it != mData.mDirectories.end();
589 ++it, ++i)
590 {
591 it->second.queryInterfaceTo(aDirectories[i].asOutParam());
592 }
593
594 LogFlowFunc(("mDirectories=%zu\n", aDirectories.size()));
595 return S_OK;
596#endif /* VBOX_WITH_GUEST_CONTROL */
597}
598
599HRESULT GuestSession::getFiles(std::vector<ComPtr<IGuestFile> > &aFiles)
600{
601#ifndef VBOX_WITH_GUEST_CONTROL
602 ReturnComNotImplemented();
603#else
604 LogFlowThisFuncEnter();
605
606 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
607
608 aFiles.resize(mData.mFiles.size());
609 size_t i = 0;
610 for(SessionFiles::iterator it = mData.mFiles.begin(); it != mData.mFiles.end(); ++it, ++i)
611 it->second.queryInterfaceTo(aFiles[i].asOutParam());
612
613 LogFlowFunc(("mDirectories=%zu\n", aFiles.size()));
614
615 return S_OK;
616#endif /* VBOX_WITH_GUEST_CONTROL */
617}
618
619HRESULT GuestSession::getEventSource(ComPtr<IEventSource> &aEventSource)
620{
621#ifndef VBOX_WITH_GUEST_CONTROL
622 ReturnComNotImplemented();
623#else
624 LogFlowThisFuncEnter();
625
626 // no need to lock - lifetime constant
627 mEventSource.queryInterfaceTo(aEventSource.asOutParam());
628
629 LogFlowThisFuncLeave();
630 return S_OK;
631#endif /* VBOX_WITH_GUEST_CONTROL */
632}
633
634// private methods
635///////////////////////////////////////////////////////////////////////////////
636
637int GuestSession::i_closeSession(uint32_t uFlags, uint32_t uTimeoutMS, int *pGuestRc)
638{
639 LogFlowThisFunc(("uFlags=%x, uTimeoutMS=%RU32\n", uFlags, uTimeoutMS));
640
641 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
642
643 /* Guest Additions < 4.3 don't support closing dedicated
644 guest sessions, skip. */
645 if (mData.mProtocolVersion < 2)
646 {
647 LogFlowThisFunc(("Installed Guest Additions don't support closing dedicated sessions, skipping\n"));
648 return VINF_SUCCESS;
649 }
650
651 /** @todo uFlags validation. */
652
653 if (mData.mStatus != GuestSessionStatus_Started)
654 {
655 LogFlowThisFunc(("Session ID=%RU32 not started (anymore), status now is: %RU32\n",
656 mData.mSession.mID, mData.mStatus));
657 return VINF_SUCCESS;
658 }
659
660 int vrc;
661
662 GuestWaitEvent *pEvent = NULL;
663 GuestEventTypes eventTypes;
664 try
665 {
666 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
667
668 vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */,
669 eventTypes, &pEvent);
670 }
671 catch (std::bad_alloc)
672 {
673 vrc = VERR_NO_MEMORY;
674 }
675
676 if (RT_FAILURE(vrc))
677 return vrc;
678
679 LogFlowThisFunc(("Sending closing request to guest session ID=%RU32, uFlags=%x\n",
680 mData.mSession.mID, uFlags));
681
682 VBOXHGCMSVCPARM paParms[4];
683 int i = 0;
684 paParms[i++].setUInt32(pEvent->ContextID());
685 paParms[i++].setUInt32(uFlags);
686
687 alock.release(); /* Drop the write lock before waiting. */
688
689 vrc = i_sendCommand(HOST_SESSION_CLOSE, i, paParms);
690 if (RT_SUCCESS(vrc))
691 vrc = i_waitForStatusChange(pEvent, GuestSessionWaitForFlag_Terminate, uTimeoutMS,
692 NULL /* Session status */, pGuestRc);
693
694 unregisterWaitEvent(pEvent);
695
696 LogFlowFuncLeaveRC(vrc);
697 return vrc;
698}
699
700int GuestSession::i_directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode,
701 uint32_t uFlags, int *pGuestRc)
702{
703 LogFlowThisFunc(("strPath=%s, uMode=%x, uFlags=%x\n",
704 strPath.c_str(), uMode, uFlags));
705
706 int vrc = VINF_SUCCESS;
707
708 GuestProcessStartupInfo procInfo;
709 procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
710 procInfo.mFlags = ProcessCreateFlag_Hidden;
711
712 try
713 {
714 /* Construct arguments. */
715 if (uFlags)
716 {
717 if (uFlags & DirectoryCreateFlag_Parents)
718 procInfo.mArguments.push_back(Utf8Str("--parents")); /* We also want to create the parent directories. */
719 else
720 vrc = VERR_INVALID_PARAMETER;
721 }
722
723 if (uMode)
724 {
725 procInfo.mArguments.push_back(Utf8Str("--mode")); /* Set the creation mode. */
726
727 char szMode[16];
728 if (RTStrPrintf(szMode, sizeof(szMode), "%o", uMode))
729 {
730 procInfo.mArguments.push_back(Utf8Str(szMode));
731 }
732 else
733 vrc = VERR_BUFFER_OVERFLOW;
734 }
735 procInfo.mArguments.push_back("--"); /* '--version' is a valid directory name. */
736 procInfo.mArguments.push_back(strPath); /* The directory we want to create. */
737 }
738 catch (std::bad_alloc)
739 {
740 vrc = VERR_NO_MEMORY;
741 }
742
743 if (RT_SUCCESS(vrc))
744 vrc = GuestProcessTool::i_run(this, procInfo, pGuestRc);
745
746 LogFlowFuncLeaveRC(vrc);
747 return vrc;
748}
749
750inline bool GuestSession::i_directoryExists(uint32_t uDirID, ComObjPtr<GuestDirectory> *pDir)
751{
752 SessionDirectories::const_iterator it = mData.mDirectories.find(uDirID);
753 if (it != mData.mDirectories.end())
754 {
755 if (pDir)
756 *pDir = it->second;
757 return true;
758 }
759 return false;
760}
761
762int GuestSession::i_directoryQueryInfoInternal(const Utf8Str &strPath, bool fFollowSymlinks,
763 GuestFsObjData &objData, int *pGuestRc)
764{
765 LogFlowThisFunc(("strPath=%s fFollowSymlinks=%RTbool\n", strPath.c_str(), fFollowSymlinks));
766
767 int vrc = i_fsQueryInfoInternal(strPath, fFollowSymlinks, objData, pGuestRc);
768 if (RT_SUCCESS(vrc))
769 {
770 vrc = objData.mType == FsObjType_Directory
771 ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
772 }
773
774 LogFlowFuncLeaveRC(vrc);
775 return vrc;
776}
777
778int GuestSession::i_directoryRemoveFromList(GuestDirectory *pDirectory)
779{
780 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
781
782 int rc = VERR_NOT_FOUND;
783
784 SessionDirectories::iterator itDirs = mData.mDirectories.begin();
785 while (itDirs != mData.mDirectories.end())
786 {
787 if (pDirectory == itDirs->second)
788 {
789 /* Make sure to consume the pointer before the one of the
790 * iterator gets released. */
791 ComObjPtr<GuestDirectory> pDir = pDirectory;
792
793 Bstr strName;
794 HRESULT hr = itDirs->second->COMGETTER(DirectoryName)(strName.asOutParam());
795 ComAssertComRC(hr);
796
797 Assert(mData.mDirectories.size());
798 Assert(mData.mNumObjects);
799 LogFlowFunc(("Removing directory \"%s\" (Session: %RU32) (now total %zu processes, %RU32 objects)\n",
800 Utf8Str(strName).c_str(), mData.mSession.mID, mData.mDirectories.size() - 1, mData.mNumObjects - 1));
801
802 rc = pDirectory->i_onRemove();
803 mData.mDirectories.erase(itDirs);
804 mData.mNumObjects--;
805
806 pDir.setNull();
807 break;
808 }
809
810 itDirs++;
811 }
812
813 LogFlowFuncLeaveRC(rc);
814 return rc;
815}
816
817int GuestSession::i_directoryRemoveInternal(const Utf8Str &strPath, uint32_t uFlags,
818 int *pGuestRc)
819{
820 AssertReturn(!(uFlags & ~DIRREMOVE_FLAG_VALID_MASK), VERR_INVALID_PARAMETER);
821
822 LogFlowThisFunc(("strPath=%s, uFlags=0x%x\n", strPath.c_str(), uFlags));
823
824 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
825
826 GuestWaitEvent *pEvent = NULL;
827 int vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */,
828 &pEvent);
829 if (RT_FAILURE(vrc))
830 return vrc;
831
832 /* Prepare HGCM call. */
833 VBOXHGCMSVCPARM paParms[8];
834 int i = 0;
835 paParms[i++].setUInt32(pEvent->ContextID());
836 paParms[i++].setPointer((void*)strPath.c_str(),
837 (ULONG)strPath.length() + 1);
838 paParms[i++].setUInt32(uFlags);
839
840 alock.release(); /* Drop write lock before sending. */
841
842 vrc = i_sendCommand(HOST_DIR_REMOVE, i, paParms);
843 if (RT_SUCCESS(vrc))
844 {
845 vrc = pEvent->Wait(30 * 1000);
846 if ( vrc == VERR_GSTCTL_GUEST_ERROR
847 && pGuestRc)
848 *pGuestRc = pEvent->GuestResult();
849 }
850
851 unregisterWaitEvent(pEvent);
852
853 LogFlowFuncLeaveRC(vrc);
854 return vrc;
855}
856
857int GuestSession::i_objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath,
858 bool fDirectory, Utf8Str &strName, int *pGuestRc)
859{
860 LogFlowThisFunc(("strTemplate=%s, strPath=%s, fDirectory=%RTbool\n",
861 strTemplate.c_str(), strPath.c_str(), fDirectory));
862
863 int vrc = VINF_SUCCESS;
864
865 GuestProcessStartupInfo procInfo;
866 procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
867 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
868
869 try
870 {
871 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
872 if (fDirectory)
873 procInfo.mArguments.push_back(Utf8Str("-d"));
874 if (strPath.length()) /* Otherwise use /tmp or equivalent. */
875 {
876 procInfo.mArguments.push_back(Utf8Str("-t"));
877 procInfo.mArguments.push_back(strPath);
878 }
879 procInfo.mArguments.push_back("--"); /* strTemplate could be '--help'. */
880 procInfo.mArguments.push_back(strTemplate);
881 }
882 catch (std::bad_alloc)
883 {
884 vrc = VERR_NO_MEMORY;
885 }
886
887 /** @todo Use an internal HGCM command for this operation, since
888 * we now can run in a user-dedicated session. */
889 int guestRc; GuestCtrlStreamObjects stdOut;
890 if (RT_SUCCESS(vrc))
891 vrc = GuestProcessTool::i_runEx(this, procInfo,
892 &stdOut, 1 /* cStrmOutObjects */,
893 &guestRc);
894 if ( RT_SUCCESS(vrc)
895 && RT_SUCCESS(guestRc))
896 {
897 GuestFsObjData objData;
898 if (!stdOut.empty())
899 {
900 vrc = objData.FromMkTemp(stdOut.at(0));
901 if (RT_FAILURE(vrc))
902 {
903 guestRc = vrc;
904 vrc = VERR_GSTCTL_GUEST_ERROR;
905 }
906 }
907 else
908 vrc = VERR_NO_DATA;
909
910 if (RT_SUCCESS(vrc))
911 strName = objData.mName;
912 }
913
914 if (pGuestRc)
915 *pGuestRc = guestRc;
916
917 LogFlowFuncLeaveRC(vrc);
918 return vrc;
919}
920
921int GuestSession::i_directoryOpenInternal(const GuestDirectoryOpenInfo &openInfo,
922 ComObjPtr<GuestDirectory> &pDirectory, int *pGuestRc)
923{
924 LogFlowThisFunc(("strPath=%s, strPath=%s, uFlags=%x\n",
925 openInfo.mPath.c_str(), openInfo.mFilter.c_str(), openInfo.mFlags));
926
927 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
928
929 int rc = VERR_MAX_PROCS_REACHED;
930 if (mData.mNumObjects >= VBOX_GUESTCTRL_MAX_OBJECTS)
931 return rc;
932
933 /* Create a new (host-based) directory ID and assign it. */
934 uint32_t uNewDirID = 0;
935 ULONG uTries = 0;
936
937 for (;;)
938 {
939 /* Is the directory ID already used? */
940 if (!i_directoryExists(uNewDirID, NULL /* pDirectory */))
941 {
942 /* Callback with context ID was not found. This means
943 * we can use this context ID for our new callback we want
944 * to add below. */
945 rc = VINF_SUCCESS;
946 break;
947 }
948 uNewDirID++;
949 if (uNewDirID == VBOX_GUESTCTRL_MAX_OBJECTS)
950 uNewDirID = 0;
951
952 if (++uTries == UINT32_MAX)
953 break; /* Don't try too hard. */
954 }
955
956 if (RT_FAILURE(rc))
957 return rc;
958
959 /* Create the directory object. */
960 HRESULT hr = pDirectory.createObject();
961 if (FAILED(hr))
962 return VERR_COM_UNEXPECTED;
963
964 Console *pConsole = mParent->i_getConsole();
965 AssertPtr(pConsole);
966
967 int vrc = pDirectory->init(pConsole, this /* Parent */,
968 uNewDirID, openInfo);
969 if (RT_FAILURE(vrc))
970 return vrc;
971
972 /*
973 * Since this is a synchronous guest call we have to
974 * register the file object first, releasing the session's
975 * lock and then proceed with the actual opening command
976 * -- otherwise the file's opening callback would hang
977 * because the session's lock still is in place.
978 */
979 try
980 {
981 /* Add the created directory to our map. */
982 mData.mDirectories[uNewDirID] = pDirectory;
983 mData.mNumObjects++;
984 Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS);
985
986 LogFlowFunc(("Added new guest directory \"%s\" (Session: %RU32) (now total %zu dirs, %RU32 objects)\n",
987 openInfo.mPath.c_str(), mData.mSession.mID, mData.mFiles.size(), mData.mNumObjects));
988
989 alock.release(); /* Release lock before firing off event. */
990
991 /** @todo Fire off a VBoxEventType_OnGuestDirectoryRegistered event? */
992 }
993 catch (std::bad_alloc &)
994 {
995 rc = VERR_NO_MEMORY;
996 }
997
998 if (RT_SUCCESS(rc))
999 {
1000 /* Nothing further to do here yet. */
1001 if (pGuestRc)
1002 *pGuestRc = VINF_SUCCESS;
1003 }
1004
1005 LogFlowFuncLeaveRC(vrc);
1006 return vrc;
1007}
1008
1009int GuestSession::i_dispatchToDirectory(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
1010{
1011 LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
1012
1013 AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
1014 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
1015
1016 if (pSvcCb->mParms < 3)
1017 return VERR_INVALID_PARAMETER;
1018
1019 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1020
1021 uint32_t uDirID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID);
1022#ifdef DEBUG
1023 LogFlowFunc(("uDirID=%RU32 (%zu total)\n",
1024 uDirID, mData.mFiles.size()));
1025#endif
1026 int rc;
1027 SessionDirectories::const_iterator itDir
1028 = mData.mDirectories.find(uDirID);
1029 if (itDir != mData.mDirectories.end())
1030 {
1031 ComObjPtr<GuestDirectory> pDirectory(itDir->second);
1032 Assert(!pDirectory.isNull());
1033
1034 alock.release();
1035
1036 rc = pDirectory->i_callbackDispatcher(pCtxCb, pSvcCb);
1037 }
1038 else
1039 rc = VERR_NOT_FOUND;
1040
1041 LogFlowFuncLeaveRC(rc);
1042 return rc;
1043}
1044
1045int GuestSession::i_dispatchToFile(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
1046{
1047 LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
1048
1049 AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
1050 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
1051
1052 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1053
1054 uint32_t uFileID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID);
1055#ifdef DEBUG
1056 LogFlowFunc(("uFileID=%RU32 (%zu total)\n",
1057 uFileID, mData.mFiles.size()));
1058#endif
1059 int rc;
1060 SessionFiles::const_iterator itFile
1061 = mData.mFiles.find(uFileID);
1062 if (itFile != mData.mFiles.end())
1063 {
1064 ComObjPtr<GuestFile> pFile(itFile->second);
1065 Assert(!pFile.isNull());
1066
1067 alock.release();
1068
1069 rc = pFile->i_callbackDispatcher(pCtxCb, pSvcCb);
1070 }
1071 else
1072 rc = VERR_NOT_FOUND;
1073
1074 LogFlowFuncLeaveRC(rc);
1075 return rc;
1076}
1077
1078int GuestSession::i_dispatchToObject(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
1079{
1080 LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
1081
1082 AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
1083 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
1084
1085 int rc;
1086 uint32_t uObjectID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID);
1087
1088 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1089
1090 /* Since we don't know which type the object is, we need to through all
1091 * all objects. */
1092 /** @todo Speed this up by adding an object type to the callback context! */
1093 SessionProcesses::const_iterator itProc = mData.mProcesses.find(uObjectID);
1094 if (itProc == mData.mProcesses.end())
1095 {
1096 SessionFiles::const_iterator itFile = mData.mFiles.find(uObjectID);
1097 if (itFile != mData.mFiles.end())
1098 {
1099 alock.release();
1100
1101 rc = i_dispatchToFile(pCtxCb, pSvcCb);
1102 }
1103 else
1104 {
1105 SessionDirectories::const_iterator itDir = mData.mDirectories.find(uObjectID);
1106 if (itDir != mData.mDirectories.end())
1107 {
1108 alock.release();
1109
1110 rc = i_dispatchToDirectory(pCtxCb, pSvcCb);
1111 }
1112 else
1113 rc = VERR_NOT_FOUND;
1114 }
1115 }
1116 else
1117 {
1118 alock.release();
1119
1120 rc = i_dispatchToProcess(pCtxCb, pSvcCb);
1121 }
1122
1123 LogFlowFuncLeaveRC(rc);
1124 return rc;
1125}
1126
1127int GuestSession::i_dispatchToProcess(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
1128{
1129 LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
1130
1131 AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
1132 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
1133
1134 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1135
1136 uint32_t uProcessID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID);
1137#ifdef DEBUG
1138 LogFlowFunc(("uProcessID=%RU32 (%zu total)\n",
1139 uProcessID, mData.mProcesses.size()));
1140#endif
1141 int rc;
1142 SessionProcesses::const_iterator itProc
1143 = mData.mProcesses.find(uProcessID);
1144 if (itProc != mData.mProcesses.end())
1145 {
1146#ifdef DEBUG_andy
1147 ULONG cRefs = itProc->second->AddRef();
1148 Assert(cRefs >= 2);
1149 LogFlowFunc(("pProcess=%p, cRefs=%RU32\n", &itProc->second, cRefs - 1));
1150 itProc->second->Release();
1151#endif
1152 ComObjPtr<GuestProcess> pProcess(itProc->second);
1153 Assert(!pProcess.isNull());
1154
1155 /* Set protocol version so that pSvcCb can
1156 * be interpreted right. */
1157 pCtxCb->uProtocol = mData.mProtocolVersion;
1158
1159 alock.release();
1160 rc = pProcess->i_callbackDispatcher(pCtxCb, pSvcCb);
1161 }
1162 else
1163 rc = VERR_NOT_FOUND;
1164
1165 LogFlowFuncLeaveRC(rc);
1166 return rc;
1167}
1168
1169int GuestSession::i_dispatchToThis(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
1170{
1171 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
1172 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
1173
1174 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1175
1176#ifdef DEBUG
1177 LogFlowThisFunc(("sessionID=%RU32, CID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
1178 mData.mSession.mID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
1179#endif
1180
1181 int rc;
1182 switch (pCbCtx->uFunction)
1183 {
1184 case GUEST_DISCONNECTED:
1185 /** @todo Handle closing all guest objects. */
1186 rc = VERR_INTERNAL_ERROR;
1187 break;
1188
1189 case GUEST_SESSION_NOTIFY: /* Guest Additions >= 4.3.0. */
1190 {
1191 rc = i_onSessionStatusChange(pCbCtx, pSvcCb);
1192 break;
1193 }
1194
1195 default:
1196 /* Silently skip unknown callbacks. */
1197 rc = VERR_NOT_SUPPORTED;
1198 break;
1199 }
1200
1201 LogFlowFuncLeaveRC(rc);
1202 return rc;
1203}
1204
1205inline bool GuestSession::i_fileExists(uint32_t uFileID, ComObjPtr<GuestFile> *pFile)
1206{
1207 SessionFiles::const_iterator it = mData.mFiles.find(uFileID);
1208 if (it != mData.mFiles.end())
1209 {
1210 if (pFile)
1211 *pFile = it->second;
1212 return true;
1213 }
1214 return false;
1215}
1216
1217int GuestSession::i_fileRemoveFromList(GuestFile *pFile)
1218{
1219 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1220
1221 int rc = VERR_NOT_FOUND;
1222
1223 SessionFiles::iterator itFiles = mData.mFiles.begin();
1224 while (itFiles != mData.mFiles.end())
1225 {
1226 if (pFile == itFiles->second)
1227 {
1228 /* Make sure to consume the pointer before the one of thfe
1229 * iterator gets released. */
1230 ComObjPtr<GuestFile> pCurFile = pFile;
1231
1232 Bstr strName;
1233 HRESULT hr = pCurFile->COMGETTER(FileName)(strName.asOutParam());
1234 ComAssertComRC(hr);
1235
1236 Assert(mData.mNumObjects);
1237 LogFlowThisFunc(("Removing guest file \"%s\" (Session: %RU32) (now total %zu files, %RU32 objects)\n",
1238 Utf8Str(strName).c_str(), mData.mSession.mID, mData.mFiles.size() - 1, mData.mNumObjects - 1));
1239
1240 rc = pFile->i_onRemove();
1241 mData.mFiles.erase(itFiles);
1242 mData.mNumObjects--;
1243
1244 alock.release(); /* Release lock before firing off event. */
1245
1246 fireGuestFileRegisteredEvent(mEventSource, this, pCurFile,
1247 false /* Unregistered */);
1248 pCurFile.setNull();
1249 break;
1250 }
1251
1252 itFiles++;
1253 }
1254
1255 LogFlowFuncLeaveRC(rc);
1256 return rc;
1257}
1258
1259int GuestSession::i_fileRemoveInternal(const Utf8Str &strPath, int *pGuestRc)
1260{
1261 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
1262
1263 int vrc = VINF_SUCCESS;
1264
1265 GuestProcessStartupInfo procInfo;
1266 GuestProcessStream streamOut;
1267
1268 procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_RM);
1269 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
1270
1271 try
1272 {
1273 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
1274 procInfo.mArguments.push_back("--"); /* strPath could be '--help', which is a valid filename. */
1275 procInfo.mArguments.push_back(strPath); /* The file we want to remove. */
1276 }
1277 catch (std::bad_alloc)
1278 {
1279 vrc = VERR_NO_MEMORY;
1280 }
1281
1282 if (RT_SUCCESS(vrc))
1283 vrc = GuestProcessTool::i_run(this, procInfo, pGuestRc);
1284
1285 LogFlowFuncLeaveRC(vrc);
1286 return vrc;
1287}
1288
1289int GuestSession::i_fileOpenInternal(const GuestFileOpenInfo &openInfo,
1290 ComObjPtr<GuestFile> &pFile, int *pGuestRc)
1291{
1292 LogFlowThisFunc(("strPath=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%x, uOffset=%RU64\n",
1293 openInfo.mFileName.c_str(), openInfo.mOpenMode.c_str(), openInfo.mDisposition.c_str(),
1294 openInfo.mCreationMode, openInfo.mInitialOffset));
1295
1296 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1297
1298 /* Guest Additions < 4.3 don't support handling
1299 guest files, skip. */
1300 if (mData.mProtocolVersion < 2)
1301 {
1302 LogFlowThisFunc(("Installed Guest Additions don't support handling guest files, skipping\n"));
1303 return VERR_NOT_SUPPORTED;
1304 }
1305
1306 int rc = VERR_MAX_PROCS_REACHED;
1307 if (mData.mNumObjects >= VBOX_GUESTCTRL_MAX_OBJECTS)
1308 return rc;
1309
1310 /* Create a new (host-based) file ID and assign it. */
1311 uint32_t uNewFileID = 0;
1312 ULONG uTries = 0;
1313
1314 for (;;)
1315 {
1316 /* Is the file ID already used? */
1317 if (!i_fileExists(uNewFileID, NULL /* pFile */))
1318 {
1319 /* Callback with context ID was not found. This means
1320 * we can use this context ID for our new callback we want
1321 * to add below. */
1322 rc = VINF_SUCCESS;
1323 break;
1324 }
1325 uNewFileID++;
1326 if (uNewFileID == VBOX_GUESTCTRL_MAX_OBJECTS)
1327 uNewFileID = 0;
1328
1329 if (++uTries == UINT32_MAX)
1330 break; /* Don't try too hard. */
1331 }
1332
1333 if (RT_FAILURE(rc))
1334 return rc;
1335
1336 /* Create the directory object. */
1337 HRESULT hr = pFile.createObject();
1338 if (FAILED(hr))
1339 return VERR_COM_UNEXPECTED;
1340
1341 Console *pConsole = mParent->i_getConsole();
1342 AssertPtr(pConsole);
1343
1344 rc = pFile->init(pConsole, this /* GuestSession */,
1345 uNewFileID, openInfo);
1346 if (RT_FAILURE(rc))
1347 return rc;
1348
1349 /*
1350 * Since this is a synchronous guest call we have to
1351 * register the file object first, releasing the session's
1352 * lock and then proceed with the actual opening command
1353 * -- otherwise the file's opening callback would hang
1354 * because the session's lock still is in place.
1355 */
1356 try
1357 {
1358 /* Add the created file to our vector. */
1359 mData.mFiles[uNewFileID] = pFile;
1360 mData.mNumObjects++;
1361 Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS);
1362
1363 LogFlowFunc(("Added new guest file \"%s\" (Session: %RU32) (now total %zu files, %RU32 objects)\n",
1364 openInfo.mFileName.c_str(), mData.mSession.mID, mData.mFiles.size(), mData.mNumObjects));
1365
1366 alock.release(); /* Release lock before firing off event. */
1367
1368 fireGuestFileRegisteredEvent(mEventSource, this, pFile,
1369 true /* Registered */);
1370 }
1371 catch (std::bad_alloc &)
1372 {
1373 rc = VERR_NO_MEMORY;
1374 }
1375
1376 if (RT_SUCCESS(rc))
1377 {
1378 int guestRc;
1379 rc = pFile->i_openFile(30 * 1000 /* 30s timeout */, &guestRc);
1380 if ( rc == VERR_GSTCTL_GUEST_ERROR
1381 && pGuestRc)
1382 {
1383 *pGuestRc = guestRc;
1384 }
1385 }
1386
1387 LogFlowFuncLeaveRC(rc);
1388 return rc;
1389}
1390
1391int GuestSession::i_fileQueryInfoInternal(const Utf8Str &strPath, bool fFollowSymlinks, GuestFsObjData &objData, int *pGuestRc)
1392{
1393 LogFlowThisFunc(("strPath=%s fFollowSymlinks=%RTbool\n", strPath.c_str(), fFollowSymlinks));
1394
1395 int vrc = i_fsQueryInfoInternal(strPath, fFollowSymlinks, objData, pGuestRc);
1396 if (RT_SUCCESS(vrc))
1397 {
1398 vrc = objData.mType == FsObjType_File
1399 ? VINF_SUCCESS : VERR_NOT_A_FILE;
1400 }
1401
1402 LogFlowFuncLeaveRC(vrc);
1403 return vrc;
1404}
1405
1406int GuestSession::i_fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize, int *pGuestRc)
1407{
1408 AssertPtrReturn(pllSize, VERR_INVALID_POINTER);
1409
1410 GuestFsObjData objData;
1411 int vrc = i_fileQueryInfoInternal(strPath, false /*fFollowSymlinks*/, objData, pGuestRc);
1412 if (RT_SUCCESS(vrc))
1413 *pllSize = objData.mObjectSize;
1414
1415 return vrc;
1416}
1417
1418/**
1419 * <Someone write documentation, pretty please!>
1420 *
1421 * @param pGuestRc Optional. Will be set to VINF_SUCCESS,
1422 * VERR_NOT_EQUAL or VERR_INVALID_STATE if the
1423 * process completed. May probably be set to a lot of
1424 * other things. Not sure if these things are related
1425 * to the process we ran or what, really. :-(
1426 */
1427int GuestSession::i_fsQueryInfoInternal(const Utf8Str &strPath, bool fFollowSymlinks, GuestFsObjData &objData, int *pGuestRc)
1428{
1429 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
1430
1431 int vrc = VINF_SUCCESS;
1432
1433 /** @todo Merge this with IGuestFile::queryInfo(). */
1434 GuestProcessStartupInfo procInfo;
1435 procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_STAT);
1436 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
1437
1438 try
1439 {
1440 /* Construct arguments. */
1441 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
1442 if (fFollowSymlinks)
1443 procInfo.mArguments.push_back(Utf8Str("-L"));
1444 procInfo.mArguments.push_back("--"); /* strPath could be '--help', which is a valid filename. */
1445 procInfo.mArguments.push_back(strPath);
1446 }
1447 catch (std::bad_alloc)
1448 {
1449 vrc = VERR_NO_MEMORY;
1450 }
1451
1452 int guestRc;
1453 GuestCtrlStreamObjects stdOut;
1454 if (RT_SUCCESS(vrc))
1455 vrc = GuestProcessTool::i_runEx(this, procInfo,
1456 &stdOut, 1 /* cStrmOutObjects */,
1457 &guestRc);
1458 if ( RT_SUCCESS(vrc)
1459 && RT_SUCCESS(guestRc))
1460 {
1461 if (!stdOut.empty())
1462 vrc = objData.FromStat(stdOut.at(0));
1463 else
1464 vrc = VERR_NO_DATA;
1465 }
1466
1467 if ( vrc == VERR_GSTCTL_GUEST_ERROR
1468 && pGuestRc)
1469 *pGuestRc = guestRc;
1470
1471 LogFlowThisFunc(("Returning rc=%Rrc, guestRc=%Rrc\n",
1472 vrc, guestRc));
1473 return vrc;
1474}
1475
1476const GuestCredentials& GuestSession::i_getCredentials(void)
1477{
1478 return mData.mCredentials;
1479}
1480
1481Utf8Str GuestSession::i_getName(void)
1482{
1483 return mData.mSession.mName;
1484}
1485
1486/* static */
1487Utf8Str GuestSession::i_guestErrorToString(int guestRc)
1488{
1489 Utf8Str strError;
1490
1491 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
1492 switch (guestRc)
1493 {
1494 case VERR_INVALID_VM_HANDLE:
1495 strError += Utf8StrFmt(tr("VMM device is not available (is the VM running?)"));
1496 break;
1497
1498 case VERR_HGCM_SERVICE_NOT_FOUND:
1499 strError += Utf8StrFmt(tr("The guest execution service is not available"));
1500 break;
1501
1502 case VERR_AUTHENTICATION_FAILURE:
1503 strError += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
1504 break;
1505
1506 case VERR_TIMEOUT:
1507 strError += Utf8StrFmt(tr("The guest did not respond within time"));
1508 break;
1509
1510 case VERR_CANCELLED:
1511 strError += Utf8StrFmt(tr("The session operation was canceled"));
1512 break;
1513
1514 case VERR_PERMISSION_DENIED:
1515 strError += Utf8StrFmt(tr("Invalid user/password credentials"));
1516 break;
1517
1518 case VERR_MAX_PROCS_REACHED:
1519 strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached"));
1520 break;
1521
1522 case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */
1523 strError += Utf8StrFmt(tr("Unable to retrieve requested information"));
1524 break;
1525
1526 case VERR_NOT_FOUND:
1527 strError += Utf8StrFmt(tr("The guest execution service is not ready (yet)"));
1528 break;
1529
1530 default:
1531 strError += Utf8StrFmt("%Rrc", guestRc);
1532 break;
1533 }
1534
1535 return strError;
1536}
1537
1538/**
1539 * Checks if this session is ready state where it can handle
1540 * all session-bound actions (like guest processes, guest files).
1541 * Only used by official API methods. Will set an external
1542 * error when not ready.
1543 */
1544HRESULT GuestSession::i_isReadyExternal(void)
1545{
1546 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1547
1548 /** @todo Be a bit more informative. */
1549 if (mData.mStatus != GuestSessionStatus_Started)
1550 return setError(E_UNEXPECTED, tr("Session is not in started state"));
1551
1552 return S_OK;
1553}
1554
1555/**
1556 * Called by IGuest right before this session gets removed from
1557 * the public session list.
1558 */
1559int GuestSession::i_onRemove(void)
1560{
1561 LogFlowThisFuncEnter();
1562
1563 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1564
1565 int vrc = VINF_SUCCESS;
1566
1567 /*
1568 * Note: The event source stuff holds references to this object,
1569 * so make sure that this is cleaned up *before* calling uninit.
1570 */
1571 if (!mEventSource.isNull())
1572 {
1573 mEventSource->UnregisterListener(mLocalListener);
1574
1575 mLocalListener.setNull();
1576 unconst(mEventSource).setNull();
1577 }
1578
1579 LogFlowFuncLeaveRC(vrc);
1580 return vrc;
1581}
1582
1583/** No locking! */
1584int GuestSession::i_onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
1585{
1586 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
1587 /* pCallback is optional. */
1588 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
1589
1590 if (pSvcCbData->mParms < 3)
1591 return VERR_INVALID_PARAMETER;
1592
1593 CALLBACKDATA_SESSION_NOTIFY dataCb;
1594 /* pSvcCb->mpaParms[0] always contains the context ID. */
1595 int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uType);
1596 AssertRCReturn(vrc, vrc);
1597 vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uResult);
1598 AssertRCReturn(vrc, vrc);
1599
1600 LogFlowThisFunc(("ID=%RU32, uType=%RU32, guestRc=%Rrc\n",
1601 mData.mSession.mID, dataCb.uType, dataCb.uResult));
1602
1603 GuestSessionStatus_T sessionStatus = GuestSessionStatus_Undefined;
1604
1605 int guestRc = dataCb.uResult; /** @todo uint32_t vs. int. */
1606 switch (dataCb.uType)
1607 {
1608 case GUEST_SESSION_NOTIFYTYPE_ERROR:
1609 sessionStatus = GuestSessionStatus_Error;
1610 break;
1611
1612 case GUEST_SESSION_NOTIFYTYPE_STARTED:
1613 sessionStatus = GuestSessionStatus_Started;
1614#if 0 /** @todo If we get some environment stuff along with this kind notification: */
1615 const char *pszzEnvBlock = ...;
1616 uint32_t cbEnvBlock = ...;
1617 if (!mData.mpBaseEnvironment)
1618 {
1619 GuestEnvironment *pBaseEnv;
1620 try { pBaseEnv = new GuestEnvironment(); } catch (std::bad_alloc &) { pBaseEnv = NULL; }
1621 if (pBaseEnv)
1622 {
1623 int vrc = pBaseEnv->initNormal();
1624 if (RT_SUCCESS(vrc))
1625 vrc = pBaseEnv->copyUtf8Block(pszzEnvBlock, cbEnvBlock);
1626 if (RT_SUCCESS(vrc))
1627 mData.mpBaseEnvironment = pBaseEnv;
1628 else
1629 pBaseEnv->release();
1630 }
1631 }
1632#endif
1633 break;
1634
1635 case GUEST_SESSION_NOTIFYTYPE_TEN:
1636 case GUEST_SESSION_NOTIFYTYPE_TES:
1637 case GUEST_SESSION_NOTIFYTYPE_TEA:
1638 sessionStatus = GuestSessionStatus_Terminated;
1639 break;
1640
1641 case GUEST_SESSION_NOTIFYTYPE_TOK:
1642 sessionStatus = GuestSessionStatus_TimedOutKilled;
1643 break;
1644
1645 case GUEST_SESSION_NOTIFYTYPE_TOA:
1646 sessionStatus = GuestSessionStatus_TimedOutAbnormally;
1647 break;
1648
1649 case GUEST_SESSION_NOTIFYTYPE_DWN:
1650 sessionStatus = GuestSessionStatus_Down;
1651 break;
1652
1653 case GUEST_SESSION_NOTIFYTYPE_UNDEFINED:
1654 default:
1655 vrc = VERR_NOT_SUPPORTED;
1656 break;
1657 }
1658
1659 if (RT_SUCCESS(vrc))
1660 {
1661 if (RT_FAILURE(guestRc))
1662 sessionStatus = GuestSessionStatus_Error;
1663 }
1664
1665 /* Set the session status. */
1666 if (RT_SUCCESS(vrc))
1667 vrc = i_setSessionStatus(sessionStatus, guestRc);
1668
1669 LogFlowThisFunc(("ID=%RU32, guestRc=%Rrc\n", mData.mSession.mID, guestRc));
1670
1671 LogFlowFuncLeaveRC(vrc);
1672 return vrc;
1673}
1674
1675int GuestSession::i_startSessionInternal(int *pGuestRc)
1676{
1677 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1678
1679 LogFlowThisFunc(("mID=%RU32, mName=%s, uProtocolVersion=%RU32, openFlags=%x, openTimeoutMS=%RU32\n",
1680 mData.mSession.mID, mData.mSession.mName.c_str(), mData.mProtocolVersion,
1681 mData.mSession.mOpenFlags, mData.mSession.mOpenTimeoutMS));
1682
1683 /* Guest Additions < 4.3 don't support opening dedicated
1684 guest sessions. Simply return success here. */
1685 if (mData.mProtocolVersion < 2)
1686 {
1687 mData.mStatus = GuestSessionStatus_Started;
1688
1689 LogFlowThisFunc(("Installed Guest Additions don't support opening dedicated sessions, skipping\n"));
1690 return VINF_SUCCESS;
1691 }
1692
1693 if (mData.mStatus != GuestSessionStatus_Undefined)
1694 return VINF_SUCCESS;
1695
1696 /** @todo mData.mSession.uFlags validation. */
1697
1698 /* Set current session status. */
1699 mData.mStatus = GuestSessionStatus_Starting;
1700 mData.mRC = VINF_SUCCESS; /* Clear previous error, if any. */
1701
1702 int vrc;
1703
1704 GuestWaitEvent *pEvent = NULL;
1705 GuestEventTypes eventTypes;
1706 try
1707 {
1708 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
1709
1710 vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */,
1711 eventTypes, &pEvent);
1712 }
1713 catch (std::bad_alloc)
1714 {
1715 vrc = VERR_NO_MEMORY;
1716 }
1717
1718 if (RT_FAILURE(vrc))
1719 return vrc;
1720
1721 VBOXHGCMSVCPARM paParms[8];
1722
1723 int i = 0;
1724 paParms[i++].setUInt32(pEvent->ContextID());
1725 paParms[i++].setUInt32(mData.mProtocolVersion);
1726 paParms[i++].setPointer((void*)mData.mCredentials.mUser.c_str(),
1727 (ULONG)mData.mCredentials.mUser.length() + 1);
1728 paParms[i++].setPointer((void*)mData.mCredentials.mPassword.c_str(),
1729 (ULONG)mData.mCredentials.mPassword.length() + 1);
1730 paParms[i++].setPointer((void*)mData.mCredentials.mDomain.c_str(),
1731 (ULONG)mData.mCredentials.mDomain.length() + 1);
1732 paParms[i++].setUInt32(mData.mSession.mOpenFlags);
1733
1734 alock.release(); /* Drop write lock before sending. */
1735
1736 vrc = i_sendCommand(HOST_SESSION_CREATE, i, paParms);
1737 if (RT_SUCCESS(vrc))
1738 {
1739 vrc = i_waitForStatusChange(pEvent, GuestSessionWaitForFlag_Start,
1740 30 * 1000 /* 30s timeout */,
1741 NULL /* Session status */, pGuestRc);
1742 }
1743 else
1744 {
1745 /*
1746 * Unable to start guest session - update its current state.
1747 * Since there is no (official API) way to recover a failed guest session
1748 * this also marks the end state. Internally just calling this
1749 * same function again will work though.
1750 */
1751 mData.mStatus = GuestSessionStatus_Error;
1752 mData.mRC = vrc;
1753 }
1754
1755 unregisterWaitEvent(pEvent);
1756
1757 LogFlowFuncLeaveRC(vrc);
1758 return vrc;
1759}
1760
1761int GuestSession::i_startSessionAsync(void)
1762{
1763 LogFlowThisFuncEnter();
1764
1765 int vrc;
1766
1767 try
1768 {
1769 /* Asynchronously open the session on the guest by kicking off a
1770 * worker thread. */
1771 std::auto_ptr<GuestSessionTaskInternalOpen> pTask(new GuestSessionTaskInternalOpen(this));
1772 AssertReturn(pTask->isOk(), pTask->rc());
1773
1774 vrc = RTThreadCreate(NULL, GuestSession::i_startSessionThread,
1775 (void *)pTask.get(), 0,
1776 RTTHREADTYPE_MAIN_WORKER, 0,
1777 "gctlSesStart");
1778 if (RT_SUCCESS(vrc))
1779 {
1780 /* pTask is now owned by openSessionThread(), so release it. */
1781 pTask.release();
1782 }
1783 }
1784 catch(std::bad_alloc &)
1785 {
1786 vrc = VERR_NO_MEMORY;
1787 }
1788
1789 LogFlowFuncLeaveRC(vrc);
1790 return vrc;
1791}
1792
1793/* static */
1794DECLCALLBACK(int) GuestSession::i_startSessionThread(RTTHREAD Thread, void *pvUser)
1795{
1796 LogFlowFunc(("pvUser=%p\n", pvUser));
1797
1798 std::auto_ptr<GuestSessionTaskInternalOpen> pTask(static_cast<GuestSessionTaskInternalOpen*>(pvUser));
1799 AssertPtr(pTask.get());
1800
1801 const ComObjPtr<GuestSession> pSession(pTask->Session());
1802 Assert(!pSession.isNull());
1803
1804 AutoCaller autoCaller(pSession);
1805 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1806
1807 int vrc = pSession->i_startSessionInternal(NULL /* Guest rc, ignored */);
1808 /* Nothing to do here anymore. */
1809
1810 LogFlowFuncLeaveRC(vrc);
1811 return vrc;
1812}
1813
1814int GuestSession::i_pathRenameInternal(const Utf8Str &strSource, const Utf8Str &strDest,
1815 uint32_t uFlags, int *pGuestRc)
1816{
1817 AssertReturn(!(uFlags & ~PATHRENAME_FLAG_VALID_MASK), VERR_INVALID_PARAMETER);
1818
1819 LogFlowThisFunc(("strSource=%s, strDest=%s, uFlags=0x%x\n",
1820 strSource.c_str(), strDest.c_str(), uFlags));
1821
1822 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1823
1824 GuestWaitEvent *pEvent = NULL;
1825 int vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */,
1826 &pEvent);
1827 if (RT_FAILURE(vrc))
1828 return vrc;
1829
1830 /* Prepare HGCM call. */
1831 VBOXHGCMSVCPARM paParms[8];
1832 int i = 0;
1833 paParms[i++].setUInt32(pEvent->ContextID());
1834 paParms[i++].setPointer((void*)strSource.c_str(),
1835 (ULONG)strSource.length() + 1);
1836 paParms[i++].setPointer((void*)strDest.c_str(),
1837 (ULONG)strDest.length() + 1);
1838 paParms[i++].setUInt32(uFlags);
1839
1840 alock.release(); /* Drop write lock before sending. */
1841
1842 vrc = i_sendCommand(HOST_PATH_RENAME, i, paParms);
1843 if (RT_SUCCESS(vrc))
1844 {
1845 vrc = pEvent->Wait(30 * 1000);
1846 if ( vrc == VERR_GSTCTL_GUEST_ERROR
1847 && pGuestRc)
1848 *pGuestRc = pEvent->GuestResult();
1849 }
1850
1851 unregisterWaitEvent(pEvent);
1852
1853 LogFlowFuncLeaveRC(vrc);
1854 return vrc;
1855}
1856
1857int GuestSession::i_processRemoveFromList(GuestProcess *pProcess)
1858{
1859 AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
1860
1861 LogFlowThisFunc(("pProcess=%p\n", pProcess));
1862
1863 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1864
1865 int rc = VERR_NOT_FOUND;
1866
1867 ULONG uPID;
1868 HRESULT hr = pProcess->COMGETTER(PID)(&uPID);
1869 ComAssertComRC(hr);
1870
1871 LogFlowFunc(("Removing process (PID=%RU32) ...\n", uPID));
1872
1873 SessionProcesses::iterator itProcs = mData.mProcesses.begin();
1874 while (itProcs != mData.mProcesses.end())
1875 {
1876 if (pProcess == itProcs->second)
1877 {
1878#ifdef DEBUG_andy
1879 ULONG cRefs = pProcess->AddRef();
1880 Assert(cRefs >= 2);
1881 LogFlowFunc(("pProcess=%p, cRefs=%RU32\n", pProcess, cRefs - 1));
1882 pProcess->Release();
1883#endif
1884 /* Make sure to consume the pointer before the one of the
1885 * iterator gets released. */
1886 ComObjPtr<GuestProcess> pProc = pProcess;
1887
1888 hr = pProc->COMGETTER(PID)(&uPID);
1889 ComAssertComRC(hr);
1890
1891 Assert(mData.mProcesses.size());
1892 Assert(mData.mNumObjects);
1893 LogFlowFunc(("Removing process ID=%RU32 (Session: %RU32), guest PID=%RU32 (now total %zu processes, %RU32 objects)\n",
1894 pProcess->getObjectID(), mData.mSession.mID, uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1));
1895
1896 rc = pProcess->i_onRemove();
1897 mData.mProcesses.erase(itProcs);
1898 mData.mNumObjects--;
1899
1900 alock.release(); /* Release lock before firing off event. */
1901
1902 fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, pProc,
1903 uPID, false /* Process unregistered */);
1904 pProc.setNull();
1905 break;
1906 }
1907
1908 itProcs++;
1909 }
1910
1911 LogFlowFuncLeaveRC(rc);
1912 return rc;
1913}
1914
1915/**
1916 * Creates but does *not* start the process yet.
1917 *
1918 * See GuestProcess::startProcess() or GuestProcess::startProcessAsync() for
1919 * starting the process.
1920 *
1921 * @return IPRT status code.
1922 * @param procInfo
1923 * @param pProcess
1924 */
1925int GuestSession::i_processCreateExInternal(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
1926{
1927 LogFlowFunc(("mExe=%s, mFlags=%x, mTimeoutMS=%RU32\n",
1928 procInfo.mExecutable.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));
1929#ifdef DEBUG
1930 if (procInfo.mArguments.size())
1931 {
1932 LogFlowFunc(("Arguments:"));
1933 ProcessArguments::const_iterator it = procInfo.mArguments.begin();
1934 while (it != procInfo.mArguments.end())
1935 {
1936 LogFlow((" %s", (*it).c_str()));
1937 it++;
1938 }
1939 LogFlow(("\n"));
1940 }
1941#endif
1942
1943 /* Validate flags. */
1944 if (procInfo.mFlags)
1945 {
1946 if ( !(procInfo.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
1947 && !(procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1948 && !(procInfo.mFlags & ProcessCreateFlag_Hidden)
1949 && !(procInfo.mFlags & ProcessCreateFlag_NoProfile)
1950 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1951 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdErr))
1952 {
1953 return VERR_INVALID_PARAMETER;
1954 }
1955 }
1956
1957 if ( (procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1958 && ( (procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1959 || (procInfo.mFlags & ProcessCreateFlag_WaitForStdErr)
1960 )
1961 )
1962 {
1963 return VERR_INVALID_PARAMETER;
1964 }
1965
1966 /* Adjust timeout. If set to 0, we define
1967 * an infinite timeout. */
1968 if (procInfo.mTimeoutMS == 0)
1969 procInfo.mTimeoutMS = UINT32_MAX;
1970
1971 /** @tood Implement process priority + affinity. */
1972
1973 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1974
1975 int rc = VERR_MAX_PROCS_REACHED;
1976 if (mData.mNumObjects >= VBOX_GUESTCTRL_MAX_OBJECTS)
1977 return rc;
1978
1979 /* Create a new (host-based) process ID and assign it. */
1980 uint32_t uNewProcessID = 0;
1981 ULONG uTries = 0;
1982
1983 for (;;)
1984 {
1985 /* Is the context ID already used? */
1986 if (!i_processExists(uNewProcessID, NULL /* pProcess */))
1987 {
1988 /* Callback with context ID was not found. This means
1989 * we can use this context ID for our new callback we want
1990 * to add below. */
1991 rc = VINF_SUCCESS;
1992 break;
1993 }
1994 uNewProcessID++;
1995 if (uNewProcessID == VBOX_GUESTCTRL_MAX_OBJECTS)
1996 uNewProcessID = 0;
1997
1998 if (++uTries == VBOX_GUESTCTRL_MAX_OBJECTS)
1999 break; /* Don't try too hard. */
2000 }
2001
2002 if (RT_FAILURE(rc))
2003 return rc;
2004
2005 /* Create the process object. */
2006 HRESULT hr = pProcess.createObject();
2007 if (FAILED(hr))
2008 return VERR_COM_UNEXPECTED;
2009
2010 rc = pProcess->init(mParent->i_getConsole() /* Console */, this /* Session */,
2011 uNewProcessID, procInfo, mData.mpBaseEnvironment);
2012 if (RT_FAILURE(rc))
2013 return rc;
2014
2015 /* Add the created process to our map. */
2016 try
2017 {
2018 mData.mProcesses[uNewProcessID] = pProcess;
2019 mData.mNumObjects++;
2020 Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS);
2021
2022 LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %zu processes, %RU32 objects)\n",
2023 mData.mSession.mID, uNewProcessID, mData.mProcesses.size(), mData.mNumObjects));
2024
2025 alock.release(); /* Release lock before firing off event. */
2026
2027 fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, pProcess,
2028 0 /* PID */, true /* Process registered */);
2029 }
2030 catch (std::bad_alloc &)
2031 {
2032 rc = VERR_NO_MEMORY;
2033 }
2034
2035 return rc;
2036}
2037
2038inline bool GuestSession::i_processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess)
2039{
2040 SessionProcesses::const_iterator it = mData.mProcesses.find(uProcessID);
2041 if (it != mData.mProcesses.end())
2042 {
2043 if (pProcess)
2044 *pProcess = it->second;
2045 return true;
2046 }
2047 return false;
2048}
2049
2050inline int GuestSession::i_processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess)
2051{
2052 AssertReturn(uPID, false);
2053 /* pProcess is optional. */
2054
2055 SessionProcesses::iterator itProcs = mData.mProcesses.begin();
2056 for (; itProcs != mData.mProcesses.end(); itProcs++)
2057 {
2058 ComObjPtr<GuestProcess> pCurProc = itProcs->second;
2059 AutoCaller procCaller(pCurProc);
2060 if (procCaller.rc())
2061 return VERR_COM_INVALID_OBJECT_STATE;
2062
2063 ULONG uCurPID;
2064 HRESULT hr = pCurProc->COMGETTER(PID)(&uCurPID);
2065 ComAssertComRC(hr);
2066
2067 if (uCurPID == uPID)
2068 {
2069 if (pProcess)
2070 *pProcess = pCurProc;
2071 return VINF_SUCCESS;
2072 }
2073 }
2074
2075 return VERR_NOT_FOUND;
2076}
2077
2078int GuestSession::i_sendCommand(uint32_t uFunction,
2079 uint32_t uParms, PVBOXHGCMSVCPARM paParms)
2080{
2081 LogFlowThisFuncEnter();
2082
2083#ifndef VBOX_GUESTCTRL_TEST_CASE
2084 ComObjPtr<Console> pConsole = mParent->i_getConsole();
2085 Assert(!pConsole.isNull());
2086
2087 /* Forward the information to the VMM device. */
2088 VMMDev *pVMMDev = pConsole->i_getVMMDev();
2089 AssertPtr(pVMMDev);
2090
2091 LogFlowThisFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms));
2092 int vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, uParms, paParms);
2093 if (RT_FAILURE(vrc))
2094 {
2095 /** @todo What to do here? */
2096 }
2097#else
2098 /* Not needed within testcases. */
2099 int vrc = VINF_SUCCESS;
2100#endif
2101 LogFlowFuncLeaveRC(vrc);
2102 return vrc;
2103}
2104
2105/* static */
2106HRESULT GuestSession::i_setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
2107{
2108 AssertPtr(pInterface);
2109 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
2110
2111 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestSession::i_guestErrorToString(guestRc).c_str());
2112}
2113
2114/* Does not do locking; caller is responsible for that! */
2115int GuestSession::i_setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc)
2116{
2117 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, sessionRc=%Rrc\n",
2118 mData.mStatus, sessionStatus, sessionRc));
2119
2120 if (sessionStatus == GuestSessionStatus_Error)
2121 {
2122 AssertMsg(RT_FAILURE(sessionRc), ("Guest rc must be an error (%Rrc)\n", sessionRc));
2123 /* Do not allow overwriting an already set error. If this happens
2124 * this means we forgot some error checking/locking somewhere. */
2125 AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));
2126 }
2127 else
2128 AssertMsg(RT_SUCCESS(sessionRc), ("Guest rc must not be an error (%Rrc)\n", sessionRc));
2129
2130 if (mData.mStatus != sessionStatus)
2131 {
2132 mData.mStatus = sessionStatus;
2133 mData.mRC = sessionRc;
2134
2135 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
2136 HRESULT hr = errorInfo.createObject();
2137 ComAssertComRC(hr);
2138 int rc2 = errorInfo->initEx(VBOX_E_IPRT_ERROR, sessionRc,
2139 COM_IIDOF(IGuestSession), getComponentName(),
2140 i_guestErrorToString(sessionRc));
2141 AssertRC(rc2);
2142
2143 fireGuestSessionStateChangedEvent(mEventSource, this,
2144 mData.mSession.mID, sessionStatus, errorInfo);
2145 }
2146
2147 return VINF_SUCCESS;
2148}
2149
2150int GuestSession::i_signalWaiters(GuestSessionWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */)
2151{
2152 /*LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n",
2153 enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));*/
2154
2155 /* Note: No write locking here -- already done in the caller. */
2156
2157 int vrc = VINF_SUCCESS;
2158 /*if (mData.mWaitEvent)
2159 vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);*/
2160 LogFlowFuncLeaveRC(vrc);
2161 return vrc;
2162}
2163
2164int GuestSession::i_startTaskAsync(const Utf8Str &strTaskDesc,
2165 GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress)
2166{
2167 LogFlowThisFunc(("strTaskDesc=%s, pTask=%p\n", strTaskDesc.c_str(), pTask));
2168
2169 AssertPtrReturn(pTask, VERR_INVALID_POINTER);
2170
2171 /* Create the progress object. */
2172 HRESULT hr = pProgress.createObject();
2173 if (FAILED(hr))
2174 return VERR_COM_UNEXPECTED;
2175
2176 hr = pProgress->init(static_cast<IGuestSession*>(this),
2177 Bstr(strTaskDesc).raw(),
2178 TRUE /* aCancelable */);
2179 if (FAILED(hr))
2180 return VERR_COM_UNEXPECTED;
2181
2182 /* Initialize our worker task. */
2183 std::auto_ptr<GuestSessionTask> task(pTask);
2184
2185 int rc = task->RunAsync(strTaskDesc, pProgress);
2186 if (RT_FAILURE(rc))
2187 return rc;
2188
2189 /* Don't destruct on success. */
2190 task.release();
2191
2192 LogFlowFuncLeaveRC(rc);
2193 return rc;
2194}
2195
2196/**
2197 * Determines the protocol version (sets mData.mProtocolVersion).
2198 *
2199 * This is called from the init method prior to to establishing a guest
2200 * session.
2201 *
2202 * @return IPRT status code.
2203 */
2204int GuestSession::i_determineProtocolVersion(void)
2205{
2206 /*
2207 * We currently do this based on the reported guest additions version,
2208 * ASSUMING that VBoxService and VBoxDrv are at the same version.
2209 */
2210 ComObjPtr<Guest> pGuest = mParent;
2211 AssertReturn(!pGuest.isNull(), VERR_NOT_SUPPORTED);
2212 uint32_t uGaVersion = pGuest->i_getAdditionsVersion();
2213
2214 /* Everyone supports version one, if they support anything at all. */
2215 mData.mProtocolVersion = 1;
2216
2217 /* Guest control 2.0 was introduced with 4.3.0. */
2218 if (uGaVersion >= VBOX_FULL_VERSION_MAKE(4,3,0))
2219 mData.mProtocolVersion = 2; /* Guest control 2.0. */
2220
2221 LogFlowThisFunc(("uGaVersion=%u.%u.%u => mProtocolVersion=%u\n",
2222 VBOX_FULL_VERSION_GET_MAJOR(uGaVersion), VBOX_FULL_VERSION_GET_MINOR(uGaVersion),
2223 VBOX_FULL_VERSION_GET_BUILD(uGaVersion), mData.mProtocolVersion));
2224
2225 /*
2226 * Inform the user about outdated guest additions (VM release log).
2227 */
2228 if (mData.mProtocolVersion < 2)
2229 LogRelMax(3, (tr("Warning: Guest Additions v%u.%u.%u only supports the older guest control protocol version %u.\n"
2230 " Please upgrade GAs to the current version to get full guest control capabilities.\n"),
2231 VBOX_FULL_VERSION_GET_MAJOR(uGaVersion), VBOX_FULL_VERSION_GET_MINOR(uGaVersion),
2232 VBOX_FULL_VERSION_GET_BUILD(uGaVersion), mData.mProtocolVersion));
2233
2234 return VINF_SUCCESS;
2235}
2236
2237int GuestSession::i_waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestSessionWaitResult_T &waitResult, int *pGuestRc)
2238{
2239 LogFlowThisFuncEnter();
2240
2241 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
2242
2243 /*LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",
2244 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));*/
2245
2246 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2247
2248 /* Did some error occur before? Then skip waiting and return. */
2249 if (mData.mStatus == GuestSessionStatus_Error)
2250 {
2251 waitResult = GuestSessionWaitResult_Error;
2252 AssertMsg(RT_FAILURE(mData.mRC), ("No error rc (%Rrc) set when guest session indicated an error\n", mData.mRC));
2253 if (pGuestRc)
2254 *pGuestRc = mData.mRC; /* Return last set error. */
2255 return VERR_GSTCTL_GUEST_ERROR;
2256 }
2257
2258 /* Guest Additions < 4.3 don't support session handling, skip. */
2259 if (mData.mProtocolVersion < 2)
2260 {
2261 waitResult = GuestSessionWaitResult_WaitFlagNotSupported;
2262
2263 LogFlowThisFunc(("Installed Guest Additions don't support waiting for dedicated sessions, skipping\n"));
2264 return VINF_SUCCESS;
2265 }
2266
2267 waitResult = GuestSessionWaitResult_None;
2268 if (fWaitFlags & GuestSessionWaitForFlag_Terminate)
2269 {
2270 switch (mData.mStatus)
2271 {
2272 case GuestSessionStatus_Terminated:
2273 case GuestSessionStatus_Down:
2274 waitResult = GuestSessionWaitResult_Terminate;
2275 break;
2276
2277 case GuestSessionStatus_TimedOutKilled:
2278 case GuestSessionStatus_TimedOutAbnormally:
2279 waitResult = GuestSessionWaitResult_Timeout;
2280 break;
2281
2282 case GuestSessionStatus_Error:
2283 /* Handled above. */
2284 break;
2285
2286 case GuestSessionStatus_Started:
2287 waitResult = GuestSessionWaitResult_Start;
2288 break;
2289
2290 case GuestSessionStatus_Undefined:
2291 case GuestSessionStatus_Starting:
2292 /* Do the waiting below. */
2293 break;
2294
2295 default:
2296 AssertMsgFailed(("Unhandled session status %RU32\n", mData.mStatus));
2297 return VERR_NOT_IMPLEMENTED;
2298 }
2299 }
2300 else if (fWaitFlags & GuestSessionWaitForFlag_Start)
2301 {
2302 switch (mData.mStatus)
2303 {
2304 case GuestSessionStatus_Started:
2305 case GuestSessionStatus_Terminating:
2306 case GuestSessionStatus_Terminated:
2307 case GuestSessionStatus_Down:
2308 waitResult = GuestSessionWaitResult_Start;
2309 break;
2310
2311 case GuestSessionStatus_Error:
2312 waitResult = GuestSessionWaitResult_Error;
2313 break;
2314
2315 case GuestSessionStatus_TimedOutKilled:
2316 case GuestSessionStatus_TimedOutAbnormally:
2317 waitResult = GuestSessionWaitResult_Timeout;
2318 break;
2319
2320 case GuestSessionStatus_Undefined:
2321 case GuestSessionStatus_Starting:
2322 /* Do the waiting below. */
2323 break;
2324
2325 default:
2326 AssertMsgFailed(("Unhandled session status %RU32\n", mData.mStatus));
2327 return VERR_NOT_IMPLEMENTED;
2328 }
2329 }
2330
2331 LogFlowThisFunc(("sessionStatus=%RU32, sessionRc=%Rrc, waitResult=%RU32\n",
2332 mData.mStatus, mData.mRC, waitResult));
2333
2334 /* No waiting needed? Return immediately using the last set error. */
2335 if (waitResult != GuestSessionWaitResult_None)
2336 {
2337 if (pGuestRc)
2338 *pGuestRc = mData.mRC; /* Return last set error (if any). */
2339 return RT_SUCCESS(mData.mRC) ? VINF_SUCCESS : VERR_GSTCTL_GUEST_ERROR;
2340 }
2341
2342 int vrc;
2343
2344 GuestWaitEvent *pEvent = NULL;
2345 GuestEventTypes eventTypes;
2346 try
2347 {
2348 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
2349
2350 vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */,
2351 eventTypes, &pEvent);
2352 }
2353 catch (std::bad_alloc)
2354 {
2355 vrc = VERR_NO_MEMORY;
2356 }
2357
2358 if (RT_FAILURE(vrc))
2359 return vrc;
2360
2361 alock.release(); /* Release lock before waiting. */
2362
2363 GuestSessionStatus_T sessionStatus;
2364 vrc = i_waitForStatusChange(pEvent, fWaitFlags,
2365 uTimeoutMS, &sessionStatus, pGuestRc);
2366 if (RT_SUCCESS(vrc))
2367 {
2368 switch (sessionStatus)
2369 {
2370 case GuestSessionStatus_Started:
2371 waitResult = GuestSessionWaitResult_Start;
2372 break;
2373
2374 case GuestSessionStatus_Terminated:
2375 waitResult = GuestSessionWaitResult_Terminate;
2376 break;
2377
2378 case GuestSessionStatus_TimedOutKilled:
2379 case GuestSessionStatus_TimedOutAbnormally:
2380 waitResult = GuestSessionWaitResult_Timeout;
2381 break;
2382
2383 case GuestSessionStatus_Down:
2384 waitResult = GuestSessionWaitResult_Terminate;
2385 break;
2386
2387 case GuestSessionStatus_Error:
2388 waitResult = GuestSessionWaitResult_Error;
2389 break;
2390
2391 default:
2392 waitResult = GuestSessionWaitResult_Status;
2393 break;
2394 }
2395 }
2396
2397 unregisterWaitEvent(pEvent);
2398
2399 LogFlowFuncLeaveRC(vrc);
2400 return vrc;
2401}
2402
2403int GuestSession::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS,
2404 GuestSessionStatus_T *pSessionStatus, int *pGuestRc)
2405{
2406 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2407
2408 VBoxEventType_T evtType;
2409 ComPtr<IEvent> pIEvent;
2410 int vrc = waitForEvent(pEvent, uTimeoutMS,
2411 &evtType, pIEvent.asOutParam());
2412 if (RT_SUCCESS(vrc))
2413 {
2414 Assert(evtType == VBoxEventType_OnGuestSessionStateChanged);
2415
2416 ComPtr<IGuestSessionStateChangedEvent> pChangedEvent = pIEvent;
2417 Assert(!pChangedEvent.isNull());
2418
2419 GuestSessionStatus_T sessionStatus;
2420 pChangedEvent->COMGETTER(Status)(&sessionStatus);
2421 if (pSessionStatus)
2422 *pSessionStatus = sessionStatus;
2423
2424 ComPtr<IVirtualBoxErrorInfo> errorInfo;
2425 HRESULT hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam());
2426 ComAssertComRC(hr);
2427
2428 LONG lGuestRc;
2429 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
2430 ComAssertComRC(hr);
2431 if (RT_FAILURE((int)lGuestRc))
2432 vrc = VERR_GSTCTL_GUEST_ERROR;
2433 if (pGuestRc)
2434 *pGuestRc = (int)lGuestRc;
2435
2436 LogFlowThisFunc(("Status changed event for session ID=%RU32, new status is: %RU32 (%Rrc)\n",
2437 mData.mSession.mID, sessionStatus,
2438 RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc));
2439 }
2440
2441 LogFlowFuncLeaveRC(vrc);
2442 return vrc;
2443}
2444
2445// implementation of public methods
2446/////////////////////////////////////////////////////////////////////////////
2447
2448HRESULT GuestSession::close()
2449{
2450#ifndef VBOX_WITH_GUEST_CONTROL
2451 ReturnComNotImplemented();
2452#else
2453 LogFlowThisFuncEnter();
2454
2455 AutoCaller autoCaller(this);
2456 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2457
2458 /* Close session on guest. */
2459 int guestRc = VINF_SUCCESS;
2460 int rc = i_closeSession(0 /* Flags */, 30 * 1000 /* Timeout */,
2461 &guestRc);
2462 /* On failure don't return here, instead do all the cleanup
2463 * work first and then return an error. */
2464
2465 /* Remove ourselves from the session list. */
2466 int rc2 = mParent->i_sessionRemove(this);
2467 if (rc2 == VERR_NOT_FOUND) /* Not finding the session anymore isn't critical. */
2468 rc2 = VINF_SUCCESS;
2469
2470 if (RT_SUCCESS(rc))
2471 rc = rc2;
2472
2473 LogFlowThisFunc(("Returning rc=%Rrc, guestRc=%Rrc\n",
2474 rc, guestRc));
2475 if (RT_FAILURE(rc))
2476 {
2477 if (rc == VERR_GSTCTL_GUEST_ERROR)
2478 return GuestSession::i_setErrorExternal(this, guestRc);
2479
2480 return setError(VBOX_E_IPRT_ERROR,
2481 tr("Closing guest session failed with %Rrc"), rc);
2482 }
2483
2484 return S_OK;
2485#endif /* VBOX_WITH_GUEST_CONTROL */
2486}
2487
2488HRESULT GuestSession::copyFrom(const com::Utf8Str &aSource, const com::Utf8Str &aDest,
2489 const std::vector<CopyFileFlag_T> &aFlags,
2490 ComPtr<IProgress> &aProgress)
2491{
2492#ifndef VBOX_WITH_GUEST_CONTROL
2493 ReturnComNotImplemented();
2494#else
2495
2496 LogFlowThisFuncEnter();
2497
2498 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0'))
2499 return setError(E_INVALIDARG, tr("No source specified"));
2500 if (RT_UNLIKELY((aDest.c_str()) == NULL || *(aDest.c_str()) == '\0'))
2501 return setError(E_INVALIDARG, tr("No destination specified"));
2502
2503 uint32_t fFlags = CopyFileFlag_None;
2504 if (aFlags.size())
2505 {
2506 for (size_t i = 0; i < aFlags.size(); i++)
2507 fFlags |= aFlags[i];
2508 }
2509
2510 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2511
2512 HRESULT hr = S_OK;
2513
2514 try
2515 {
2516 ComObjPtr<Progress> pProgress;
2517 SessionTaskCopyFrom *pTask = new SessionTaskCopyFrom(this /* GuestSession */,
2518 aSource, aDest, fFlags);
2519 int rc = i_startTaskAsync(Utf8StrFmt(tr("Copying \"%s\" from guest to \"%s\" on the host"), aSource.c_str(),
2520 aDest.c_str()), pTask, pProgress);
2521 if (RT_SUCCESS(rc))
2522 /* Return progress to the caller. */
2523 hr = pProgress.queryInterfaceTo(aProgress.asOutParam());
2524 else
2525 hr = setError(VBOX_E_IPRT_ERROR,
2526 tr("Starting task for copying file \"%s\" from guest to \"%s\" on the host failed: %Rrc"), rc);
2527 }
2528 catch(std::bad_alloc &)
2529 {
2530 hr = E_OUTOFMEMORY;
2531 }
2532
2533 return hr;
2534#endif /* VBOX_WITH_GUEST_CONTROL */
2535}
2536
2537HRESULT GuestSession::copyTo(const com::Utf8Str &aSource, const com::Utf8Str &aDest, const std::vector<CopyFileFlag_T> &aFlags,
2538 ComPtr<IProgress> &aProgress)
2539{
2540#ifndef VBOX_WITH_GUEST_CONTROL
2541 ReturnComNotImplemented();
2542#else
2543
2544 LogFlowThisFuncEnter();
2545
2546 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0'))
2547 return setError(E_INVALIDARG, tr("No source specified"));
2548 if (RT_UNLIKELY((aDest.c_str()) == NULL || *(aDest.c_str()) == '\0'))
2549 return setError(E_INVALIDARG, tr("No destination specified"));
2550
2551 uint32_t fFlags = CopyFileFlag_None;
2552 if (aFlags.size())
2553 {
2554 for (size_t i = 0; i < aFlags.size(); i++)
2555 fFlags |= aFlags[i];
2556 }
2557
2558 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2559
2560 HRESULT hr = S_OK;
2561
2562 try
2563 {
2564 ComObjPtr<Progress> pProgress;
2565 SessionTaskCopyTo *pTask = new SessionTaskCopyTo(this /* GuestSession */,
2566 aSource, aDest, fFlags);
2567 AssertPtrReturn(pTask, E_OUTOFMEMORY);
2568 int rc = i_startTaskAsync(Utf8StrFmt(tr("Copying \"%s\" from host to \"%s\" on the guest"), aSource.c_str(),
2569 aDest.c_str()), pTask, pProgress);
2570 if (RT_SUCCESS(rc))
2571 {
2572 /* Return progress to the caller. */
2573 hr = pProgress.queryInterfaceTo(aProgress.asOutParam());
2574 }
2575 else
2576 hr = setError(VBOX_E_IPRT_ERROR,
2577 tr("Starting task for copying file \"%s\" from host to \"%s\" on the guest failed: %Rrc"), rc);
2578 }
2579 catch(std::bad_alloc &)
2580 {
2581 hr = E_OUTOFMEMORY;
2582 }
2583
2584 return hr;
2585#endif /* VBOX_WITH_GUEST_CONTROL */
2586}
2587
2588HRESULT GuestSession::directoryCreate(const com::Utf8Str &aPath, ULONG aMode,
2589 const std::vector<DirectoryCreateFlag_T> &aFlags)
2590{
2591#ifndef VBOX_WITH_GUEST_CONTROL
2592 ReturnComNotImplemented();
2593#else
2594 LogFlowThisFuncEnter();
2595
2596 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2597 return setError(E_INVALIDARG, tr("No directory to create specified"));
2598
2599 uint32_t fFlags = DirectoryCreateFlag_None;
2600 if (aFlags.size())
2601 {
2602 for (size_t i = 0; i < aFlags.size(); i++)
2603 fFlags |= aFlags[i];
2604
2605 if (fFlags)
2606 if (!(fFlags & DirectoryCreateFlag_Parents))
2607 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), fFlags);
2608 }
2609
2610 HRESULT hr = S_OK;
2611
2612 ComObjPtr <GuestDirectory> pDirectory; int guestRc;
2613 int rc = i_directoryCreateInternal(aPath, (uint32_t)aMode, fFlags, &guestRc);
2614 if (RT_FAILURE(rc))
2615 {
2616 switch (rc)
2617 {
2618 case VERR_GSTCTL_GUEST_ERROR:
2619 /** @todo Handle VERR_NOT_EQUAL (meaning process exit code <> 0). */
2620 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Could not create directory"));
2621 break;
2622
2623 case VERR_INVALID_PARAMETER:
2624 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Invalid parameters given"));
2625 break;
2626
2627 case VERR_BROKEN_PIPE:
2628 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Unexpectedly aborted"));
2629 break;
2630
2631 default:
2632 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
2633 break;
2634 }
2635 }
2636
2637 return hr;
2638#endif /* VBOX_WITH_GUEST_CONTROL */
2639}
2640
2641HRESULT GuestSession::directoryCreateTemp(const com::Utf8Str &aTemplateName, ULONG aMode, const com::Utf8Str &aPath,
2642 BOOL aSecure, com::Utf8Str &aDirectory)
2643{
2644#ifndef VBOX_WITH_GUEST_CONTROL
2645 ReturnComNotImplemented();
2646#else
2647 LogFlowThisFuncEnter();
2648
2649 if (RT_UNLIKELY((aTemplateName.c_str()) == NULL || *(aTemplateName.c_str()) == '\0'))
2650 return setError(E_INVALIDARG, tr("No template specified"));
2651 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2652 return setError(E_INVALIDARG, tr("No directory name specified"));
2653
2654 HRESULT hr = S_OK;
2655
2656 int guestRc;
2657 int rc = i_objectCreateTempInternal(aTemplateName,
2658 aPath,
2659 true /* Directory */, aDirectory, &guestRc);
2660 if (!RT_SUCCESS(rc))
2661 {
2662 switch (rc)
2663 {
2664 case VERR_GSTCTL_GUEST_ERROR:
2665 hr = GuestProcess::i_setErrorExternal(this, guestRc);
2666 break;
2667
2668 default:
2669 hr = setError(VBOX_E_IPRT_ERROR, tr("Temporary directory creation \"%s\" with template \"%s\" failed: %Rrc"),
2670 aPath.c_str(), aTemplateName.c_str(), rc);
2671 break;
2672 }
2673 }
2674
2675 return hr;
2676#endif /* VBOX_WITH_GUEST_CONTROL */
2677}
2678
2679HRESULT GuestSession::directoryExists(const com::Utf8Str &aPath, BOOL *aExists)
2680{
2681#ifndef VBOX_WITH_GUEST_CONTROL
2682 ReturnComNotImplemented();
2683#else
2684 LogFlowThisFuncEnter();
2685
2686 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2687 return setError(E_INVALIDARG, tr("No directory to check existence for specified"));
2688
2689 HRESULT hr = S_OK;
2690
2691 GuestFsObjData objData; int guestRc;
2692 int rc = i_directoryQueryInfoInternal(aPath, false /*fFollowSymlinks*/, objData, &guestRc);
2693 if (RT_SUCCESS(rc))
2694 *aExists = objData.mType == FsObjType_Directory;
2695 else
2696 {
2697 switch (rc)
2698 {
2699 case VERR_GSTCTL_GUEST_ERROR:
2700 hr = GuestProcess::i_setErrorExternal(this, guestRc);
2701 break;
2702
2703 default:
2704 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence \"%s\" failed: %Rrc"),
2705 aPath.c_str(), rc);
2706 break;
2707 }
2708 }
2709
2710 return hr;
2711#endif /* VBOX_WITH_GUEST_CONTROL */
2712}
2713
2714HRESULT GuestSession::directoryOpen(const com::Utf8Str &aPath, const com::Utf8Str &aFilter,
2715 const std::vector<DirectoryOpenFlag_T> &aFlags, ComPtr<IGuestDirectory> &aDirectory)
2716{
2717#ifndef VBOX_WITH_GUEST_CONTROL
2718 ReturnComNotImplemented();
2719#else
2720 LogFlowThisFuncEnter();
2721
2722 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2723 return setError(E_INVALIDARG, tr("No directory to open specified"));
2724 if (RT_UNLIKELY((aFilter.c_str()) != NULL && *(aFilter.c_str()) != '\0'))
2725 return setError(E_INVALIDARG, tr("Directory filters are not implemented yet"));
2726
2727 uint32_t fFlags = DirectoryOpenFlag_None;
2728 if (aFlags.size())
2729 {
2730 for (size_t i = 0; i < aFlags.size(); i++)
2731 fFlags |= aFlags[i];
2732
2733 if (fFlags)
2734 return setError(E_INVALIDARG, tr("Open flags (%#x) not implemented yet"), fFlags);
2735 }
2736
2737 HRESULT hr = S_OK;
2738
2739 GuestDirectoryOpenInfo openInfo;
2740 openInfo.mPath = aPath;
2741 openInfo.mFilter = aFilter;
2742 openInfo.mFlags = fFlags;
2743
2744 ComObjPtr <GuestDirectory> pDirectory; int guestRc;
2745 int rc = i_directoryOpenInternal(openInfo, pDirectory, &guestRc);
2746 if (RT_SUCCESS(rc))
2747 {
2748 /* Return directory object to the caller. */
2749 hr = pDirectory.queryInterfaceTo(aDirectory.asOutParam());
2750 }
2751 else
2752 {
2753 switch (rc)
2754 {
2755 case VERR_INVALID_PARAMETER:
2756 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed; invalid parameters given"),
2757 aPath.c_str());
2758 break;
2759
2760 case VERR_GSTCTL_GUEST_ERROR:
2761 hr = GuestDirectory::i_setErrorExternal(this, guestRc);
2762 break;
2763
2764 default:
2765 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed: %Rrc"),
2766 aPath.c_str(),rc);
2767 break;
2768 }
2769 }
2770
2771 return hr;
2772#endif /* VBOX_WITH_GUEST_CONTROL */
2773}
2774
2775HRESULT GuestSession::directoryQueryInfo(const com::Utf8Str &aPath, ComPtr<IGuestFsObjInfo> &aInfo)
2776{
2777#ifndef VBOX_WITH_GUEST_CONTROL
2778 ReturnComNotImplemented();
2779#else
2780 LogFlowThisFuncEnter();
2781
2782 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2783 return setError(E_INVALIDARG, tr("No directory to query information for specified"));
2784
2785 HRESULT hr = S_OK;
2786
2787 GuestFsObjData objData; int guestRc;
2788 int vrc = i_directoryQueryInfoInternal(aPath, false /*fFollowSymlinks*/, objData, &guestRc);
2789 if (RT_SUCCESS(vrc))
2790 {
2791 if (objData.mType == FsObjType_Directory)
2792 {
2793 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
2794 hr = pFsObjInfo.createObject();
2795 if (FAILED(hr)) return hr;
2796
2797 vrc = pFsObjInfo->init(objData);
2798 if (RT_SUCCESS(vrc))
2799 {
2800 hr = pFsObjInfo.queryInterfaceTo(aInfo.asOutParam());
2801 if (FAILED(hr)) return hr;
2802 }
2803 }
2804 }
2805
2806 if (RT_FAILURE(vrc))
2807 {
2808 switch (vrc)
2809 {
2810 case VERR_GSTCTL_GUEST_ERROR:
2811 hr = GuestProcess::i_setErrorExternal(this, guestRc);
2812 break;
2813
2814 case VERR_NOT_A_DIRECTORY:
2815 hr = setError(VBOX_E_IPRT_ERROR, tr("Element \"%s\" exists but is not a directory"),
2816 aPath.c_str());
2817 break;
2818
2819 default:
2820 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information for \"%s\" failed: %Rrc"),
2821 aPath.c_str(), vrc);
2822 break;
2823 }
2824 }
2825
2826 return hr;
2827#endif /* VBOX_WITH_GUEST_CONTROL */
2828}
2829
2830HRESULT GuestSession::directoryRemove(const com::Utf8Str &aPath)
2831{
2832#ifndef VBOX_WITH_GUEST_CONTROL
2833 ReturnComNotImplemented();
2834#else
2835 LogFlowThisFuncEnter();
2836
2837 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2838 return setError(E_INVALIDARG, tr("No directory to remove specified"));
2839
2840 HRESULT hr = i_isReadyExternal();
2841 if (FAILED(hr))
2842 return hr;
2843
2844 /* No flags; only remove the directory when empty. */
2845 uint32_t uFlags = 0;
2846
2847 int guestRc;
2848 int vrc = i_directoryRemoveInternal(aPath, uFlags, &guestRc);
2849 if (RT_FAILURE(vrc))
2850 {
2851 switch (vrc)
2852 {
2853 case VERR_NOT_SUPPORTED:
2854 hr = setError(VBOX_E_IPRT_ERROR,
2855 tr("Handling removing guest directories not supported by installed Guest Additions"));
2856 break;
2857
2858 case VERR_GSTCTL_GUEST_ERROR:
2859 hr = GuestDirectory::i_setErrorExternal(this, guestRc);
2860 break;
2861
2862 default:
2863 hr = setError(VBOX_E_IPRT_ERROR, tr("Removing guest directory \"%s\" failed: %Rrc"),
2864 aPath.c_str(), vrc);
2865 break;
2866 }
2867 }
2868
2869 return hr;
2870#endif /* VBOX_WITH_GUEST_CONTROL */
2871}
2872
2873HRESULT GuestSession::directoryRemoveRecursive(const com::Utf8Str &aPath, const std::vector<DirectoryRemoveRecFlag_T> &aFlags,
2874 ComPtr<IProgress> &aProgress)
2875{
2876#ifndef VBOX_WITH_GUEST_CONTROL
2877 ReturnComNotImplemented();
2878#else
2879 LogFlowThisFuncEnter();
2880
2881 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2882 return setError(E_INVALIDARG, tr("No directory to remove recursively specified"));
2883
2884 HRESULT hr = i_isReadyExternal();
2885 if (FAILED(hr))
2886 return hr;
2887
2888 ComObjPtr<Progress> pProgress;
2889 hr = pProgress.createObject();
2890 if (SUCCEEDED(hr))
2891 hr = pProgress->init(static_cast<IGuestSession *>(this),
2892 Bstr(tr("Removing guest directory")).raw(),
2893 TRUE /*aCancelable*/);
2894 if (FAILED(hr))
2895 return hr;
2896
2897 /* Note: At the moment we don't supply progress information while
2898 * deleting a guest directory recursively. So just complete
2899 * the progress object right now. */
2900 /** @todo Implement progress reporting on guest directory deletion! */
2901 hr = pProgress->i_notifyComplete(S_OK);
2902 if (FAILED(hr))
2903 return hr;
2904
2905 /* Remove the directory + all its contents. */
2906 uint32_t uFlags = DIRREMOVE_FLAG_RECURSIVE
2907 | DIRREMOVE_FLAG_CONTENT_AND_DIR;
2908 int guestRc;
2909 int vrc = i_directoryRemoveInternal(aPath, uFlags, &guestRc);
2910 if (RT_FAILURE(vrc))
2911 {
2912 switch (vrc)
2913 {
2914 case VERR_NOT_SUPPORTED:
2915 hr = setError(VBOX_E_IPRT_ERROR,
2916 tr("Handling removing guest directories recursively not supported by installed Guest Additions"));
2917 break;
2918
2919 case VERR_GSTCTL_GUEST_ERROR:
2920 hr = GuestFile::i_setErrorExternal(this, guestRc);
2921 break;
2922
2923 default:
2924 hr = setError(VBOX_E_IPRT_ERROR, tr("Recursively removing guest directory \"%s\" failed: %Rrc"),
2925 aPath.c_str(), vrc);
2926 break;
2927 }
2928 }
2929 else
2930 {
2931 pProgress.queryInterfaceTo(aProgress.asOutParam());
2932 }
2933
2934 return hr;
2935#endif /* VBOX_WITH_GUEST_CONTROL */
2936}
2937
2938HRESULT GuestSession::directoryRename(const com::Utf8Str &aSource,
2939 const com::Utf8Str &aDest,
2940 const std::vector<PathRenameFlag_T> &aFlags)
2941{
2942#ifndef VBOX_WITH_GUEST_CONTROL
2943 ReturnComNotImplemented();
2944#else
2945 LogFlowThisFuncEnter();
2946
2947 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0'))
2948 return setError(E_INVALIDARG, tr("No source directory to rename specified"));
2949
2950 if (RT_UNLIKELY((aDest.c_str()) == NULL || *(aDest.c_str()) == '\0'))
2951 return setError(E_INVALIDARG, tr("No destination directory to rename the source to specified"));
2952
2953 HRESULT hr = i_isReadyExternal();
2954 if (FAILED(hr))
2955 return hr;
2956
2957 /* No flags; only remove the directory when empty. */
2958 uint32_t uFlags = 0;
2959
2960 int guestRc;
2961 int vrc = i_pathRenameInternal(aSource, aDest, uFlags, &guestRc);
2962 if (RT_FAILURE(vrc))
2963 {
2964 switch (vrc)
2965 {
2966 case VERR_NOT_SUPPORTED:
2967 hr = setError(VBOX_E_IPRT_ERROR,
2968 tr("Handling renaming guest directories not supported by installed Guest Additions"));
2969 break;
2970
2971 case VERR_GSTCTL_GUEST_ERROR:
2972 hr = setError(VBOX_E_IPRT_ERROR,
2973 tr("Renaming guest directory failed: %Rrc"), guestRc);
2974 break;
2975
2976 default:
2977 hr = setError(VBOX_E_IPRT_ERROR, tr("Renaming guest directory \"%s\" failed: %Rrc"),
2978 aSource.c_str(), vrc);
2979 break;
2980 }
2981 }
2982
2983 return hr;
2984#endif /* VBOX_WITH_GUEST_CONTROL */
2985}
2986
2987HRESULT GuestSession::directorySetACL(const com::Utf8Str &aPath, const com::Utf8Str &aAcl)
2988{
2989#ifndef VBOX_WITH_GUEST_CONTROL
2990 ReturnComNotImplemented();
2991#else
2992 LogFlowThisFuncEnter();
2993
2994 ReturnComNotImplemented();
2995#endif /* VBOX_WITH_GUEST_CONTROL */
2996}
2997
2998HRESULT GuestSession::environmentScheduleSet(const com::Utf8Str &aName, const com::Utf8Str &aValue)
2999{
3000#ifndef VBOX_WITH_GUEST_CONTROL
3001 ReturnComNotImplemented();
3002#else
3003 LogFlowThisFuncEnter();
3004
3005 HRESULT hrc;
3006 if (RT_LIKELY(aName.isNotEmpty()))
3007 {
3008 if (RT_LIKELY(strchr(aName.c_str(), '=') == NULL))
3009 {
3010 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3011 int vrc = mData.mEnvironmentChanges.setVariable(aName, aValue);
3012 if (RT_SUCCESS(vrc))
3013 hrc = S_OK;
3014 else
3015 hrc = setErrorVrc(vrc);
3016 }
3017 else
3018 hrc = setError(E_INVALIDARG, tr("The equal char is not allowed in environment variable names"));
3019 }
3020 else
3021 hrc = setError(E_INVALIDARG, tr("No variable name specified"));
3022
3023 LogFlowThisFuncLeave();
3024 return hrc;
3025#endif /* VBOX_WITH_GUEST_CONTROL */
3026}
3027
3028HRESULT GuestSession::environmentScheduleUnset(const com::Utf8Str &aName)
3029{
3030#ifndef VBOX_WITH_GUEST_CONTROL
3031 ReturnComNotImplemented();
3032#else
3033 LogFlowThisFuncEnter();
3034 HRESULT hrc;
3035 if (RT_LIKELY(aName.isNotEmpty()))
3036 {
3037 if (RT_LIKELY(strchr(aName.c_str(), '=') == NULL))
3038 {
3039 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3040 int vrc = mData.mEnvironmentChanges.unsetVariable(aName);
3041 if (RT_SUCCESS(vrc))
3042 hrc = S_OK;
3043 else
3044 hrc = setErrorVrc(vrc);
3045 }
3046 else
3047 hrc = setError(E_INVALIDARG, tr("The equal char is not allowed in environment variable names"));
3048 }
3049 else
3050 hrc = setError(E_INVALIDARG, tr("No variable name specified"));
3051
3052 LogFlowThisFuncLeave();
3053 return hrc;
3054#endif /* VBOX_WITH_GUEST_CONTROL */
3055}
3056
3057HRESULT GuestSession::environmentGetBaseVariable(const com::Utf8Str &aName, com::Utf8Str &aValue)
3058{
3059#ifndef VBOX_WITH_GUEST_CONTROL
3060 ReturnComNotImplemented();
3061#else
3062 LogFlowThisFuncEnter();
3063 HRESULT hrc;
3064 if (RT_LIKELY(aName.isNotEmpty()))
3065 {
3066 if (RT_LIKELY(strchr(aName.c_str(), '=') == NULL))
3067 {
3068 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
3069 if (mData.mpBaseEnvironment)
3070 {
3071 int vrc = mData.mpBaseEnvironment->getVariable(aName, &aValue);
3072 if (RT_SUCCESS(vrc))
3073 hrc = S_OK;
3074 else
3075 hrc = setErrorVrc(vrc);
3076 }
3077 else if (mData.mProtocolVersion < 99999)
3078 hrc = setError(VBOX_E_NOT_SUPPORTED, tr("The base environment feature is not supported by the guest additions"));
3079 else
3080 hrc = setError(VBOX_E_INVALID_OBJECT_STATE, tr("The base environment has not yet been reported by the guest"));
3081 }
3082 else
3083 hrc = setError(E_INVALIDARG, tr("The equal char is not allowed in environment variable names"));
3084 }
3085 else
3086 hrc = setError(E_INVALIDARG, tr("No variable name specified"));
3087
3088 LogFlowThisFuncLeave();
3089 return hrc;
3090#endif /* VBOX_WITH_GUEST_CONTROL */
3091}
3092
3093HRESULT GuestSession::environmentDoesBaseVariableExist(const com::Utf8Str &aName, BOOL *aExists)
3094{
3095#ifndef VBOX_WITH_GUEST_CONTROL
3096 ReturnComNotImplemented();
3097#else
3098 LogFlowThisFuncEnter();
3099 *aExists = FALSE;
3100 HRESULT hrc;
3101 if (RT_LIKELY(aName.isNotEmpty()))
3102 {
3103 if (RT_LIKELY(strchr(aName.c_str(), '=') == NULL))
3104 {
3105 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
3106 if (mData.mpBaseEnvironment)
3107 {
3108 hrc = S_OK;
3109 *aExists = mData.mpBaseEnvironment->doesVariableExist(aName);
3110 }
3111 else if (mData.mProtocolVersion < 99999)
3112 hrc = setError(VBOX_E_NOT_SUPPORTED, tr("The base environment feature is not supported by the guest additions"));
3113 else
3114 hrc = setError(VBOX_E_INVALID_OBJECT_STATE, tr("The base environment has not yet been reported by the guest"));
3115 }
3116 else
3117 hrc = setError(E_INVALIDARG, tr("The equal char is not allowed in environment variable names"));
3118 }
3119 else
3120 hrc = setError(E_INVALIDARG, tr("No variable name specified"));
3121
3122 LogFlowThisFuncLeave();
3123 return hrc;
3124#endif /* VBOX_WITH_GUEST_CONTROL */
3125}
3126
3127HRESULT GuestSession::fileCreateTemp(const com::Utf8Str &aTemplateName, ULONG aMode, const com::Utf8Str &aPath, BOOL aSecure,
3128 ComPtr<IGuestFile> &aFile)
3129{
3130#ifndef VBOX_WITH_GUEST_CONTROL
3131 ReturnComNotImplemented();
3132#else
3133 LogFlowThisFuncEnter();
3134
3135
3136 ReturnComNotImplemented();
3137#endif /* VBOX_WITH_GUEST_CONTROL */
3138}
3139
3140HRESULT GuestSession::fileExists(const com::Utf8Str &aPath, BOOL *aExists)
3141{
3142#ifndef VBOX_WITH_GUEST_CONTROL
3143 ReturnComNotImplemented();
3144#else
3145 LogFlowThisFuncEnter();
3146
3147 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3148 return setError(E_INVALIDARG, tr("No file to check existence for specified"));
3149
3150 GuestFsObjData objData; int guestRc;
3151 int vrc = i_fileQueryInfoInternal(aPath, false /*fFollowSymlinks*/, objData, &guestRc);
3152 if (RT_SUCCESS(vrc))
3153 {
3154 *aExists = TRUE;
3155 return S_OK;
3156 }
3157
3158 HRESULT hr = S_OK;
3159
3160 switch (vrc)
3161 {
3162 case VERR_GSTCTL_GUEST_ERROR:
3163 hr = GuestProcess::i_setErrorExternal(this, guestRc);
3164 break;
3165
3166 case VERR_NOT_A_FILE:
3167 *aExists = FALSE;
3168 break;
3169
3170 default:
3171 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information for \"%s\" failed: %Rrc"),
3172 aPath.c_str(), vrc);
3173 break;
3174 }
3175
3176 return hr;
3177#endif /* VBOX_WITH_GUEST_CONTROL */
3178}
3179
3180HRESULT GuestSession::fileRemove(const com::Utf8Str &aPath)
3181{
3182#ifndef VBOX_WITH_GUEST_CONTROL
3183 ReturnComNotImplemented();
3184#else
3185 LogFlowThisFuncEnter();
3186
3187 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3188 return setError(E_INVALIDARG, tr("No file to remove specified"));
3189
3190 HRESULT hr = S_OK;
3191
3192 int guestRc;
3193 int vrc = i_fileRemoveInternal(aPath, &guestRc);
3194 if (RT_FAILURE(vrc))
3195 {
3196 switch (vrc)
3197 {
3198 case VERR_GSTCTL_GUEST_ERROR:
3199 hr = GuestProcess::i_setErrorExternal(this, guestRc);
3200 break;
3201
3202 default:
3203 hr = setError(VBOX_E_IPRT_ERROR, tr("Removing file \"%s\" failed: %Rrc"),
3204 aPath.c_str(), vrc);
3205 break;
3206 }
3207 }
3208
3209 return hr;
3210#endif /* VBOX_WITH_GUEST_CONTROL */
3211}
3212
3213HRESULT GuestSession::fileOpen(const com::Utf8Str &aPath, const com::Utf8Str &aOpenMode, const com::Utf8Str &aDisposition,
3214 ULONG aCreationMode, ComPtr<IGuestFile> &aFile)
3215{
3216#ifndef VBOX_WITH_GUEST_CONTROL
3217 ReturnComNotImplemented();
3218#else
3219 LogFlowThisFuncEnter();
3220
3221 Utf8Str strSharingMode = ""; /* Sharing mode is ignored. */
3222
3223 return fileOpenEx(aPath, aOpenMode, aDisposition, strSharingMode, aCreationMode,
3224 0 /* aOffset */, aFile);
3225#endif /* VBOX_WITH_GUEST_CONTROL */
3226}
3227
3228HRESULT GuestSession::fileOpenEx(const com::Utf8Str &aPath, const com::Utf8Str &aOpenMode, const com::Utf8Str &aDisposition,
3229 const com::Utf8Str &aSharingMode, ULONG aCreationMode, LONG64 aOffset,
3230 ComPtr<IGuestFile> &aFile)
3231
3232{
3233#ifndef VBOX_WITH_GUEST_CONTROL
3234 ReturnComNotImplemented();
3235#else
3236 LogFlowThisFuncEnter();
3237
3238 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3239 return setError(E_INVALIDARG, tr("No file to open specified"));
3240 if (RT_UNLIKELY((aOpenMode.c_str()) == NULL || *(aOpenMode.c_str()) == '\0'))
3241 return setError(E_INVALIDARG, tr("No open mode specified"));
3242 if (RT_UNLIKELY((aDisposition.c_str()) == NULL || *(aDisposition.c_str()) == '\0'))
3243 return setError(E_INVALIDARG, tr("No disposition mode specified"));
3244 /* aSharingMode is optional. */
3245
3246 HRESULT hr = i_isReadyExternal();
3247 if (FAILED(hr))
3248 return hr;
3249
3250 /** @todo Validate creation mode. */
3251 uint32_t uCreationMode = 0;
3252
3253 GuestFileOpenInfo openInfo;
3254 openInfo.mFileName = aPath;
3255 openInfo.mOpenMode = aOpenMode;
3256 openInfo.mDisposition = aDisposition;
3257 openInfo.mSharingMode = aSharingMode;
3258 openInfo.mCreationMode = aCreationMode;
3259 openInfo.mInitialOffset = aOffset;
3260
3261 uint64_t uFlagsIgnored;
3262 int vrc = RTFileModeToFlagsEx(openInfo.mOpenMode.c_str(),
3263 openInfo.mDisposition.c_str(),
3264 openInfo.mSharingMode.c_str(),
3265 &uFlagsIgnored);
3266 if (RT_FAILURE(vrc))
3267 return setError(E_INVALIDARG, tr("Invalid open mode / disposition / sharing mode specified"));
3268
3269 ComObjPtr <GuestFile> pFile; int guestRc;
3270 vrc = i_fileOpenInternal(openInfo, pFile, &guestRc);
3271 if (RT_SUCCESS(vrc))
3272 /* Return directory object to the caller. */
3273 hr = pFile.queryInterfaceTo(aFile.asOutParam());
3274 else
3275 {
3276 switch (vrc)
3277 {
3278 case VERR_NOT_SUPPORTED:
3279 hr = setError(VBOX_E_IPRT_ERROR,
3280 tr("Handling guest files not supported by installed Guest Additions"));
3281 break;
3282
3283 case VERR_GSTCTL_GUEST_ERROR:
3284 hr = GuestFile::i_setErrorExternal(this, guestRc);
3285 break;
3286
3287 default:
3288 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening guest file \"%s\" failed: %Rrc"),
3289 aPath.c_str(), vrc);
3290 break;
3291 }
3292 }
3293
3294 return hr;
3295#endif /* VBOX_WITH_GUEST_CONTROL */
3296}
3297
3298HRESULT GuestSession::fileQueryInfo(const com::Utf8Str &aPath, ComPtr<IGuestFsObjInfo> &aInfo)
3299
3300{
3301#ifndef VBOX_WITH_GUEST_CONTROL
3302 ReturnComNotImplemented();
3303#else
3304 LogFlowThisFuncEnter();
3305
3306 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3307 return setError(E_INVALIDARG, tr("No file to query information for specified"));
3308
3309 HRESULT hr = S_OK;
3310
3311 GuestFsObjData objData; int guestRc;
3312 int vrc = i_fileQueryInfoInternal(aPath, false /*fFollowSymlinks*/, objData, &guestRc);
3313 if (RT_SUCCESS(vrc))
3314 {
3315 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
3316 hr = pFsObjInfo.createObject();
3317 if (FAILED(hr)) return hr;
3318
3319 vrc = pFsObjInfo->init(objData);
3320 if (RT_SUCCESS(vrc))
3321 {
3322 hr = pFsObjInfo.queryInterfaceTo(aInfo.asOutParam());
3323 if (FAILED(hr)) return hr;
3324 }
3325 }
3326
3327 if (RT_FAILURE(vrc))
3328 {
3329 switch (vrc)
3330 {
3331 case VERR_GSTCTL_GUEST_ERROR:
3332 hr = GuestProcess::i_setErrorExternal(this, guestRc);
3333 break;
3334
3335 case VERR_NOT_A_FILE:
3336 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a file"));
3337 break;
3338
3339 default:
3340 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), vrc);
3341 break;
3342 }
3343 }
3344
3345 return hr;
3346#endif /* VBOX_WITH_GUEST_CONTROL */
3347}
3348
3349HRESULT GuestSession::fileQuerySize(const com::Utf8Str &aPath, LONG64 *aSize)
3350{
3351#ifndef VBOX_WITH_GUEST_CONTROL
3352 ReturnComNotImplemented();
3353#else
3354 LogFlowThisFuncEnter();
3355
3356 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3357 return setError(E_INVALIDARG, tr("No file to query size for specified"));
3358
3359 HRESULT hr = S_OK;
3360
3361 int64_t llSize; int guestRc;
3362 int vrc = i_fileQuerySizeInternal(aPath, &llSize, &guestRc);
3363 if (RT_SUCCESS(vrc))
3364 *aSize = llSize;
3365 else
3366 {
3367 switch (vrc)
3368 {
3369 case VERR_GSTCTL_GUEST_ERROR:
3370 hr = GuestProcess::i_setErrorExternal(this, guestRc);
3371 break;
3372
3373 default:
3374 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), vrc);
3375 break;
3376 }
3377 }
3378
3379 return hr;
3380#endif /* VBOX_WITH_GUEST_CONTROL */
3381}
3382
3383HRESULT GuestSession::fileRename(const com::Utf8Str &aSource, const com::Utf8Str &aDest,
3384 const std::vector<PathRenameFlag_T> &aFlags)
3385{
3386#ifndef VBOX_WITH_GUEST_CONTROL
3387 ReturnComNotImplemented();
3388#else
3389 LogFlowThisFuncEnter();
3390
3391 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0'))
3392 return setError(E_INVALIDARG, tr("No source file to rename specified"));
3393
3394 if (RT_UNLIKELY((aDest.c_str()) == NULL || *(aDest.c_str()) == '\0'))
3395 return setError(E_INVALIDARG, tr("No destination file to rename the source to specified"));
3396
3397 HRESULT hr = i_isReadyExternal();
3398 if (FAILED(hr))
3399 return hr;
3400
3401 /* No flags; only remove the directory when empty. */
3402 uint32_t uFlags = 0;
3403
3404 int guestRc;
3405 int vrc = i_pathRenameInternal(aSource, aDest, uFlags, &guestRc);
3406 if (RT_FAILURE(vrc))
3407 {
3408 switch (vrc)
3409 {
3410 case VERR_NOT_SUPPORTED:
3411 hr = setError(VBOX_E_IPRT_ERROR,
3412 tr("Handling renaming guest files not supported by installed Guest Additions"));
3413 break;
3414
3415 case VERR_GSTCTL_GUEST_ERROR:
3416 /** @todo Proper guestRc to text translation needed. */
3417 hr = setError(VBOX_E_IPRT_ERROR,
3418 tr("Renaming guest file failed: %Rrc"), guestRc);
3419 break;
3420
3421 default:
3422 hr = setError(VBOX_E_IPRT_ERROR, tr("Renaming guest file \"%s\" failed: %Rrc"),
3423 aSource.c_str(), vrc);
3424 break;
3425 }
3426 }
3427
3428 return hr;
3429#endif /* VBOX_WITH_GUEST_CONTROL */
3430}
3431
3432HRESULT GuestSession::fileSetACL(const com::Utf8Str &aFile, const com::Utf8Str &aAcl)
3433{
3434#ifndef VBOX_WITH_GUEST_CONTROL
3435 ReturnComNotImplemented();
3436#else
3437 LogFlowThisFuncEnter();
3438
3439 ReturnComNotImplemented();
3440#endif /* VBOX_WITH_GUEST_CONTROL */
3441}
3442
3443HRESULT GuestSession::fsExists(const com::Utf8Str &aPath, BOOL aFollowSymlinks, BOOL *aExists)
3444{
3445#ifndef VBOX_WITH_GUEST_CONTROL
3446 ReturnComNotImplemented();
3447#else
3448 LogFlowThisFuncEnter();
3449
3450 HRESULT hrc = S_OK;
3451 *aExists = false;
3452 if (RT_LIKELY(aPath.isNotEmpty()))
3453 {
3454 GuestFsObjData objData;
3455 int rcGuest;
3456 int vrc = i_fsQueryInfoInternal(aPath, aFollowSymlinks != FALSE, objData, &rcGuest);
3457 if (RT_SUCCESS(vrc))
3458 *aExists = TRUE;
3459 else if ( vrc == VERR_NOT_A_FILE
3460 || vrc == VERR_PATH_NOT_FOUND
3461 || vrc == VERR_FILE_NOT_FOUND
3462 || vrc == VERR_INVALID_NAME)
3463 hrc = S_OK; /* Ignore these vrc values. */
3464 else if (vrc == VERR_GSTCTL_GUEST_ERROR) /** @todo What _is_ rcGuest, really? Stuff like VERR_NOT_A_FILE too?? */
3465 hrc = GuestProcess::i_setErrorExternal(this, rcGuest);
3466 else
3467 hrc = setErrorVrc(vrc, tr("Querying file information for \"%s\" failed: %Rrc"), aPath.c_str(), vrc);
3468 }
3469 /* else: If the file name is empty, there is no way it can exists. So, don't
3470 be a tedious and return E_INVALIDARG, simply return FALSE. */
3471 LogFlowThisFuncLeave();
3472 return hrc;
3473#endif /* VBOX_WITH_GUEST_CONTROL */
3474}
3475
3476HRESULT GuestSession::fsQueryInfo(const com::Utf8Str &aPath, BOOL aFollowSymlinks, ComPtr<IGuestFsObjInfo> &aInfo)
3477{
3478#ifndef VBOX_WITH_GUEST_CONTROL
3479 ReturnComNotImplemented();
3480#else
3481 LogFlowThisFuncEnter();
3482
3483 HRESULT hrc = S_OK;
3484 if (RT_LIKELY(aPath.isNotEmpty()))
3485 {
3486 GuestFsObjData Info;
3487 int rcGuest;
3488 int vrc = i_fsQueryInfoInternal(aPath, aFollowSymlinks != FALSE, Info, &rcGuest);
3489 if (RT_SUCCESS(vrc))
3490 {
3491 ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
3492 hrc = ptrFsObjInfo.createObject();
3493 if (SUCCEEDED(hrc))
3494 {
3495 vrc = ptrFsObjInfo->init(Info);
3496 if (RT_SUCCESS(vrc))
3497 hrc = ptrFsObjInfo.queryInterfaceTo(aInfo.asOutParam());
3498 else
3499 hrc = setErrorVrc(vrc);
3500 }
3501 }
3502 else if (vrc == VERR_GSTCTL_GUEST_ERROR)
3503 hrc = GuestProcess::i_setErrorExternal(this, rcGuest);
3504 else
3505 hrc = setErrorVrc(vrc, tr("Querying file information for \"%s\" failed: %Rrc"), aPath.c_str(), vrc);
3506 }
3507 /* else: If the file name is empty, there is no way it can exists. So, don't
3508 be a tedious and return E_INVALIDARG, simply return FALSE. */
3509 LogFlowThisFuncLeave();
3510 return hrc;
3511#endif /* VBOX_WITH_GUEST_CONTROL */
3512}
3513
3514HRESULT GuestSession::processCreate(const com::Utf8Str &aExecutable, const std::vector<com::Utf8Str> &aArguments,
3515 const std::vector<com::Utf8Str> &aEnvironment,
3516 const std::vector<ProcessCreateFlag_T> &aFlags,
3517 ULONG aTimeoutMS, ComPtr<IGuestProcess> &aGuestProcess)
3518{
3519#ifndef VBOX_WITH_GUEST_CONTROL
3520 ReturnComNotImplemented();
3521#else
3522 LogFlowThisFuncEnter();
3523
3524 std::vector<LONG> affinityIgnored;
3525
3526 return processCreateEx(aExecutable, aArguments, aEnvironment, aFlags, aTimeoutMS, ProcessPriority_Default,
3527 affinityIgnored, aGuestProcess);
3528#endif /* VBOX_WITH_GUEST_CONTROL */
3529}
3530
3531HRESULT GuestSession::processCreateEx(const com::Utf8Str &aExecutable, const std::vector<com::Utf8Str> &aArguments,
3532 const std::vector<com::Utf8Str> &aEnvironment,
3533 const std::vector<ProcessCreateFlag_T> &aFlags, ULONG aTimeoutMS,
3534 ProcessPriority_T aPriority, const std::vector<LONG> &aAffinity,
3535 ComPtr<IGuestProcess> &aGuestProcess)
3536{
3537#ifndef VBOX_WITH_GUEST_CONTROL
3538 ReturnComNotImplemented();
3539#else
3540 LogFlowThisFuncEnter();
3541
3542 /** @todo r=bird: Check input better? aPriority is passed on to the guest
3543 * without any validation. Flags not existing in this vbox version are
3544 * ignored, potentially doing something entirely different than what the
3545 * caller had in mind. */
3546
3547 /*
3548 * Must have an executable to execute. If none is given, we try use the
3549 * zero'th argument.
3550 */
3551 const char *pszExecutable = aExecutable.c_str();
3552 if (RT_UNLIKELY(pszExecutable == NULL || *pszExecutable == '\0'))
3553 {
3554 if (aArguments.size() > 0)
3555 pszExecutable = aArguments[0].c_str();
3556 if (pszExecutable == NULL || *pszExecutable == '\0')
3557 return setError(E_INVALIDARG, tr("No command to execute specified"));
3558 }
3559
3560 /*
3561 * Check the session.
3562 */
3563 HRESULT hr = i_isReadyExternal();
3564 if (FAILED(hr))
3565 return hr;
3566
3567 /*
3568 * Build the process startup info.
3569 */
3570 GuestProcessStartupInfo procInfo;
3571
3572 /* Executable and arguments. */
3573 procInfo.mExecutable = pszExecutable;
3574 if (aArguments.size())
3575 for (size_t i = 0; i < aArguments.size(); i++)
3576 procInfo.mArguments.push_back(aArguments[i]);
3577
3578 /* Combine the environment changes associated with the ones passed in by
3579 the caller, giving priority to the latter. The changes are putenv style
3580 and will be applied to the standard environment for the guest user. */
3581 int vrc = procInfo.mEnvironmentChanges.copy(mData.mEnvironmentChanges);
3582 if (RT_SUCCESS(vrc))
3583 vrc = procInfo.mEnvironmentChanges.applyPutEnvArray(aEnvironment);
3584 if (RT_SUCCESS(vrc))
3585 {
3586 /* Convert the flag array into a mask. */
3587 if (aFlags.size())
3588 for (size_t i = 0; i < aFlags.size(); i++)
3589 procInfo.mFlags |= aFlags[i];
3590
3591 procInfo.mTimeoutMS = aTimeoutMS;
3592
3593 /** @todo use RTCPUSET instead of archaic 64-bit variables! */
3594 if (aAffinity.size())
3595 for (size_t i = 0; i < aAffinity.size(); i++)
3596 if (aAffinity[i])
3597 procInfo.mAffinity |= (uint64_t)1 << i;
3598
3599 procInfo.mPriority = aPriority;
3600
3601 /*
3602 * Create a guest process object.
3603 */
3604 ComObjPtr<GuestProcess> pProcess;
3605 vrc = i_processCreateExInternal(procInfo, pProcess);
3606 if (RT_SUCCESS(vrc))
3607 {
3608 /* Return guest session to the caller. */
3609 hr = pProcess.queryInterfaceTo(aGuestProcess.asOutParam());
3610 if (SUCCEEDED(hr))
3611 {
3612 /*
3613 * Start the process.
3614 */
3615 vrc = pProcess->i_startProcessAsync();
3616 if (RT_SUCCESS(vrc))
3617 {
3618 LogFlowFuncLeaveRC(vrc);
3619 return S_OK;
3620 }
3621
3622 hr = setErrorVrc(vrc, tr("Failed to start guest process: %Rrc"), vrc);
3623 /** @todo r=bird: What happens to the interface that *aGuestProcess points to
3624 * now? Looks like a leak or an undocument hack of sorts... */
3625 }
3626 }
3627 else if (vrc == VERR_MAX_PROCS_REACHED)
3628 hr = setErrorVrc(vrc, tr("Maximum number of concurrent guest processes per session (%u) reached"),
3629 VBOX_GUESTCTRL_MAX_OBJECTS);
3630 else
3631 hr = setErrorVrc(vrc, tr("Failed to create guest process object: %Rrc"), vrc);
3632 }
3633 else
3634 hr = setErrorVrc(vrc, tr("Failed to set up the environment: %Rrc"), vrc);
3635
3636 LogFlowFuncLeaveRC(vrc);
3637 return hr;
3638#endif /* VBOX_WITH_GUEST_CONTROL */
3639}
3640
3641HRESULT GuestSession::processGet(ULONG aPid, ComPtr<IGuestProcess> &aGuestProcess)
3642
3643{
3644#ifndef VBOX_WITH_GUEST_CONTROL
3645 ReturnComNotImplemented();
3646#else
3647 LogFlowThisFunc(("PID=%RU32\n", aPid));
3648
3649 if (aPid == 0)
3650 return setError(E_INVALIDARG, tr("No valid process ID (PID) specified"));
3651
3652 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
3653
3654 HRESULT hr = S_OK;
3655
3656 ComObjPtr<GuestProcess> pProcess;
3657 int rc = i_processGetByPID(aPid, &pProcess);
3658 if (RT_FAILURE(rc))
3659 hr = setError(E_INVALIDARG, tr("No process with PID %RU32 found"), aPid);
3660
3661 /* This will set (*aProcess) to NULL if pProgress is NULL. */
3662 HRESULT hr2 = pProcess.queryInterfaceTo(aGuestProcess.asOutParam());
3663 if (SUCCEEDED(hr))
3664 hr = hr2;
3665
3666 LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", (IGuestProcess*)aGuestProcess, hr));
3667 return hr;
3668#endif /* VBOX_WITH_GUEST_CONTROL */
3669}
3670
3671HRESULT GuestSession::symlinkCreate(const com::Utf8Str &aSource, const com::Utf8Str &aTarget, SymlinkType_T aType)
3672{
3673#ifndef VBOX_WITH_GUEST_CONTROL
3674 ReturnComNotImplemented();
3675#else
3676 LogFlowThisFuncEnter();
3677
3678 ReturnComNotImplemented();
3679#endif /* VBOX_WITH_GUEST_CONTROL */
3680}
3681
3682HRESULT GuestSession::symlinkExists(const com::Utf8Str &aSymlink, BOOL *aExists)
3683
3684{
3685#ifndef VBOX_WITH_GUEST_CONTROL
3686 ReturnComNotImplemented();
3687#else
3688 LogFlowThisFuncEnter();
3689
3690 ReturnComNotImplemented();
3691#endif /* VBOX_WITH_GUEST_CONTROL */
3692}
3693
3694HRESULT GuestSession::symlinkRead(const com::Utf8Str &aSymlink, const std::vector<SymlinkReadFlag_T> &aFlags,
3695 com::Utf8Str &aTarget)
3696{
3697#ifndef VBOX_WITH_GUEST_CONTROL
3698 ReturnComNotImplemented();
3699#else
3700 LogFlowThisFuncEnter();
3701
3702 ReturnComNotImplemented();
3703#endif /* VBOX_WITH_GUEST_CONTROL */
3704}
3705
3706HRESULT GuestSession::symlinkRemoveDirectory(const com::Utf8Str &aPath)
3707{
3708#ifndef VBOX_WITH_GUEST_CONTROL
3709 ReturnComNotImplemented();
3710#else
3711 LogFlowThisFuncEnter();
3712
3713 ReturnComNotImplemented();
3714#endif /* VBOX_WITH_GUEST_CONTROL */
3715}
3716
3717HRESULT GuestSession::symlinkRemoveFile(const com::Utf8Str &aFile)
3718{
3719#ifndef VBOX_WITH_GUEST_CONTROL
3720 ReturnComNotImplemented();
3721#else
3722 LogFlowThisFuncEnter();
3723
3724 ReturnComNotImplemented();
3725#endif /* VBOX_WITH_GUEST_CONTROL */
3726}
3727
3728HRESULT GuestSession::waitFor(ULONG aWaitFor, ULONG aTimeoutMS, GuestSessionWaitResult_T *aReason)
3729{
3730#ifndef VBOX_WITH_GUEST_CONTROL
3731 ReturnComNotImplemented();
3732#else
3733 LogFlowThisFuncEnter();
3734
3735 /*
3736 * Note: Do not hold any locks here while waiting!
3737 */
3738 HRESULT hr = S_OK;
3739
3740 int guestRc; GuestSessionWaitResult_T waitResult;
3741 int vrc = i_waitFor(aWaitFor, aTimeoutMS, waitResult, &guestRc);
3742 if (RT_SUCCESS(vrc))
3743 *aReason = waitResult;
3744 else
3745 {
3746 switch (vrc)
3747 {
3748 case VERR_GSTCTL_GUEST_ERROR:
3749 hr = GuestSession::i_setErrorExternal(this, guestRc);
3750 break;
3751
3752 case VERR_TIMEOUT:
3753 *aReason = GuestSessionWaitResult_Timeout;
3754 break;
3755
3756 default:
3757 {
3758 const char *pszSessionName = mData.mSession.mName.c_str();
3759 hr = setError(VBOX_E_IPRT_ERROR,
3760 tr("Waiting for guest session \"%s\" failed: %Rrc"),
3761 pszSessionName ? pszSessionName : tr("Unnamed"), vrc);
3762 break;
3763 }
3764 }
3765 }
3766
3767 LogFlowFuncLeaveRC(vrc);
3768 return hr;
3769#endif /* VBOX_WITH_GUEST_CONTROL */
3770}
3771
3772HRESULT GuestSession::waitForArray(const std::vector<GuestSessionWaitForFlag_T> &aWaitFor, ULONG aTimeoutMS,
3773 GuestSessionWaitResult_T *aReason)
3774{
3775#ifndef VBOX_WITH_GUEST_CONTROL
3776 ReturnComNotImplemented();
3777#else
3778 LogFlowThisFuncEnter();
3779
3780 /*
3781 * Note: Do not hold any locks here while waiting!
3782 */
3783 uint32_t fWaitFor = GuestSessionWaitForFlag_None;
3784 for (size_t i = 0; i < aWaitFor.size(); i++)
3785 fWaitFor |= aWaitFor[i];
3786
3787 return WaitFor(fWaitFor, aTimeoutMS, aReason);
3788#endif /* VBOX_WITH_GUEST_CONTROL */
3789}
3790
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