VirtualBox

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

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

LogRelMax

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

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