VirtualBox

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

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

6813 - DisplayImpl using COM Wrappers

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