VirtualBox

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

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

Main/GuestCtrl: Try to fix testsuite session file reference tests.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 105.0 KB
Line 
1/* $Id: GuestSessionImpl.cpp 50771 2014-03-13 15:12:44Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Guest session handling.
4 */
5
6/*
7 * Copyright (C) 2012-2013 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->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->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->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->getConsole();
2006 Assert(!pConsole.isNull());
2007
2008 /* Forward the information to the VMM device. */
2009 VMMDev *pVMMDev = pConsole->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->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->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, const std::vector<CopyFileFlag_T> &aFlags, ComPtr<IProgress> &aProgress)
2416{
2417#ifndef VBOX_WITH_GUEST_CONTROL
2418 ReturnComNotImplemented();
2419#else
2420
2421 LogFlowThisFuncEnter();
2422
2423 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0'))
2424 return setError(E_INVALIDARG, tr("No source specified"));
2425 if (RT_UNLIKELY((aDest.c_str()) == NULL || *(aDest.c_str()) == '\0'))
2426 return setError(E_INVALIDARG, tr("No destination specified"));
2427
2428 uint32_t fFlags = CopyFileFlag_None;
2429 if (aFlags.size())
2430 {
2431 for (size_t i = 0; i < aFlags.size(); i++)
2432 fFlags |= aFlags[i];
2433 }
2434
2435 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2436
2437 HRESULT hr = S_OK;
2438
2439 try
2440 {
2441 ComObjPtr<Progress> pProgress;
2442 SessionTaskCopyFrom *pTask = new SessionTaskCopyFrom(this /* GuestSession */,
2443 aSource, aDest, fFlags);
2444 int rc = i_startTaskAsync(Utf8StrFmt(tr("Copying \"%s\" from guest to \"%s\" on the host"), aSource.c_str(), aDest.c_str()),
2445 pTask, pProgress);
2446 if (RT_SUCCESS(rc))
2447 /* Return progress to the caller. */
2448 hr = pProgress.queryInterfaceTo(aProgress.asOutParam());
2449 else
2450 hr = setError(VBOX_E_IPRT_ERROR,
2451 tr("Starting task for copying file \"%s\" from guest to \"%s\" on the host failed: %Rrc"), rc);
2452 }
2453 catch(std::bad_alloc &)
2454 {
2455 hr = E_OUTOFMEMORY;
2456 }
2457
2458 return hr;
2459#endif /* VBOX_WITH_GUEST_CONTROL */
2460}
2461
2462HRESULT GuestSession::copyTo(const com::Utf8Str &aSource, const com::Utf8Str &aDest, const std::vector<CopyFileFlag_T> &aFlags, ComPtr<IProgress> &aProgress)
2463{
2464#ifndef VBOX_WITH_GUEST_CONTROL
2465 ReturnComNotImplemented();
2466#else
2467
2468 LogFlowThisFuncEnter();
2469
2470 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0'))
2471 return setError(E_INVALIDARG, tr("No source specified"));
2472 if (RT_UNLIKELY((aDest.c_str()) == NULL || *(aDest.c_str()) == '\0'))
2473 return setError(E_INVALIDARG, tr("No destination specified"));
2474
2475 uint32_t fFlags = CopyFileFlag_None;
2476 if (aFlags.size())
2477 {
2478 for (size_t i = 0; i < aFlags.size(); i++)
2479 fFlags |= aFlags[i];
2480 }
2481
2482 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2483
2484 HRESULT hr = S_OK;
2485
2486 try
2487 {
2488 ComObjPtr<Progress> pProgress;
2489 SessionTaskCopyTo *pTask = new SessionTaskCopyTo(this /* GuestSession */,
2490 aSource, aDest, fFlags);
2491 AssertPtrReturn(pTask, E_OUTOFMEMORY);
2492 int rc = i_startTaskAsync(Utf8StrFmt(tr("Copying \"%s\" from host to \"%s\" on the guest"), aSource.c_str(), aDest.c_str()),
2493 pTask, pProgress);
2494 if (RT_SUCCESS(rc))
2495 {
2496 /* Return progress to the caller. */
2497 hr = pProgress.queryInterfaceTo(aProgress.asOutParam());
2498 }
2499 else
2500 hr = setError(VBOX_E_IPRT_ERROR,
2501 tr("Starting task for copying file \"%s\" from host to \"%s\" on the guest failed: %Rrc"), rc);
2502 }
2503 catch(std::bad_alloc &)
2504 {
2505 hr = E_OUTOFMEMORY;
2506 }
2507
2508 return hr;
2509#endif /* VBOX_WITH_GUEST_CONTROL */
2510}
2511
2512HRESULT GuestSession::directoryCreate(const com::Utf8Str &aPath, ULONG aMode,
2513 const std::vector<DirectoryCreateFlag_T> &aFlags)
2514{
2515#ifndef VBOX_WITH_GUEST_CONTROL
2516 ReturnComNotImplemented();
2517#else
2518 LogFlowThisFuncEnter();
2519
2520 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2521 return setError(E_INVALIDARG, tr("No directory to create specified"));
2522
2523 uint32_t fFlags = DirectoryCreateFlag_None;
2524 if (aFlags.size())
2525 {
2526 for (size_t i = 0; i < aFlags.size(); i++)
2527 fFlags |= aFlags[i];
2528
2529 if (fFlags)
2530 if (!(fFlags & DirectoryCreateFlag_Parents))
2531 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), fFlags);
2532 }
2533
2534 HRESULT hr = S_OK;
2535
2536 ComObjPtr <GuestDirectory> pDirectory; int guestRc;
2537 int rc = i_directoryCreateInternal(aPath, (uint32_t)aMode, fFlags, &guestRc);
2538 if (RT_FAILURE(rc))
2539 {
2540 switch (rc)
2541 {
2542 case VERR_GSTCTL_GUEST_ERROR:
2543 /** @todo Handle VERR_NOT_EQUAL (meaning process exit code <> 0). */
2544 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Could not create directory"));
2545 break;
2546
2547 case VERR_INVALID_PARAMETER:
2548 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Invalid parameters given"));
2549 break;
2550
2551 case VERR_BROKEN_PIPE:
2552 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Unexpectedly aborted"));
2553 break;
2554
2555 default:
2556 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
2557 break;
2558 }
2559 }
2560
2561 return hr;
2562#endif /* VBOX_WITH_GUEST_CONTROL */
2563}
2564
2565HRESULT GuestSession::directoryCreateTemp(const com::Utf8Str &aTemplateName, ULONG aMode, const com::Utf8Str &aPath, BOOL aSecure, com::Utf8Str &aDirectory)
2566{
2567#ifndef VBOX_WITH_GUEST_CONTROL
2568 ReturnComNotImplemented();
2569#else
2570 LogFlowThisFuncEnter();
2571
2572 if (RT_UNLIKELY((aTemplateName.c_str()) == NULL || *(aTemplateName.c_str()) == '\0'))
2573 return setError(E_INVALIDARG, tr("No template specified"));
2574 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2575 return setError(E_INVALIDARG, tr("No directory name specified"));
2576
2577 HRESULT hr = S_OK;
2578
2579 int guestRc;
2580 int rc = i_objectCreateTempInternal(aTemplateName,
2581 aPath,
2582 true /* Directory */, aDirectory, &guestRc);
2583 if (!RT_SUCCESS(rc))
2584 {
2585 switch (rc)
2586 {
2587 case VERR_GSTCTL_GUEST_ERROR:
2588 hr = GuestProcess::i_setErrorExternal(this, guestRc);
2589 break;
2590
2591 default:
2592 hr = setError(VBOX_E_IPRT_ERROR, tr("Temporary directory creation \"%s\" with template \"%s\" failed: %Rrc"),
2593 aPath.c_str(), aTemplateName.c_str(), rc);
2594 break;
2595 }
2596 }
2597
2598 return hr;
2599#endif /* VBOX_WITH_GUEST_CONTROL */
2600}
2601
2602HRESULT GuestSession::directoryExists(const com::Utf8Str &aPath, BOOL *aExists)
2603{
2604#ifndef VBOX_WITH_GUEST_CONTROL
2605 ReturnComNotImplemented();
2606#else
2607 LogFlowThisFuncEnter();
2608
2609 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2610 return setError(E_INVALIDARG, tr("No directory to check existence for specified"));
2611
2612 HRESULT hr = S_OK;
2613
2614 GuestFsObjData objData; int guestRc;
2615 int rc = i_directoryQueryInfoInternal(aPath, objData, &guestRc);
2616 if (RT_SUCCESS(rc))
2617 *aExists = objData.mType == FsObjType_Directory;
2618 else
2619 {
2620 switch (rc)
2621 {
2622 case VERR_GSTCTL_GUEST_ERROR:
2623 hr = GuestProcess::i_setErrorExternal(this, guestRc);
2624 break;
2625
2626 default:
2627 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence \"%s\" failed: %Rrc"),
2628 aPath.c_str(), rc);
2629 break;
2630 }
2631 }
2632
2633 return hr;
2634#endif /* VBOX_WITH_GUEST_CONTROL */
2635}
2636
2637HRESULT GuestSession::directoryOpen(const com::Utf8Str &aPath, const com::Utf8Str &aFilter, const std::vector<DirectoryOpenFlag_T> &aFlags, ComPtr<IGuestDirectory> &aDirectory)
2638{
2639#ifndef VBOX_WITH_GUEST_CONTROL
2640 ReturnComNotImplemented();
2641#else
2642 LogFlowThisFuncEnter();
2643
2644 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2645 return setError(E_INVALIDARG, tr("No directory to open specified"));
2646 if (RT_UNLIKELY((aFilter.c_str()) != NULL && *(aFilter.c_str()) != '\0'))
2647 return setError(E_INVALIDARG, tr("Directory filters are not implemented yet"));
2648
2649 uint32_t fFlags = DirectoryOpenFlag_None;
2650 if (aFlags.size())
2651 {
2652 for (size_t i = 0; i < aFlags.size(); i++)
2653 fFlags |= aFlags[i];
2654
2655 if (fFlags)
2656 return setError(E_INVALIDARG, tr("Open flags (%#x) not implemented yet"), fFlags);
2657 }
2658
2659 HRESULT hr = S_OK;
2660
2661 GuestDirectoryOpenInfo openInfo;
2662 openInfo.mPath = aPath;
2663 openInfo.mFilter = aFilter;
2664 openInfo.mFlags = fFlags;
2665
2666 ComObjPtr <GuestDirectory> pDirectory; int guestRc;
2667 int rc = i_directoryOpenInternal(openInfo, pDirectory, &guestRc);
2668 if (RT_SUCCESS(rc))
2669 {
2670 /* Return directory object to the caller. */
2671 hr = pDirectory.queryInterfaceTo(aDirectory.asOutParam());
2672 }
2673 else
2674 {
2675 switch (rc)
2676 {
2677 case VERR_INVALID_PARAMETER:
2678 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed; invalid parameters given",
2679 aPath.c_str()));
2680 break;
2681
2682 case VERR_GSTCTL_GUEST_ERROR:
2683 hr = GuestDirectory::i_setErrorExternal(this, guestRc);
2684 break;
2685
2686 default:
2687 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed: %Rrc"),
2688 aPath.c_str(),rc);
2689 break;
2690 }
2691 }
2692
2693 return hr;
2694#endif /* VBOX_WITH_GUEST_CONTROL */
2695}
2696
2697HRESULT GuestSession::directoryQueryInfo(const com::Utf8Str &aPath, ComPtr<IGuestFsObjInfo> &aInfo)
2698{
2699#ifndef VBOX_WITH_GUEST_CONTROL
2700 ReturnComNotImplemented();
2701#else
2702 LogFlowThisFuncEnter();
2703
2704 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2705 return setError(E_INVALIDARG, tr("No directory to query information for specified"));
2706
2707 HRESULT hr = S_OK;
2708
2709 GuestFsObjData objData; int guestRc;
2710 int vrc = i_directoryQueryInfoInternal(aPath, objData, &guestRc);
2711 if (RT_SUCCESS(vrc))
2712 {
2713 if (objData.mType == FsObjType_Directory)
2714 {
2715 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
2716 hr = pFsObjInfo.createObject();
2717 if (FAILED(hr)) return hr;
2718
2719 vrc = pFsObjInfo->init(objData);
2720 if (RT_SUCCESS(vrc))
2721 {
2722 hr = pFsObjInfo.queryInterfaceTo(aInfo.asOutParam());
2723 if (FAILED(hr)) return hr;
2724 }
2725 }
2726 }
2727
2728 if (RT_FAILURE(vrc))
2729 {
2730 switch (vrc)
2731 {
2732 case VERR_GSTCTL_GUEST_ERROR:
2733 hr = GuestProcess::i_setErrorExternal(this, guestRc);
2734 break;
2735
2736 case VERR_NOT_A_DIRECTORY:
2737 hr = setError(VBOX_E_IPRT_ERROR, tr("Element \"%s\" exists but is not a directory",
2738 aPath.c_str()));
2739 break;
2740
2741 default:
2742 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information for \"%s\" failed: %Rrc"),
2743 aPath.c_str(), vrc);
2744 break;
2745 }
2746 }
2747
2748 return hr;
2749#endif /* VBOX_WITH_GUEST_CONTROL */
2750}
2751
2752HRESULT GuestSession::directoryRemove(const com::Utf8Str &aPath)
2753{
2754#ifndef VBOX_WITH_GUEST_CONTROL
2755 ReturnComNotImplemented();
2756#else
2757 LogFlowThisFuncEnter();
2758
2759 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2760 return setError(E_INVALIDARG, tr("No directory to remove specified"));
2761
2762 HRESULT hr = i_isReadyExternal();
2763 if (FAILED(hr))
2764 return hr;
2765
2766 /* No flags; only remove the directory when empty. */
2767 uint32_t uFlags = 0;
2768
2769 int guestRc;
2770 int vrc = i_directoryRemoveInternal(aPath, uFlags, &guestRc);
2771 if (RT_FAILURE(vrc))
2772 {
2773 switch (vrc)
2774 {
2775 case VERR_NOT_SUPPORTED:
2776 hr = setError(VBOX_E_IPRT_ERROR,
2777 tr("Handling removing guest directories not supported by installed Guest Additions"));
2778 break;
2779
2780 case VERR_GSTCTL_GUEST_ERROR:
2781 hr = GuestDirectory::i_setErrorExternal(this, guestRc);
2782 break;
2783
2784 default:
2785 hr = setError(VBOX_E_IPRT_ERROR, tr("Removing guest directory \"%s\" failed: %Rrc"),
2786 aPath.c_str(), vrc);
2787 break;
2788 }
2789 }
2790
2791 return hr;
2792#endif /* VBOX_WITH_GUEST_CONTROL */
2793}
2794
2795HRESULT GuestSession::directoryRemoveRecursive(const com::Utf8Str &aPath, const std::vector<DirectoryRemoveRecFlag_T> &aFlags, ComPtr<IProgress> &aProgress)
2796{
2797#ifndef VBOX_WITH_GUEST_CONTROL
2798 ReturnComNotImplemented();
2799#else
2800 LogFlowThisFuncEnter();
2801
2802 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2803 return setError(E_INVALIDARG, tr("No directory to remove recursively specified"));
2804
2805 HRESULT hr = i_isReadyExternal();
2806 if (FAILED(hr))
2807 return hr;
2808
2809 ComObjPtr<Progress> pProgress;
2810 hr = pProgress.createObject();
2811 if (SUCCEEDED(hr))
2812 hr = pProgress->init(static_cast<IGuestSession *>(this),
2813 Bstr(tr("Removing guest directory")).raw(),
2814 TRUE /*aCancelable*/);
2815 if (FAILED(hr))
2816 return hr;
2817
2818 /* Note: At the moment we don't supply progress information while
2819 * deleting a guest directory recursively. So just complete
2820 * the progress object right now. */
2821 /** @todo Implement progress reporting on guest directory deletion! */
2822 hr = pProgress->notifyComplete(S_OK);
2823 if (FAILED(hr))
2824 return hr;
2825
2826 /* Remove the directory + all its contents. */
2827 uint32_t uFlags = DIRREMOVE_FLAG_RECURSIVE
2828 | DIRREMOVE_FLAG_CONTENT_AND_DIR;
2829 int guestRc;
2830 int vrc = i_directoryRemoveInternal(aPath, uFlags, &guestRc);
2831 if (RT_FAILURE(vrc))
2832 {
2833 switch (vrc)
2834 {
2835 case VERR_NOT_SUPPORTED:
2836 hr = setError(VBOX_E_IPRT_ERROR,
2837 tr("Handling removing guest directories recursively not supported by installed Guest Additions"));
2838 break;
2839
2840 case VERR_GSTCTL_GUEST_ERROR:
2841 hr = GuestFile::i_setErrorExternal(this, guestRc);
2842 break;
2843
2844 default:
2845 hr = setError(VBOX_E_IPRT_ERROR, tr("Recursively removing guest directory \"%s\" failed: %Rrc"),
2846 aPath.c_str(), vrc);
2847 break;
2848 }
2849 }
2850 else
2851 {
2852 pProgress.queryInterfaceTo(aProgress.asOutParam());
2853 }
2854
2855 return hr;
2856#endif /* VBOX_WITH_GUEST_CONTROL */
2857}
2858
2859HRESULT GuestSession::directoryRename(const com::Utf8Str &aSource,
2860 const com::Utf8Str &aDest,
2861 const std::vector<PathRenameFlag_T> &aFlags)
2862{
2863#ifndef VBOX_WITH_GUEST_CONTROL
2864 ReturnComNotImplemented();
2865#else
2866 LogFlowThisFuncEnter();
2867
2868 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0'))
2869 return setError(E_INVALIDARG, tr("No source directory to rename specified"));
2870
2871 if (RT_UNLIKELY((aDest.c_str()) == NULL || *(aDest.c_str()) == '\0'))
2872 return setError(E_INVALIDARG, tr("No destination directory to rename the source to specified"));
2873
2874 HRESULT hr = i_isReadyExternal();
2875 if (FAILED(hr))
2876 return hr;
2877
2878 /* No flags; only remove the directory when empty. */
2879 uint32_t uFlags = 0;
2880
2881 int guestRc;
2882 int vrc = i_pathRenameInternal(aSource, aDest, uFlags, &guestRc);
2883 if (RT_FAILURE(vrc))
2884 {
2885 switch (vrc)
2886 {
2887 case VERR_NOT_SUPPORTED:
2888 hr = setError(VBOX_E_IPRT_ERROR,
2889 tr("Handling renaming guest directories not supported by installed Guest Additions"));
2890 break;
2891
2892 case VERR_GSTCTL_GUEST_ERROR:
2893 hr = setError(VBOX_E_IPRT_ERROR,
2894 tr("Renaming guest directory failed: %Rrc"), guestRc);
2895 break;
2896
2897 default:
2898 hr = setError(VBOX_E_IPRT_ERROR, tr("Renaming guest directory \"%s\" failed: %Rrc"),
2899 aSource.c_str(), vrc);
2900 break;
2901 }
2902 }
2903
2904 return hr;
2905#endif /* VBOX_WITH_GUEST_CONTROL */
2906}
2907
2908HRESULT GuestSession::directorySetACL(const com::Utf8Str &aPath, const com::Utf8Str &aAcl)
2909{
2910#ifndef VBOX_WITH_GUEST_CONTROL
2911 ReturnComNotImplemented();
2912#else
2913 LogFlowThisFuncEnter();
2914
2915 ReturnComNotImplemented();
2916#endif /* VBOX_WITH_GUEST_CONTROL */
2917}
2918
2919HRESULT GuestSession::environmentClear()
2920{
2921#ifndef VBOX_WITH_GUEST_CONTROL
2922 ReturnComNotImplemented();
2923#else
2924 LogFlowThisFuncEnter();
2925
2926 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2927
2928 mData.mEnvironment.Clear();
2929
2930 LogFlowThisFuncLeave();
2931 return S_OK;
2932#endif /* VBOX_WITH_GUEST_CONTROL */
2933}
2934
2935HRESULT GuestSession::environmentGet(const com::Utf8Str &aName, com::Utf8Str &aValue)
2936{
2937#ifndef VBOX_WITH_GUEST_CONTROL
2938 ReturnComNotImplemented();
2939#else
2940 LogFlowThisFuncEnter();
2941
2942 if (RT_UNLIKELY(aName.c_str() == NULL) || *(aName.c_str()) == '\0')
2943 return setError(E_INVALIDARG, tr("No value name specified"));
2944
2945 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2946
2947 aValue = mData.mEnvironment.Get(aName);
2948
2949 LogFlowThisFuncLeave();
2950 return S_OK;
2951#endif /* VBOX_WITH_GUEST_CONTROL */
2952}
2953
2954HRESULT GuestSession::environmentSet(const com::Utf8Str &aName, const com::Utf8Str &aValue)
2955{
2956#ifndef VBOX_WITH_GUEST_CONTROL
2957 ReturnComNotImplemented();
2958#else
2959 LogFlowThisFuncEnter();
2960
2961 if (RT_UNLIKELY((aName.c_str() == NULL) || *(aName.c_str()) == '\0'))
2962 return setError(E_INVALIDARG, tr("No value name specified"));
2963
2964 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2965
2966 int rc = mData.mEnvironment.Set(aName, aValue);
2967
2968 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
2969 LogFlowFuncLeaveRC(hr);
2970 return hr;
2971#endif /* VBOX_WITH_GUEST_CONTROL */
2972}
2973
2974HRESULT GuestSession::environmentUnset(const com::Utf8Str &aName)
2975{
2976#ifndef VBOX_WITH_GUEST_CONTROL
2977 ReturnComNotImplemented();
2978#else
2979 LogFlowThisFuncEnter();
2980
2981 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2982
2983 mData.mEnvironment.Unset(aName);
2984
2985 LogFlowThisFuncLeave();
2986 return S_OK;
2987#endif /* VBOX_WITH_GUEST_CONTROL */
2988}
2989
2990HRESULT GuestSession::fileCreateTemp(const com::Utf8Str &aTemplateName, ULONG aMode, const com::Utf8Str &aPath, BOOL aSecure, ComPtr<IGuestFile> &aFile)
2991{
2992#ifndef VBOX_WITH_GUEST_CONTROL
2993 ReturnComNotImplemented();
2994#else
2995 LogFlowThisFuncEnter();
2996
2997
2998 ReturnComNotImplemented();
2999#endif /* VBOX_WITH_GUEST_CONTROL */
3000}
3001
3002HRESULT GuestSession::fileExists(const com::Utf8Str &aPath, BOOL *aExists)
3003{
3004#ifndef VBOX_WITH_GUEST_CONTROL
3005 ReturnComNotImplemented();
3006#else
3007 LogFlowThisFuncEnter();
3008
3009 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3010 return setError(E_INVALIDARG, tr("No file to check existence for specified"));
3011
3012 GuestFsObjData objData; int guestRc;
3013 int vrc = i_fileQueryInfoInternal(aPath, objData, &guestRc);
3014 if (RT_SUCCESS(vrc))
3015 {
3016 *aExists = TRUE;
3017 return S_OK;
3018 }
3019
3020 HRESULT hr = S_OK;
3021
3022 switch (vrc)
3023 {
3024 case VERR_GSTCTL_GUEST_ERROR:
3025 hr = GuestProcess::i_setErrorExternal(this, guestRc);
3026 break;
3027
3028 case VERR_NOT_A_FILE:
3029 *aExists = FALSE;
3030 break;
3031
3032 default:
3033 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information for \"%s\" failed: %Rrc"),
3034 aPath.c_str(), vrc);
3035 break;
3036 }
3037
3038 return hr;
3039#endif /* VBOX_WITH_GUEST_CONTROL */
3040}
3041
3042HRESULT GuestSession::fileRemove(const com::Utf8Str &aPath)
3043{
3044#ifndef VBOX_WITH_GUEST_CONTROL
3045 ReturnComNotImplemented();
3046#else
3047 LogFlowThisFuncEnter();
3048
3049 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3050 return setError(E_INVALIDARG, tr("No file to remove specified"));
3051
3052 HRESULT hr = S_OK;
3053
3054 int guestRc;
3055 int vrc = i_fileRemoveInternal(aPath, &guestRc);
3056 if (RT_FAILURE(vrc))
3057 {
3058 switch (vrc)
3059 {
3060 case VERR_GSTCTL_GUEST_ERROR:
3061 hr = GuestProcess::i_setErrorExternal(this, guestRc);
3062 break;
3063
3064 default:
3065 hr = setError(VBOX_E_IPRT_ERROR, tr("Removing file \"%s\" failed: %Rrc"),
3066 aPath.c_str(), vrc);
3067 break;
3068 }
3069 }
3070
3071 return hr;
3072#endif /* VBOX_WITH_GUEST_CONTROL */
3073}
3074
3075HRESULT GuestSession::fileOpen(const com::Utf8Str &aPath, const com::Utf8Str &aOpenMode, const com::Utf8Str &aDisposition, ULONG aCreationMode, ComPtr<IGuestFile> &aFile)
3076{
3077#ifndef VBOX_WITH_GUEST_CONTROL
3078 ReturnComNotImplemented();
3079#else
3080 LogFlowThisFuncEnter();
3081
3082 Utf8Str strSharingMode = ""; /* Sharing mode is ignored. */
3083
3084 return fileOpenEx(aPath, aOpenMode, aDisposition, strSharingMode, aCreationMode,
3085 0 /* aOffset */, aFile);
3086#endif /* VBOX_WITH_GUEST_CONTROL */
3087}
3088
3089HRESULT GuestSession::fileOpenEx(const com::Utf8Str &aPath, const com::Utf8Str &aOpenMode, const com::Utf8Str &aDisposition, const com::Utf8Str &aSharingMode, ULONG aCreationMode, LONG64 aOffset, ComPtr<IGuestFile> &aFile)
3090
3091{
3092#ifndef VBOX_WITH_GUEST_CONTROL
3093 ReturnComNotImplemented();
3094#else
3095 LogFlowThisFuncEnter();
3096
3097 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3098 return setError(E_INVALIDARG, tr("No file to open specified"));
3099 if (RT_UNLIKELY((aOpenMode.c_str()) == NULL || *(aOpenMode.c_str()) == '\0'))
3100 return setError(E_INVALIDARG, tr("No open mode specified"));
3101 if (RT_UNLIKELY((aDisposition.c_str()) == NULL || *(aDisposition.c_str()) == '\0'))
3102 return setError(E_INVALIDARG, tr("No disposition mode specified"));
3103 /* aSharingMode is optional. */
3104
3105 HRESULT hr = i_isReadyExternal();
3106 if (FAILED(hr))
3107 return hr;
3108
3109 /** @todo Validate creation mode. */
3110 uint32_t uCreationMode = 0;
3111
3112 GuestFileOpenInfo openInfo;
3113 openInfo.mFileName = aPath;
3114 openInfo.mOpenMode = aOpenMode;
3115 openInfo.mDisposition = aDisposition;
3116 openInfo.mSharingMode = aSharingMode;
3117 openInfo.mCreationMode = aCreationMode;
3118 openInfo.mInitialOffset = aOffset;
3119
3120 uint64_t uFlagsIgnored;
3121 int vrc = RTFileModeToFlagsEx(openInfo.mOpenMode.c_str(),
3122 openInfo.mDisposition.c_str(),
3123 openInfo.mSharingMode.c_str(),
3124 &uFlagsIgnored);
3125 if (RT_FAILURE(vrc))
3126 return setError(E_INVALIDARG, tr("Invalid open mode / disposition / sharing mode specified"));
3127
3128 ComObjPtr <GuestFile> pFile; int guestRc;
3129 vrc = i_fileOpenInternal(openInfo, pFile, &guestRc);
3130 if (RT_SUCCESS(vrc))
3131 /* Return directory object to the caller. */
3132 hr = pFile.queryInterfaceTo(aFile.asOutParam());
3133 else
3134 {
3135 switch (vrc)
3136 {
3137 case VERR_NOT_SUPPORTED:
3138 hr = setError(VBOX_E_IPRT_ERROR,
3139 tr("Handling guest files not supported by installed Guest Additions"));
3140 break;
3141
3142 case VERR_GSTCTL_GUEST_ERROR:
3143 hr = GuestFile::i_setErrorExternal(this, guestRc);
3144 break;
3145
3146 default:
3147 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening guest file \"%s\" failed: %Rrc"),
3148 aPath.c_str(), vrc);
3149 break;
3150 }
3151 }
3152
3153 return hr;
3154#endif /* VBOX_WITH_GUEST_CONTROL */
3155}
3156
3157HRESULT GuestSession::fileQueryInfo(const com::Utf8Str &aPath, ComPtr<IGuestFsObjInfo> &aInfo)
3158
3159{
3160#ifndef VBOX_WITH_GUEST_CONTROL
3161 ReturnComNotImplemented();
3162#else
3163 LogFlowThisFuncEnter();
3164
3165 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3166 return setError(E_INVALIDARG, tr("No file to query information for specified"));
3167
3168 HRESULT hr = S_OK;
3169
3170 GuestFsObjData objData; int guestRc;
3171 int vrc = i_fileQueryInfoInternal(aPath, objData, &guestRc);
3172 if (RT_SUCCESS(vrc))
3173 {
3174 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
3175 hr = pFsObjInfo.createObject();
3176 if (FAILED(hr)) return hr;
3177
3178 vrc = pFsObjInfo->init(objData);
3179 if (RT_SUCCESS(vrc))
3180 {
3181 hr = pFsObjInfo.queryInterfaceTo(aInfo.asOutParam());
3182 if (FAILED(hr)) return hr;
3183 }
3184 }
3185
3186 if (RT_FAILURE(vrc))
3187 {
3188 switch (vrc)
3189 {
3190 case VERR_GSTCTL_GUEST_ERROR:
3191 hr = GuestProcess::i_setErrorExternal(this, guestRc);
3192 break;
3193
3194 case VERR_NOT_A_FILE:
3195 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a file"));
3196 break;
3197
3198 default:
3199 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), vrc);
3200 break;
3201 }
3202 }
3203
3204 return hr;
3205#endif /* VBOX_WITH_GUEST_CONTROL */
3206}
3207
3208HRESULT GuestSession::fileQuerySize(const com::Utf8Str &aPath, LONG64 *aSize)
3209{
3210#ifndef VBOX_WITH_GUEST_CONTROL
3211 ReturnComNotImplemented();
3212#else
3213 LogFlowThisFuncEnter();
3214
3215 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3216 return setError(E_INVALIDARG, tr("No file to query size for specified"));
3217
3218 HRESULT hr = S_OK;
3219
3220 int64_t llSize; int guestRc;
3221 int vrc = i_fileQuerySizeInternal(aPath, &llSize, &guestRc);
3222 if (RT_SUCCESS(vrc))
3223 *aSize = llSize;
3224 else
3225 {
3226 switch (vrc)
3227 {
3228 case VERR_GSTCTL_GUEST_ERROR:
3229 hr = GuestProcess::i_setErrorExternal(this, guestRc);
3230 break;
3231
3232 default:
3233 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), vrc);
3234 break;
3235 }
3236 }
3237
3238 return hr;
3239#endif /* VBOX_WITH_GUEST_CONTROL */
3240}
3241
3242HRESULT GuestSession::fileRename(const com::Utf8Str &aSource, const com::Utf8Str &aDest, const std::vector<PathRenameFlag_T> &aFlags)
3243{
3244#ifndef VBOX_WITH_GUEST_CONTROL
3245 ReturnComNotImplemented();
3246#else
3247 LogFlowThisFuncEnter();
3248
3249 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0'))
3250 return setError(E_INVALIDARG, tr("No source file to rename specified"));
3251
3252 if (RT_UNLIKELY((aDest.c_str()) == NULL || *(aDest.c_str()) == '\0'))
3253 return setError(E_INVALIDARG, tr("No destination file to rename the source to specified"));
3254
3255 HRESULT hr = i_isReadyExternal();
3256 if (FAILED(hr))
3257 return hr;
3258
3259 /* No flags; only remove the directory when empty. */
3260 uint32_t uFlags = 0;
3261
3262 int guestRc;
3263 int vrc = i_pathRenameInternal(aSource, aDest, uFlags, &guestRc);
3264 if (RT_FAILURE(vrc))
3265 {
3266 switch (vrc)
3267 {
3268 case VERR_NOT_SUPPORTED:
3269 hr = setError(VBOX_E_IPRT_ERROR,
3270 tr("Handling renaming guest files not supported by installed Guest Additions"));
3271 break;
3272
3273 case VERR_GSTCTL_GUEST_ERROR:
3274 /** @todo Proper guestRc to text translation needed. */
3275 hr = setError(VBOX_E_IPRT_ERROR,
3276 tr("Renaming guest file failed: %Rrc"), guestRc);
3277 break;
3278
3279 default:
3280 hr = setError(VBOX_E_IPRT_ERROR, tr("Renaming guest file \"%s\" failed: %Rrc"),
3281 aSource.c_str(), vrc);
3282 break;
3283 }
3284 }
3285
3286 return hr;
3287#endif /* VBOX_WITH_GUEST_CONTROL */
3288}
3289HRESULT GuestSession::fileSetACL(const com::Utf8Str &aFile, const com::Utf8Str &aAcl)
3290{
3291#ifndef VBOX_WITH_GUEST_CONTROL
3292 ReturnComNotImplemented();
3293#else
3294 LogFlowThisFuncEnter();
3295
3296 ReturnComNotImplemented();
3297#endif /* VBOX_WITH_GUEST_CONTROL */
3298}
3299
3300HRESULT GuestSession::processCreate(const com::Utf8Str &aCommand, const std::vector<com::Utf8Str> &aArguments, const std::vector<com::Utf8Str> &aEnvironment, const std::vector<ProcessCreateFlag_T> &aFlags, ULONG aTimeoutMS, ComPtr<IGuestProcess> &aGuestProcess)
3301{
3302#ifndef VBOX_WITH_GUEST_CONTROL
3303 ReturnComNotImplemented();
3304#else
3305 LogFlowThisFuncEnter();
3306
3307 std::vector<LONG> affinityIgnored;
3308
3309 return processCreateEx(aCommand, aArguments, aEnvironment, aFlags, aTimeoutMS, ProcessPriority_Default, affinityIgnored, aGuestProcess);
3310#endif /* VBOX_WITH_GUEST_CONTROL */
3311}
3312
3313HRESULT GuestSession::processCreateEx(const com::Utf8Str &aCommand, const std::vector<com::Utf8Str> &aArguments, const std::vector<com::Utf8Str> &aEnvironment, const std::vector<ProcessCreateFlag_T> &aFlags, ULONG aTimeoutMS, ProcessPriority_T aPriority, const std::vector<LONG> &aAffinity, ComPtr<IGuestProcess> &aGuestProcess)
3314{
3315#ifndef VBOX_WITH_GUEST_CONTROL
3316 ReturnComNotImplemented();
3317#else
3318 LogFlowThisFuncEnter();
3319
3320 if (RT_UNLIKELY((aCommand.c_str()) == NULL || *(aCommand.c_str()) == '\0'))
3321 return setError(E_INVALIDARG, tr("No command to execute specified"));
3322
3323 HRESULT hr = i_isReadyExternal();
3324 if (FAILED(hr))
3325 return hr;
3326
3327 GuestProcessStartupInfo procInfo;
3328 procInfo.mCommand = aCommand;
3329
3330 if (aArguments.size())
3331 for (size_t i = 0; i < aArguments.size(); i++)
3332 procInfo.mArguments.push_back(aArguments[i]);
3333
3334 int rc = VINF_SUCCESS;
3335
3336 /*
3337 * Create the process environment:
3338 * - Apply the session environment in a first step, and
3339 * - Apply environment variables specified by this call to
3340 * have the chance of overwriting/deleting session entries.
3341 */
3342 procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
3343
3344 if (aEnvironment.size())
3345 for (size_t i = 0; i < aEnvironment.size() && RT_SUCCESS(rc); i++)
3346 rc = procInfo.mEnvironment.Set(aEnvironment[i]);
3347
3348 if (RT_SUCCESS(rc))
3349 {
3350 if (aFlags.size())
3351 for (size_t i = 0; i < aFlags.size(); i++)
3352 procInfo.mFlags |= aFlags[i];
3353
3354 procInfo.mTimeoutMS = aTimeoutMS;
3355
3356 if (aAffinity.size())
3357 for (size_t i = 0; i < aAffinity.size(); i++)
3358 if (aAffinity[i])
3359 procInfo.mAffinity |= (uint64_t)1 << i;
3360
3361 procInfo.mPriority = aPriority;
3362
3363 ComObjPtr<GuestProcess> pProcess;
3364 rc = i_processCreateExInteral(procInfo, pProcess);
3365 if (RT_SUCCESS(rc))
3366 {
3367 /* Return guest session to the caller. */
3368 HRESULT hr2 = pProcess.queryInterfaceTo(aGuestProcess.asOutParam());
3369 if (FAILED(hr2))
3370 rc = VERR_COM_OBJECT_NOT_FOUND;
3371
3372 if (RT_SUCCESS(rc))
3373 rc = pProcess->i_startProcessAsync();
3374 }
3375 }
3376
3377 if (RT_FAILURE(rc))
3378 {
3379 switch (rc)
3380 {
3381 case VERR_MAX_PROCS_REACHED:
3382 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest processes per session (%ld) reached"),
3383 VBOX_GUESTCTRL_MAX_OBJECTS);
3384 break;
3385
3386 /** @todo Add more errors here. */
3387
3388 default:
3389 hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest process, rc=%Rrc"), rc);
3390 break;
3391 }
3392 }
3393
3394 LogFlowFuncLeaveRC(rc);
3395 return hr;
3396#endif /* VBOX_WITH_GUEST_CONTROL */
3397}
3398
3399HRESULT GuestSession::processGet(ULONG aPid, ComPtr<IGuestProcess> &aGuestProcess)
3400
3401{
3402#ifndef VBOX_WITH_GUEST_CONTROL
3403 ReturnComNotImplemented();
3404#else
3405 LogFlowThisFunc(("PID=%RU32\n", aPid));
3406
3407 if (aPid == 0)
3408 return setError(E_INVALIDARG, tr("No valid process ID (PID) specified"));
3409
3410 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
3411
3412 HRESULT hr = S_OK;
3413
3414 ComObjPtr<GuestProcess> pProcess;
3415 int rc = i_processGetByPID(aPid, &pProcess);
3416 if (RT_FAILURE(rc))
3417 hr = setError(E_INVALIDARG, tr("No process with PID %RU32 found"), aPid);
3418
3419 /* This will set (*aProcess) to NULL if pProgress is NULL. */
3420 HRESULT hr2 = pProcess.queryInterfaceTo(aGuestProcess.asOutParam());
3421 if (SUCCEEDED(hr))
3422 hr = hr2;
3423
3424 LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", (IGuestProcess*)aGuestProcess, hr));
3425 return hr;
3426#endif /* VBOX_WITH_GUEST_CONTROL */
3427}
3428
3429HRESULT GuestSession::symlinkCreate(const com::Utf8Str &aSource, const com::Utf8Str &aTarget, SymlinkType_T aType)
3430{
3431#ifndef VBOX_WITH_GUEST_CONTROL
3432 ReturnComNotImplemented();
3433#else
3434 LogFlowThisFuncEnter();
3435
3436 ReturnComNotImplemented();
3437#endif /* VBOX_WITH_GUEST_CONTROL */
3438}
3439
3440HRESULT GuestSession::symlinkExists(const com::Utf8Str &aSymlink, BOOL *aExists)
3441
3442{
3443#ifndef VBOX_WITH_GUEST_CONTROL
3444 ReturnComNotImplemented();
3445#else
3446 LogFlowThisFuncEnter();
3447
3448 ReturnComNotImplemented();
3449#endif /* VBOX_WITH_GUEST_CONTROL */
3450}
3451
3452HRESULT GuestSession::symlinkRead(const com::Utf8Str &aSymlink, const std::vector<SymlinkReadFlag_T> &aFlags, com::Utf8Str &aTarget)
3453{
3454#ifndef VBOX_WITH_GUEST_CONTROL
3455 ReturnComNotImplemented();
3456#else
3457 LogFlowThisFuncEnter();
3458
3459 ReturnComNotImplemented();
3460#endif /* VBOX_WITH_GUEST_CONTROL */
3461}
3462
3463HRESULT GuestSession::symlinkRemoveDirectory(const com::Utf8Str &aPath)
3464{
3465#ifndef VBOX_WITH_GUEST_CONTROL
3466 ReturnComNotImplemented();
3467#else
3468 LogFlowThisFuncEnter();
3469
3470 ReturnComNotImplemented();
3471#endif /* VBOX_WITH_GUEST_CONTROL */
3472}
3473
3474HRESULT GuestSession::symlinkRemoveFile(const com::Utf8Str &aFile)
3475{
3476#ifndef VBOX_WITH_GUEST_CONTROL
3477 ReturnComNotImplemented();
3478#else
3479 LogFlowThisFuncEnter();
3480
3481 ReturnComNotImplemented();
3482#endif /* VBOX_WITH_GUEST_CONTROL */
3483}
3484
3485HRESULT GuestSession::waitFor(ULONG aWaitFor, ULONG aTimeoutMS, GuestSessionWaitResult_T *aReason)
3486{
3487#ifndef VBOX_WITH_GUEST_CONTROL
3488 ReturnComNotImplemented();
3489#else
3490 LogFlowThisFuncEnter();
3491
3492 /*
3493 * Note: Do not hold any locks here while waiting!
3494 */
3495 HRESULT hr = S_OK;
3496
3497 int guestRc; GuestSessionWaitResult_T waitResult;
3498 int vrc = i_waitFor(aWaitFor, aTimeoutMS, waitResult, &guestRc);
3499 if (RT_SUCCESS(vrc))
3500 *aReason = waitResult;
3501 else
3502 {
3503 switch (vrc)
3504 {
3505 case VERR_GSTCTL_GUEST_ERROR:
3506 hr = GuestSession::i_setErrorExternal(this, guestRc);
3507 break;
3508
3509 case VERR_TIMEOUT:
3510 *aReason = GuestSessionWaitResult_Timeout;
3511 break;
3512
3513 default:
3514 {
3515 const char *pszSessionName = mData.mSession.mName.c_str();
3516 hr = setError(VBOX_E_IPRT_ERROR,
3517 tr("Waiting for guest session \"%s\" failed: %Rrc"),
3518 pszSessionName ? pszSessionName : tr("Unnamed"), vrc);
3519 break;
3520 }
3521 }
3522 }
3523
3524 LogFlowFuncLeaveRC(vrc);
3525 return hr;
3526#endif /* VBOX_WITH_GUEST_CONTROL */
3527}
3528
3529HRESULT GuestSession::waitForArray(const std::vector<GuestSessionWaitForFlag_T> &aWaitFor, ULONG aTimeoutMS, GuestSessionWaitResult_T *aReason)
3530{
3531#ifndef VBOX_WITH_GUEST_CONTROL
3532 ReturnComNotImplemented();
3533#else
3534 LogFlowThisFuncEnter();
3535
3536 /*
3537 * Note: Do not hold any locks here while waiting!
3538 */
3539 uint32_t fWaitFor = GuestSessionWaitForFlag_None;
3540 for (size_t i = 0; i < aWaitFor.size(); i++)
3541 fWaitFor |= aWaitFor[i];
3542
3543 return WaitFor(fWaitFor, aTimeoutMS, aReason);
3544#endif /* VBOX_WITH_GUEST_CONTROL */
3545}
3546
Note: See TracBrowser for help on using the repository browser.

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