VirtualBox

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

最後變更 在這個檔案從55535是 55535,由 vboxsync 提交於 10 年 前

Main,VBoxManage,VBoxShell,ValidationKit: Changed the IGuestSession:createProcess[Ex] interfaces to take argv[0] as input separate from the executable name. This is not yet implemented on the guest side.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 107.4 KB
 
1/* $Id: GuestSessionImpl.cpp 55535 2015-04-30 02:13:56Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Guest session handling.
4 */
5
6/*
7 * Copyright (C) 2012-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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.mExecutable = 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.mExecutable = 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.mExecutable = 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.mExecutable = 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.
1840 *
1841 * See GuestProcess::startProcess() or GuestProcess::startProcessAsync() for
1842 * starting the process.
1843 *
1844 * @return IPRT status code.
1845 * @param procInfo
1846 * @param pProcess
1847 */
1848int GuestSession::i_processCreateExInternal(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
1849{
1850 LogFlowFunc(("mExe=%s, mFlags=%x, mTimeoutMS=%RU32\n",
1851 procInfo.mExecutable.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));
1852#ifdef DEBUG
1853 if (procInfo.mArguments.size())
1854 {
1855 LogFlowFunc(("Arguments:"));
1856 ProcessArguments::const_iterator it = procInfo.mArguments.begin();
1857 while (it != procInfo.mArguments.end())
1858 {
1859 LogFlow((" %s", (*it).c_str()));
1860 it++;
1861 }
1862 LogFlow(("\n"));
1863 }
1864#endif
1865
1866 /* Validate flags. */
1867 if (procInfo.mFlags)
1868 {
1869 if ( !(procInfo.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
1870 && !(procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1871 && !(procInfo.mFlags & ProcessCreateFlag_Hidden)
1872 && !(procInfo.mFlags & ProcessCreateFlag_NoProfile)
1873 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1874 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdErr))
1875 {
1876 return VERR_INVALID_PARAMETER;
1877 }
1878 }
1879
1880 if ( (procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1881 && ( (procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1882 || (procInfo.mFlags & ProcessCreateFlag_WaitForStdErr)
1883 )
1884 )
1885 {
1886 return VERR_INVALID_PARAMETER;
1887 }
1888
1889 /* Adjust timeout. If set to 0, we define
1890 * an infinite timeout. */
1891 if (procInfo.mTimeoutMS == 0)
1892 procInfo.mTimeoutMS = UINT32_MAX;
1893
1894 /** @tood Implement process priority + affinity. */
1895
1896 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1897
1898 int rc = VERR_MAX_PROCS_REACHED;
1899 if (mData.mNumObjects >= VBOX_GUESTCTRL_MAX_OBJECTS)
1900 return rc;
1901
1902 /* Create a new (host-based) process ID and assign it. */
1903 uint32_t uNewProcessID = 0;
1904 ULONG uTries = 0;
1905
1906 for (;;)
1907 {
1908 /* Is the context ID already used? */
1909 if (!i_processExists(uNewProcessID, NULL /* pProcess */))
1910 {
1911 /* Callback with context ID was not found. This means
1912 * we can use this context ID for our new callback we want
1913 * to add below. */
1914 rc = VINF_SUCCESS;
1915 break;
1916 }
1917 uNewProcessID++;
1918 if (uNewProcessID == VBOX_GUESTCTRL_MAX_OBJECTS)
1919 uNewProcessID = 0;
1920
1921 if (++uTries == VBOX_GUESTCTRL_MAX_OBJECTS)
1922 break; /* Don't try too hard. */
1923 }
1924
1925 if (RT_FAILURE(rc))
1926 return rc;
1927
1928 /* Create the process object. */
1929 HRESULT hr = pProcess.createObject();
1930 if (FAILED(hr))
1931 return VERR_COM_UNEXPECTED;
1932
1933 rc = pProcess->init(mParent->i_getConsole() /* Console */, this /* Session */,
1934 uNewProcessID, procInfo);
1935 if (RT_FAILURE(rc))
1936 return rc;
1937
1938 /* Add the created process to our map. */
1939 try
1940 {
1941 mData.mProcesses[uNewProcessID] = pProcess;
1942 mData.mNumObjects++;
1943 Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS);
1944
1945 LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %zu processes, %RU32 objects)\n",
1946 mData.mSession.mID, uNewProcessID, mData.mProcesses.size(), mData.mNumObjects));
1947
1948 alock.release(); /* Release lock before firing off event. */
1949
1950 fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, pProcess,
1951 0 /* PID */, true /* Process registered */);
1952 }
1953 catch (std::bad_alloc &)
1954 {
1955 rc = VERR_NO_MEMORY;
1956 }
1957
1958 return rc;
1959}
1960
1961inline bool GuestSession::i_processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess)
1962{
1963 SessionProcesses::const_iterator it = mData.mProcesses.find(uProcessID);
1964 if (it != mData.mProcesses.end())
1965 {
1966 if (pProcess)
1967 *pProcess = it->second;
1968 return true;
1969 }
1970 return false;
1971}
1972
1973inline int GuestSession::i_processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess)
1974{
1975 AssertReturn(uPID, false);
1976 /* pProcess is optional. */
1977
1978 SessionProcesses::iterator itProcs = mData.mProcesses.begin();
1979 for (; itProcs != mData.mProcesses.end(); itProcs++)
1980 {
1981 ComObjPtr<GuestProcess> pCurProc = itProcs->second;
1982 AutoCaller procCaller(pCurProc);
1983 if (procCaller.rc())
1984 return VERR_COM_INVALID_OBJECT_STATE;
1985
1986 ULONG uCurPID;
1987 HRESULT hr = pCurProc->COMGETTER(PID)(&uCurPID);
1988 ComAssertComRC(hr);
1989
1990 if (uCurPID == uPID)
1991 {
1992 if (pProcess)
1993 *pProcess = pCurProc;
1994 return VINF_SUCCESS;
1995 }
1996 }
1997
1998 return VERR_NOT_FOUND;
1999}
2000
2001int GuestSession::i_sendCommand(uint32_t uFunction,
2002 uint32_t uParms, PVBOXHGCMSVCPARM paParms)
2003{
2004 LogFlowThisFuncEnter();
2005
2006#ifndef VBOX_GUESTCTRL_TEST_CASE
2007 ComObjPtr<Console> pConsole = mParent->i_getConsole();
2008 Assert(!pConsole.isNull());
2009
2010 /* Forward the information to the VMM device. */
2011 VMMDev *pVMMDev = pConsole->i_getVMMDev();
2012 AssertPtr(pVMMDev);
2013
2014 LogFlowThisFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms));
2015 int vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, uParms, paParms);
2016 if (RT_FAILURE(vrc))
2017 {
2018 /** @todo What to do here? */
2019 }
2020#else
2021 /* Not needed within testcases. */
2022 int vrc = VINF_SUCCESS;
2023#endif
2024 LogFlowFuncLeaveRC(vrc);
2025 return vrc;
2026}
2027
2028/* static */
2029HRESULT GuestSession::i_setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
2030{
2031 AssertPtr(pInterface);
2032 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
2033
2034 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestSession::i_guestErrorToString(guestRc).c_str());
2035}
2036
2037/* Does not do locking; caller is responsible for that! */
2038int GuestSession::i_setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc)
2039{
2040 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, sessionRc=%Rrc\n",
2041 mData.mStatus, sessionStatus, sessionRc));
2042
2043 if (sessionStatus == GuestSessionStatus_Error)
2044 {
2045 AssertMsg(RT_FAILURE(sessionRc), ("Guest rc must be an error (%Rrc)\n", sessionRc));
2046 /* Do not allow overwriting an already set error. If this happens
2047 * this means we forgot some error checking/locking somewhere. */
2048 AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));
2049 }
2050 else
2051 AssertMsg(RT_SUCCESS(sessionRc), ("Guest rc must not be an error (%Rrc)\n", sessionRc));
2052
2053 if (mData.mStatus != sessionStatus)
2054 {
2055 mData.mStatus = sessionStatus;
2056 mData.mRC = sessionRc;
2057
2058 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
2059 HRESULT hr = errorInfo.createObject();
2060 ComAssertComRC(hr);
2061 int rc2 = errorInfo->initEx(VBOX_E_IPRT_ERROR, sessionRc,
2062 COM_IIDOF(IGuestSession), getComponentName(),
2063 i_guestErrorToString(sessionRc));
2064 AssertRC(rc2);
2065
2066 fireGuestSessionStateChangedEvent(mEventSource, this,
2067 mData.mSession.mID, sessionStatus, errorInfo);
2068 }
2069
2070 return VINF_SUCCESS;
2071}
2072
2073int GuestSession::i_signalWaiters(GuestSessionWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */)
2074{
2075 /*LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n",
2076 enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));*/
2077
2078 /* Note: No write locking here -- already done in the caller. */
2079
2080 int vrc = VINF_SUCCESS;
2081 /*if (mData.mWaitEvent)
2082 vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);*/
2083 LogFlowFuncLeaveRC(vrc);
2084 return vrc;
2085}
2086
2087int GuestSession::i_startTaskAsync(const Utf8Str &strTaskDesc,
2088 GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress)
2089{
2090 LogFlowThisFunc(("strTaskDesc=%s, pTask=%p\n", strTaskDesc.c_str(), pTask));
2091
2092 AssertPtrReturn(pTask, VERR_INVALID_POINTER);
2093
2094 /* Create the progress object. */
2095 HRESULT hr = pProgress.createObject();
2096 if (FAILED(hr))
2097 return VERR_COM_UNEXPECTED;
2098
2099 hr = pProgress->init(static_cast<IGuestSession*>(this),
2100 Bstr(strTaskDesc).raw(),
2101 TRUE /* aCancelable */);
2102 if (FAILED(hr))
2103 return VERR_COM_UNEXPECTED;
2104
2105 /* Initialize our worker task. */
2106 std::auto_ptr<GuestSessionTask> task(pTask);
2107
2108 int rc = task->RunAsync(strTaskDesc, pProgress);
2109 if (RT_FAILURE(rc))
2110 return rc;
2111
2112 /* Don't destruct on success. */
2113 task.release();
2114
2115 LogFlowFuncLeaveRC(rc);
2116 return rc;
2117}
2118
2119/**
2120 * Queries/collects information prior to establishing a guest session.
2121 * This is necessary to know which guest control protocol version to use,
2122 * among other things (later).
2123 *
2124 * @return IPRT status code.
2125 */
2126int GuestSession::i_queryInfo(void)
2127{
2128 /*
2129 * Try querying the guest control protocol version running on the guest.
2130 * This is done using the Guest Additions version
2131 */
2132 ComObjPtr<Guest> pGuest = mParent;
2133 Assert(!pGuest.isNull());
2134
2135 uint32_t uVerAdditions = pGuest->i_getAdditionsVersion();
2136 uint32_t uVBoxMajor = VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions);
2137 uint32_t uVBoxMinor = VBOX_FULL_VERSION_GET_MINOR(uVerAdditions);
2138
2139#ifdef DEBUG_andy
2140 /* Hardcode the to-used protocol version; nice for testing side effects. */
2141 mData.mProtocolVersion = 2;
2142#else
2143 mData.mProtocolVersion = (
2144 /* VBox 5.0 and up. */
2145 uVBoxMajor >= 5
2146 /* VBox 4.3 and up. */
2147 || (uVBoxMajor == 4 && uVBoxMinor >= 3))
2148 ? 2 /* Guest control 2.0. */
2149 : 1; /* Legacy guest control (VBox < 4.3). */
2150 /* Build revision is ignored. */
2151#endif
2152
2153 LogFlowThisFunc(("uVerAdditions=%RU32 (%RU32.%RU32), mProtocolVersion=%RU32\n",
2154 uVerAdditions, uVBoxMajor, uVBoxMinor, mData.mProtocolVersion));
2155
2156 /* Tell the user but don't bitch too often. */
2157 /** @todo Find a bit nicer text. */
2158 if (mData.mProtocolVersion < 2)
2159 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"),
2160 uVBoxMajor, uVBoxMinor, mData.mProtocolVersion));
2161
2162 return VINF_SUCCESS;
2163}
2164
2165int GuestSession::i_waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestSessionWaitResult_T &waitResult, int *pGuestRc)
2166{
2167 LogFlowThisFuncEnter();
2168
2169 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
2170
2171 /*LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",
2172 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));*/
2173
2174 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2175
2176 /* Did some error occur before? Then skip waiting and return. */
2177 if (mData.mStatus == GuestSessionStatus_Error)
2178 {
2179 waitResult = GuestSessionWaitResult_Error;
2180 AssertMsg(RT_FAILURE(mData.mRC), ("No error rc (%Rrc) set when guest session indicated an error\n", mData.mRC));
2181 if (pGuestRc)
2182 *pGuestRc = mData.mRC; /* Return last set error. */
2183 return VERR_GSTCTL_GUEST_ERROR;
2184 }
2185
2186 /* Guest Additions < 4.3 don't support session handling, skip. */
2187 if (mData.mProtocolVersion < 2)
2188 {
2189 waitResult = GuestSessionWaitResult_WaitFlagNotSupported;
2190
2191 LogFlowThisFunc(("Installed Guest Additions don't support waiting for dedicated sessions, skipping\n"));
2192 return VINF_SUCCESS;
2193 }
2194
2195 waitResult = GuestSessionWaitResult_None;
2196 if (fWaitFlags & GuestSessionWaitForFlag_Terminate)
2197 {
2198 switch (mData.mStatus)
2199 {
2200 case GuestSessionStatus_Terminated:
2201 case GuestSessionStatus_Down:
2202 waitResult = GuestSessionWaitResult_Terminate;
2203 break;
2204
2205 case GuestSessionStatus_TimedOutKilled:
2206 case GuestSessionStatus_TimedOutAbnormally:
2207 waitResult = GuestSessionWaitResult_Timeout;
2208 break;
2209
2210 case GuestSessionStatus_Error:
2211 /* Handled above. */
2212 break;
2213
2214 case GuestSessionStatus_Started:
2215 waitResult = GuestSessionWaitResult_Start;
2216 break;
2217
2218 case GuestSessionStatus_Undefined:
2219 case GuestSessionStatus_Starting:
2220 /* Do the waiting below. */
2221 break;
2222
2223 default:
2224 AssertMsgFailed(("Unhandled session status %RU32\n", mData.mStatus));
2225 return VERR_NOT_IMPLEMENTED;
2226 }
2227 }
2228 else if (fWaitFlags & GuestSessionWaitForFlag_Start)
2229 {
2230 switch (mData.mStatus)
2231 {
2232 case GuestSessionStatus_Started:
2233 case GuestSessionStatus_Terminating:
2234 case GuestSessionStatus_Terminated:
2235 case GuestSessionStatus_Down:
2236 waitResult = GuestSessionWaitResult_Start;
2237 break;
2238
2239 case GuestSessionStatus_Error:
2240 waitResult = GuestSessionWaitResult_Error;
2241 break;
2242
2243 case GuestSessionStatus_TimedOutKilled:
2244 case GuestSessionStatus_TimedOutAbnormally:
2245 waitResult = GuestSessionWaitResult_Timeout;
2246 break;
2247
2248 case GuestSessionStatus_Undefined:
2249 case GuestSessionStatus_Starting:
2250 /* Do the waiting below. */
2251 break;
2252
2253 default:
2254 AssertMsgFailed(("Unhandled session status %RU32\n", mData.mStatus));
2255 return VERR_NOT_IMPLEMENTED;
2256 }
2257 }
2258
2259 LogFlowThisFunc(("sessionStatus=%RU32, sessionRc=%Rrc, waitResult=%RU32\n",
2260 mData.mStatus, mData.mRC, waitResult));
2261
2262 /* No waiting needed? Return immediately using the last set error. */
2263 if (waitResult != GuestSessionWaitResult_None)
2264 {
2265 if (pGuestRc)
2266 *pGuestRc = mData.mRC; /* Return last set error (if any). */
2267 return RT_SUCCESS(mData.mRC) ? VINF_SUCCESS : VERR_GSTCTL_GUEST_ERROR;
2268 }
2269
2270 int vrc;
2271
2272 GuestWaitEvent *pEvent = NULL;
2273 GuestEventTypes eventTypes;
2274 try
2275 {
2276 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
2277
2278 vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */,
2279 eventTypes, &pEvent);
2280 }
2281 catch (std::bad_alloc)
2282 {
2283 vrc = VERR_NO_MEMORY;
2284 }
2285
2286 if (RT_FAILURE(vrc))
2287 return vrc;
2288
2289 alock.release(); /* Release lock before waiting. */
2290
2291 GuestSessionStatus_T sessionStatus;
2292 vrc = i_waitForStatusChange(pEvent, fWaitFlags,
2293 uTimeoutMS, &sessionStatus, pGuestRc);
2294 if (RT_SUCCESS(vrc))
2295 {
2296 switch (sessionStatus)
2297 {
2298 case GuestSessionStatus_Started:
2299 waitResult = GuestSessionWaitResult_Start;
2300 break;
2301
2302 case GuestSessionStatus_Terminated:
2303 waitResult = GuestSessionWaitResult_Terminate;
2304 break;
2305
2306 case GuestSessionStatus_TimedOutKilled:
2307 case GuestSessionStatus_TimedOutAbnormally:
2308 waitResult = GuestSessionWaitResult_Timeout;
2309 break;
2310
2311 case GuestSessionStatus_Down:
2312 waitResult = GuestSessionWaitResult_Terminate;
2313 break;
2314
2315 case GuestSessionStatus_Error:
2316 waitResult = GuestSessionWaitResult_Error;
2317 break;
2318
2319 default:
2320 waitResult = GuestSessionWaitResult_Status;
2321 break;
2322 }
2323 }
2324
2325 unregisterWaitEvent(pEvent);
2326
2327 LogFlowFuncLeaveRC(vrc);
2328 return vrc;
2329}
2330
2331int GuestSession::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS,
2332 GuestSessionStatus_T *pSessionStatus, int *pGuestRc)
2333{
2334 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2335
2336 VBoxEventType_T evtType;
2337 ComPtr<IEvent> pIEvent;
2338 int vrc = waitForEvent(pEvent, uTimeoutMS,
2339 &evtType, pIEvent.asOutParam());
2340 if (RT_SUCCESS(vrc))
2341 {
2342 Assert(evtType == VBoxEventType_OnGuestSessionStateChanged);
2343
2344 ComPtr<IGuestSessionStateChangedEvent> pChangedEvent = pIEvent;
2345 Assert(!pChangedEvent.isNull());
2346
2347 GuestSessionStatus_T sessionStatus;
2348 pChangedEvent->COMGETTER(Status)(&sessionStatus);
2349 if (pSessionStatus)
2350 *pSessionStatus = sessionStatus;
2351
2352 ComPtr<IVirtualBoxErrorInfo> errorInfo;
2353 HRESULT hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam());
2354 ComAssertComRC(hr);
2355
2356 LONG lGuestRc;
2357 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
2358 ComAssertComRC(hr);
2359 if (RT_FAILURE((int)lGuestRc))
2360 vrc = VERR_GSTCTL_GUEST_ERROR;
2361 if (pGuestRc)
2362 *pGuestRc = (int)lGuestRc;
2363
2364 LogFlowThisFunc(("Status changed event for session ID=%RU32, new status is: %RU32 (%Rrc)\n",
2365 mData.mSession.mID, sessionStatus,
2366 RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc));
2367 }
2368
2369 LogFlowFuncLeaveRC(vrc);
2370 return vrc;
2371}
2372
2373// implementation of public methods
2374/////////////////////////////////////////////////////////////////////////////
2375
2376HRESULT GuestSession::close()
2377{
2378#ifndef VBOX_WITH_GUEST_CONTROL
2379 ReturnComNotImplemented();
2380#else
2381 LogFlowThisFuncEnter();
2382
2383 AutoCaller autoCaller(this);
2384 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2385
2386 /* Close session on guest. */
2387 int guestRc = VINF_SUCCESS;
2388 int rc = i_closeSession(0 /* Flags */, 30 * 1000 /* Timeout */,
2389 &guestRc);
2390 /* On failure don't return here, instead do all the cleanup
2391 * work first and then return an error. */
2392
2393 /* Remove ourselves from the session list. */
2394 int rc2 = mParent->i_sessionRemove(this);
2395 if (rc2 == VERR_NOT_FOUND) /* Not finding the session anymore isn't critical. */
2396 rc2 = VINF_SUCCESS;
2397
2398 if (RT_SUCCESS(rc))
2399 rc = rc2;
2400
2401 LogFlowThisFunc(("Returning rc=%Rrc, guestRc=%Rrc\n",
2402 rc, guestRc));
2403 if (RT_FAILURE(rc))
2404 {
2405 if (rc == VERR_GSTCTL_GUEST_ERROR)
2406 return GuestSession::i_setErrorExternal(this, guestRc);
2407
2408 return setError(VBOX_E_IPRT_ERROR,
2409 tr("Closing guest session failed with %Rrc"), rc);
2410 }
2411
2412 return S_OK;
2413#endif /* VBOX_WITH_GUEST_CONTROL */
2414}
2415
2416HRESULT GuestSession::copyFrom(const com::Utf8Str &aSource, const com::Utf8Str &aDest,
2417 const std::vector<CopyFileFlag_T> &aFlags,
2418 ComPtr<IProgress> &aProgress)
2419{
2420#ifndef VBOX_WITH_GUEST_CONTROL
2421 ReturnComNotImplemented();
2422#else
2423
2424 LogFlowThisFuncEnter();
2425
2426 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0'))
2427 return setError(E_INVALIDARG, tr("No source specified"));
2428 if (RT_UNLIKELY((aDest.c_str()) == NULL || *(aDest.c_str()) == '\0'))
2429 return setError(E_INVALIDARG, tr("No destination specified"));
2430
2431 uint32_t fFlags = CopyFileFlag_None;
2432 if (aFlags.size())
2433 {
2434 for (size_t i = 0; i < aFlags.size(); i++)
2435 fFlags |= aFlags[i];
2436 }
2437
2438 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2439
2440 HRESULT hr = S_OK;
2441
2442 try
2443 {
2444 ComObjPtr<Progress> pProgress;
2445 SessionTaskCopyFrom *pTask = new SessionTaskCopyFrom(this /* GuestSession */,
2446 aSource, aDest, fFlags);
2447 int rc = i_startTaskAsync(Utf8StrFmt(tr("Copying \"%s\" from guest to \"%s\" on the host"), aSource.c_str(),
2448 aDest.c_str()), pTask, pProgress);
2449 if (RT_SUCCESS(rc))
2450 /* Return progress to the caller. */
2451 hr = pProgress.queryInterfaceTo(aProgress.asOutParam());
2452 else
2453 hr = setError(VBOX_E_IPRT_ERROR,
2454 tr("Starting task for copying file \"%s\" from guest to \"%s\" on the host failed: %Rrc"), rc);
2455 }
2456 catch(std::bad_alloc &)
2457 {
2458 hr = E_OUTOFMEMORY;
2459 }
2460
2461 return hr;
2462#endif /* VBOX_WITH_GUEST_CONTROL */
2463}
2464
2465HRESULT GuestSession::copyTo(const com::Utf8Str &aSource, const com::Utf8Str &aDest, const std::vector<CopyFileFlag_T> &aFlags,
2466 ComPtr<IProgress> &aProgress)
2467{
2468#ifndef VBOX_WITH_GUEST_CONTROL
2469 ReturnComNotImplemented();
2470#else
2471
2472 LogFlowThisFuncEnter();
2473
2474 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0'))
2475 return setError(E_INVALIDARG, tr("No source specified"));
2476 if (RT_UNLIKELY((aDest.c_str()) == NULL || *(aDest.c_str()) == '\0'))
2477 return setError(E_INVALIDARG, tr("No destination specified"));
2478
2479 uint32_t fFlags = CopyFileFlag_None;
2480 if (aFlags.size())
2481 {
2482 for (size_t i = 0; i < aFlags.size(); i++)
2483 fFlags |= aFlags[i];
2484 }
2485
2486 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2487
2488 HRESULT hr = S_OK;
2489
2490 try
2491 {
2492 ComObjPtr<Progress> pProgress;
2493 SessionTaskCopyTo *pTask = new SessionTaskCopyTo(this /* GuestSession */,
2494 aSource, aDest, fFlags);
2495 AssertPtrReturn(pTask, E_OUTOFMEMORY);
2496 int rc = i_startTaskAsync(Utf8StrFmt(tr("Copying \"%s\" from host to \"%s\" on the guest"), aSource.c_str(),
2497 aDest.c_str()), pTask, pProgress);
2498 if (RT_SUCCESS(rc))
2499 {
2500 /* Return progress to the caller. */
2501 hr = pProgress.queryInterfaceTo(aProgress.asOutParam());
2502 }
2503 else
2504 hr = setError(VBOX_E_IPRT_ERROR,
2505 tr("Starting task for copying file \"%s\" from host to \"%s\" on the guest failed: %Rrc"), rc);
2506 }
2507 catch(std::bad_alloc &)
2508 {
2509 hr = E_OUTOFMEMORY;
2510 }
2511
2512 return hr;
2513#endif /* VBOX_WITH_GUEST_CONTROL */
2514}
2515
2516HRESULT GuestSession::directoryCreate(const com::Utf8Str &aPath, ULONG aMode,
2517 const std::vector<DirectoryCreateFlag_T> &aFlags)
2518{
2519#ifndef VBOX_WITH_GUEST_CONTROL
2520 ReturnComNotImplemented();
2521#else
2522 LogFlowThisFuncEnter();
2523
2524 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2525 return setError(E_INVALIDARG, tr("No directory to create specified"));
2526
2527 uint32_t fFlags = DirectoryCreateFlag_None;
2528 if (aFlags.size())
2529 {
2530 for (size_t i = 0; i < aFlags.size(); i++)
2531 fFlags |= aFlags[i];
2532
2533 if (fFlags)
2534 if (!(fFlags & DirectoryCreateFlag_Parents))
2535 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), fFlags);
2536 }
2537
2538 HRESULT hr = S_OK;
2539
2540 ComObjPtr <GuestDirectory> pDirectory; int guestRc;
2541 int rc = i_directoryCreateInternal(aPath, (uint32_t)aMode, fFlags, &guestRc);
2542 if (RT_FAILURE(rc))
2543 {
2544 switch (rc)
2545 {
2546 case VERR_GSTCTL_GUEST_ERROR:
2547 /** @todo Handle VERR_NOT_EQUAL (meaning process exit code <> 0). */
2548 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Could not create directory"));
2549 break;
2550
2551 case VERR_INVALID_PARAMETER:
2552 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Invalid parameters given"));
2553 break;
2554
2555 case VERR_BROKEN_PIPE:
2556 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Unexpectedly aborted"));
2557 break;
2558
2559 default:
2560 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
2561 break;
2562 }
2563 }
2564
2565 return hr;
2566#endif /* VBOX_WITH_GUEST_CONTROL */
2567}
2568
2569HRESULT GuestSession::directoryCreateTemp(const com::Utf8Str &aTemplateName, ULONG aMode, const com::Utf8Str &aPath,
2570 BOOL aSecure, com::Utf8Str &aDirectory)
2571{
2572#ifndef VBOX_WITH_GUEST_CONTROL
2573 ReturnComNotImplemented();
2574#else
2575 LogFlowThisFuncEnter();
2576
2577 if (RT_UNLIKELY((aTemplateName.c_str()) == NULL || *(aTemplateName.c_str()) == '\0'))
2578 return setError(E_INVALIDARG, tr("No template specified"));
2579 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2580 return setError(E_INVALIDARG, tr("No directory name specified"));
2581
2582 HRESULT hr = S_OK;
2583
2584 int guestRc;
2585 int rc = i_objectCreateTempInternal(aTemplateName,
2586 aPath,
2587 true /* Directory */, aDirectory, &guestRc);
2588 if (!RT_SUCCESS(rc))
2589 {
2590 switch (rc)
2591 {
2592 case VERR_GSTCTL_GUEST_ERROR:
2593 hr = GuestProcess::i_setErrorExternal(this, guestRc);
2594 break;
2595
2596 default:
2597 hr = setError(VBOX_E_IPRT_ERROR, tr("Temporary directory creation \"%s\" with template \"%s\" failed: %Rrc"),
2598 aPath.c_str(), aTemplateName.c_str(), rc);
2599 break;
2600 }
2601 }
2602
2603 return hr;
2604#endif /* VBOX_WITH_GUEST_CONTROL */
2605}
2606
2607HRESULT GuestSession::directoryExists(const com::Utf8Str &aPath, BOOL *aExists)
2608{
2609#ifndef VBOX_WITH_GUEST_CONTROL
2610 ReturnComNotImplemented();
2611#else
2612 LogFlowThisFuncEnter();
2613
2614 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2615 return setError(E_INVALIDARG, tr("No directory to check existence for specified"));
2616
2617 HRESULT hr = S_OK;
2618
2619 GuestFsObjData objData; int guestRc;
2620 int rc = i_directoryQueryInfoInternal(aPath, objData, &guestRc);
2621 if (RT_SUCCESS(rc))
2622 *aExists = objData.mType == FsObjType_Directory;
2623 else
2624 {
2625 switch (rc)
2626 {
2627 case VERR_GSTCTL_GUEST_ERROR:
2628 hr = GuestProcess::i_setErrorExternal(this, guestRc);
2629 break;
2630
2631 default:
2632 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence \"%s\" failed: %Rrc"),
2633 aPath.c_str(), rc);
2634 break;
2635 }
2636 }
2637
2638 return hr;
2639#endif /* VBOX_WITH_GUEST_CONTROL */
2640}
2641
2642HRESULT GuestSession::directoryOpen(const com::Utf8Str &aPath, const com::Utf8Str &aFilter,
2643 const std::vector<DirectoryOpenFlag_T> &aFlags, ComPtr<IGuestDirectory> &aDirectory)
2644{
2645#ifndef VBOX_WITH_GUEST_CONTROL
2646 ReturnComNotImplemented();
2647#else
2648 LogFlowThisFuncEnter();
2649
2650 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2651 return setError(E_INVALIDARG, tr("No directory to open specified"));
2652 if (RT_UNLIKELY((aFilter.c_str()) != NULL && *(aFilter.c_str()) != '\0'))
2653 return setError(E_INVALIDARG, tr("Directory filters are not implemented yet"));
2654
2655 uint32_t fFlags = DirectoryOpenFlag_None;
2656 if (aFlags.size())
2657 {
2658 for (size_t i = 0; i < aFlags.size(); i++)
2659 fFlags |= aFlags[i];
2660
2661 if (fFlags)
2662 return setError(E_INVALIDARG, tr("Open flags (%#x) not implemented yet"), fFlags);
2663 }
2664
2665 HRESULT hr = S_OK;
2666
2667 GuestDirectoryOpenInfo openInfo;
2668 openInfo.mPath = aPath;
2669 openInfo.mFilter = aFilter;
2670 openInfo.mFlags = fFlags;
2671
2672 ComObjPtr <GuestDirectory> pDirectory; int guestRc;
2673 int rc = i_directoryOpenInternal(openInfo, pDirectory, &guestRc);
2674 if (RT_SUCCESS(rc))
2675 {
2676 /* Return directory object to the caller. */
2677 hr = pDirectory.queryInterfaceTo(aDirectory.asOutParam());
2678 }
2679 else
2680 {
2681 switch (rc)
2682 {
2683 case VERR_INVALID_PARAMETER:
2684 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed; invalid parameters given"),
2685 aPath.c_str());
2686 break;
2687
2688 case VERR_GSTCTL_GUEST_ERROR:
2689 hr = GuestDirectory::i_setErrorExternal(this, guestRc);
2690 break;
2691
2692 default:
2693 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed: %Rrc"),
2694 aPath.c_str(),rc);
2695 break;
2696 }
2697 }
2698
2699 return hr;
2700#endif /* VBOX_WITH_GUEST_CONTROL */
2701}
2702
2703HRESULT GuestSession::directoryQueryInfo(const com::Utf8Str &aPath, ComPtr<IGuestFsObjInfo> &aInfo)
2704{
2705#ifndef VBOX_WITH_GUEST_CONTROL
2706 ReturnComNotImplemented();
2707#else
2708 LogFlowThisFuncEnter();
2709
2710 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2711 return setError(E_INVALIDARG, tr("No directory to query information for specified"));
2712
2713 HRESULT hr = S_OK;
2714
2715 GuestFsObjData objData; int guestRc;
2716 int vrc = i_directoryQueryInfoInternal(aPath, objData, &guestRc);
2717 if (RT_SUCCESS(vrc))
2718 {
2719 if (objData.mType == FsObjType_Directory)
2720 {
2721 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
2722 hr = pFsObjInfo.createObject();
2723 if (FAILED(hr)) return hr;
2724
2725 vrc = pFsObjInfo->init(objData);
2726 if (RT_SUCCESS(vrc))
2727 {
2728 hr = pFsObjInfo.queryInterfaceTo(aInfo.asOutParam());
2729 if (FAILED(hr)) return hr;
2730 }
2731 }
2732 }
2733
2734 if (RT_FAILURE(vrc))
2735 {
2736 switch (vrc)
2737 {
2738 case VERR_GSTCTL_GUEST_ERROR:
2739 hr = GuestProcess::i_setErrorExternal(this, guestRc);
2740 break;
2741
2742 case VERR_NOT_A_DIRECTORY:
2743 hr = setError(VBOX_E_IPRT_ERROR, tr("Element \"%s\" exists but is not a directory"),
2744 aPath.c_str());
2745 break;
2746
2747 default:
2748 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information for \"%s\" failed: %Rrc"),
2749 aPath.c_str(), vrc);
2750 break;
2751 }
2752 }
2753
2754 return hr;
2755#endif /* VBOX_WITH_GUEST_CONTROL */
2756}
2757
2758HRESULT GuestSession::directoryRemove(const com::Utf8Str &aPath)
2759{
2760#ifndef VBOX_WITH_GUEST_CONTROL
2761 ReturnComNotImplemented();
2762#else
2763 LogFlowThisFuncEnter();
2764
2765 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2766 return setError(E_INVALIDARG, tr("No directory to remove specified"));
2767
2768 HRESULT hr = i_isReadyExternal();
2769 if (FAILED(hr))
2770 return hr;
2771
2772 /* No flags; only remove the directory when empty. */
2773 uint32_t uFlags = 0;
2774
2775 int guestRc;
2776 int vrc = i_directoryRemoveInternal(aPath, uFlags, &guestRc);
2777 if (RT_FAILURE(vrc))
2778 {
2779 switch (vrc)
2780 {
2781 case VERR_NOT_SUPPORTED:
2782 hr = setError(VBOX_E_IPRT_ERROR,
2783 tr("Handling removing guest directories not supported by installed Guest Additions"));
2784 break;
2785
2786 case VERR_GSTCTL_GUEST_ERROR:
2787 hr = GuestDirectory::i_setErrorExternal(this, guestRc);
2788 break;
2789
2790 default:
2791 hr = setError(VBOX_E_IPRT_ERROR, tr("Removing guest directory \"%s\" failed: %Rrc"),
2792 aPath.c_str(), vrc);
2793 break;
2794 }
2795 }
2796
2797 return hr;
2798#endif /* VBOX_WITH_GUEST_CONTROL */
2799}
2800
2801HRESULT GuestSession::directoryRemoveRecursive(const com::Utf8Str &aPath, const std::vector<DirectoryRemoveRecFlag_T> &aFlags,
2802 ComPtr<IProgress> &aProgress)
2803{
2804#ifndef VBOX_WITH_GUEST_CONTROL
2805 ReturnComNotImplemented();
2806#else
2807 LogFlowThisFuncEnter();
2808
2809 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
2810 return setError(E_INVALIDARG, tr("No directory to remove recursively specified"));
2811
2812 HRESULT hr = i_isReadyExternal();
2813 if (FAILED(hr))
2814 return hr;
2815
2816 ComObjPtr<Progress> pProgress;
2817 hr = pProgress.createObject();
2818 if (SUCCEEDED(hr))
2819 hr = pProgress->init(static_cast<IGuestSession *>(this),
2820 Bstr(tr("Removing guest directory")).raw(),
2821 TRUE /*aCancelable*/);
2822 if (FAILED(hr))
2823 return hr;
2824
2825 /* Note: At the moment we don't supply progress information while
2826 * deleting a guest directory recursively. So just complete
2827 * the progress object right now. */
2828 /** @todo Implement progress reporting on guest directory deletion! */
2829 hr = pProgress->i_notifyComplete(S_OK);
2830 if (FAILED(hr))
2831 return hr;
2832
2833 /* Remove the directory + all its contents. */
2834 uint32_t uFlags = DIRREMOVE_FLAG_RECURSIVE
2835 | DIRREMOVE_FLAG_CONTENT_AND_DIR;
2836 int guestRc;
2837 int vrc = i_directoryRemoveInternal(aPath, uFlags, &guestRc);
2838 if (RT_FAILURE(vrc))
2839 {
2840 switch (vrc)
2841 {
2842 case VERR_NOT_SUPPORTED:
2843 hr = setError(VBOX_E_IPRT_ERROR,
2844 tr("Handling removing guest directories recursively not supported by installed Guest Additions"));
2845 break;
2846
2847 case VERR_GSTCTL_GUEST_ERROR:
2848 hr = GuestFile::i_setErrorExternal(this, guestRc);
2849 break;
2850
2851 default:
2852 hr = setError(VBOX_E_IPRT_ERROR, tr("Recursively removing guest directory \"%s\" failed: %Rrc"),
2853 aPath.c_str(), vrc);
2854 break;
2855 }
2856 }
2857 else
2858 {
2859 pProgress.queryInterfaceTo(aProgress.asOutParam());
2860 }
2861
2862 return hr;
2863#endif /* VBOX_WITH_GUEST_CONTROL */
2864}
2865
2866HRESULT GuestSession::directoryRename(const com::Utf8Str &aSource,
2867 const com::Utf8Str &aDest,
2868 const std::vector<PathRenameFlag_T> &aFlags)
2869{
2870#ifndef VBOX_WITH_GUEST_CONTROL
2871 ReturnComNotImplemented();
2872#else
2873 LogFlowThisFuncEnter();
2874
2875 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0'))
2876 return setError(E_INVALIDARG, tr("No source directory to rename specified"));
2877
2878 if (RT_UNLIKELY((aDest.c_str()) == NULL || *(aDest.c_str()) == '\0'))
2879 return setError(E_INVALIDARG, tr("No destination directory to rename the source to specified"));
2880
2881 HRESULT hr = i_isReadyExternal();
2882 if (FAILED(hr))
2883 return hr;
2884
2885 /* No flags; only remove the directory when empty. */
2886 uint32_t uFlags = 0;
2887
2888 int guestRc;
2889 int vrc = i_pathRenameInternal(aSource, aDest, uFlags, &guestRc);
2890 if (RT_FAILURE(vrc))
2891 {
2892 switch (vrc)
2893 {
2894 case VERR_NOT_SUPPORTED:
2895 hr = setError(VBOX_E_IPRT_ERROR,
2896 tr("Handling renaming guest directories not supported by installed Guest Additions"));
2897 break;
2898
2899 case VERR_GSTCTL_GUEST_ERROR:
2900 hr = setError(VBOX_E_IPRT_ERROR,
2901 tr("Renaming guest directory failed: %Rrc"), guestRc);
2902 break;
2903
2904 default:
2905 hr = setError(VBOX_E_IPRT_ERROR, tr("Renaming guest directory \"%s\" failed: %Rrc"),
2906 aSource.c_str(), vrc);
2907 break;
2908 }
2909 }
2910
2911 return hr;
2912#endif /* VBOX_WITH_GUEST_CONTROL */
2913}
2914
2915HRESULT GuestSession::directorySetACL(const com::Utf8Str &aPath, const com::Utf8Str &aAcl)
2916{
2917#ifndef VBOX_WITH_GUEST_CONTROL
2918 ReturnComNotImplemented();
2919#else
2920 LogFlowThisFuncEnter();
2921
2922 ReturnComNotImplemented();
2923#endif /* VBOX_WITH_GUEST_CONTROL */
2924}
2925
2926HRESULT GuestSession::environmentClear()
2927{
2928#ifndef VBOX_WITH_GUEST_CONTROL
2929 ReturnComNotImplemented();
2930#else
2931 LogFlowThisFuncEnter();
2932
2933 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2934
2935 mData.mEnvironment.Clear();
2936
2937 LogFlowThisFuncLeave();
2938 return S_OK;
2939#endif /* VBOX_WITH_GUEST_CONTROL */
2940}
2941
2942HRESULT GuestSession::environmentGet(const com::Utf8Str &aName, com::Utf8Str &aValue)
2943{
2944#ifndef VBOX_WITH_GUEST_CONTROL
2945 ReturnComNotImplemented();
2946#else
2947 LogFlowThisFuncEnter();
2948
2949 if (RT_UNLIKELY(aName.c_str() == NULL) || *(aName.c_str()) == '\0')
2950 return setError(E_INVALIDARG, tr("No value name specified"));
2951
2952 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2953
2954 aValue = mData.mEnvironment.Get(aName);
2955
2956 LogFlowThisFuncLeave();
2957 return S_OK;
2958#endif /* VBOX_WITH_GUEST_CONTROL */
2959}
2960
2961HRESULT GuestSession::environmentSet(const com::Utf8Str &aName, const com::Utf8Str &aValue)
2962{
2963#ifndef VBOX_WITH_GUEST_CONTROL
2964 ReturnComNotImplemented();
2965#else
2966 LogFlowThisFuncEnter();
2967
2968 if (RT_UNLIKELY((aName.c_str() == NULL) || *(aName.c_str()) == '\0'))
2969 return setError(E_INVALIDARG, tr("No value name specified"));
2970
2971 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2972
2973 int rc = mData.mEnvironment.Set(aName, aValue);
2974
2975 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
2976 LogFlowFuncLeaveRC(hr);
2977 return hr;
2978#endif /* VBOX_WITH_GUEST_CONTROL */
2979}
2980
2981HRESULT GuestSession::environmentUnset(const com::Utf8Str &aName)
2982{
2983#ifndef VBOX_WITH_GUEST_CONTROL
2984 ReturnComNotImplemented();
2985#else
2986 LogFlowThisFuncEnter();
2987
2988 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2989
2990 mData.mEnvironment.Unset(aName);
2991
2992 LogFlowThisFuncLeave();
2993 return S_OK;
2994#endif /* VBOX_WITH_GUEST_CONTROL */
2995}
2996
2997HRESULT GuestSession::fileCreateTemp(const com::Utf8Str &aTemplateName, ULONG aMode, const com::Utf8Str &aPath, BOOL aSecure,
2998 ComPtr<IGuestFile> &aFile)
2999{
3000#ifndef VBOX_WITH_GUEST_CONTROL
3001 ReturnComNotImplemented();
3002#else
3003 LogFlowThisFuncEnter();
3004
3005
3006 ReturnComNotImplemented();
3007#endif /* VBOX_WITH_GUEST_CONTROL */
3008}
3009
3010HRESULT GuestSession::fileExists(const com::Utf8Str &aPath, BOOL *aExists)
3011{
3012#ifndef VBOX_WITH_GUEST_CONTROL
3013 ReturnComNotImplemented();
3014#else
3015 LogFlowThisFuncEnter();
3016
3017 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3018 return setError(E_INVALIDARG, tr("No file to check existence for specified"));
3019
3020 GuestFsObjData objData; int guestRc;
3021 int vrc = i_fileQueryInfoInternal(aPath, objData, &guestRc);
3022 if (RT_SUCCESS(vrc))
3023 {
3024 *aExists = TRUE;
3025 return S_OK;
3026 }
3027
3028 HRESULT hr = S_OK;
3029
3030 switch (vrc)
3031 {
3032 case VERR_GSTCTL_GUEST_ERROR:
3033 hr = GuestProcess::i_setErrorExternal(this, guestRc);
3034 break;
3035
3036 case VERR_NOT_A_FILE:
3037 *aExists = FALSE;
3038 break;
3039
3040 default:
3041 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information for \"%s\" failed: %Rrc"),
3042 aPath.c_str(), vrc);
3043 break;
3044 }
3045
3046 return hr;
3047#endif /* VBOX_WITH_GUEST_CONTROL */
3048}
3049
3050HRESULT GuestSession::fileRemove(const com::Utf8Str &aPath)
3051{
3052#ifndef VBOX_WITH_GUEST_CONTROL
3053 ReturnComNotImplemented();
3054#else
3055 LogFlowThisFuncEnter();
3056
3057 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3058 return setError(E_INVALIDARG, tr("No file to remove specified"));
3059
3060 HRESULT hr = S_OK;
3061
3062 int guestRc;
3063 int vrc = i_fileRemoveInternal(aPath, &guestRc);
3064 if (RT_FAILURE(vrc))
3065 {
3066 switch (vrc)
3067 {
3068 case VERR_GSTCTL_GUEST_ERROR:
3069 hr = GuestProcess::i_setErrorExternal(this, guestRc);
3070 break;
3071
3072 default:
3073 hr = setError(VBOX_E_IPRT_ERROR, tr("Removing file \"%s\" failed: %Rrc"),
3074 aPath.c_str(), vrc);
3075 break;
3076 }
3077 }
3078
3079 return hr;
3080#endif /* VBOX_WITH_GUEST_CONTROL */
3081}
3082
3083HRESULT GuestSession::fileOpen(const com::Utf8Str &aPath, const com::Utf8Str &aOpenMode, const com::Utf8Str &aDisposition,
3084 ULONG aCreationMode, ComPtr<IGuestFile> &aFile)
3085{
3086#ifndef VBOX_WITH_GUEST_CONTROL
3087 ReturnComNotImplemented();
3088#else
3089 LogFlowThisFuncEnter();
3090
3091 Utf8Str strSharingMode = ""; /* Sharing mode is ignored. */
3092
3093 return fileOpenEx(aPath, aOpenMode, aDisposition, strSharingMode, aCreationMode,
3094 0 /* aOffset */, aFile);
3095#endif /* VBOX_WITH_GUEST_CONTROL */
3096}
3097
3098HRESULT GuestSession::fileOpenEx(const com::Utf8Str &aPath, const com::Utf8Str &aOpenMode, const com::Utf8Str &aDisposition,
3099 const com::Utf8Str &aSharingMode, ULONG aCreationMode, LONG64 aOffset,
3100 ComPtr<IGuestFile> &aFile)
3101
3102{
3103#ifndef VBOX_WITH_GUEST_CONTROL
3104 ReturnComNotImplemented();
3105#else
3106 LogFlowThisFuncEnter();
3107
3108 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3109 return setError(E_INVALIDARG, tr("No file to open specified"));
3110 if (RT_UNLIKELY((aOpenMode.c_str()) == NULL || *(aOpenMode.c_str()) == '\0'))
3111 return setError(E_INVALIDARG, tr("No open mode specified"));
3112 if (RT_UNLIKELY((aDisposition.c_str()) == NULL || *(aDisposition.c_str()) == '\0'))
3113 return setError(E_INVALIDARG, tr("No disposition mode specified"));
3114 /* aSharingMode is optional. */
3115
3116 HRESULT hr = i_isReadyExternal();
3117 if (FAILED(hr))
3118 return hr;
3119
3120 /** @todo Validate creation mode. */
3121 uint32_t uCreationMode = 0;
3122
3123 GuestFileOpenInfo openInfo;
3124 openInfo.mFileName = aPath;
3125 openInfo.mOpenMode = aOpenMode;
3126 openInfo.mDisposition = aDisposition;
3127 openInfo.mSharingMode = aSharingMode;
3128 openInfo.mCreationMode = aCreationMode;
3129 openInfo.mInitialOffset = aOffset;
3130
3131 uint64_t uFlagsIgnored;
3132 int vrc = RTFileModeToFlagsEx(openInfo.mOpenMode.c_str(),
3133 openInfo.mDisposition.c_str(),
3134 openInfo.mSharingMode.c_str(),
3135 &uFlagsIgnored);
3136 if (RT_FAILURE(vrc))
3137 return setError(E_INVALIDARG, tr("Invalid open mode / disposition / sharing mode specified"));
3138
3139 ComObjPtr <GuestFile> pFile; int guestRc;
3140 vrc = i_fileOpenInternal(openInfo, pFile, &guestRc);
3141 if (RT_SUCCESS(vrc))
3142 /* Return directory object to the caller. */
3143 hr = pFile.queryInterfaceTo(aFile.asOutParam());
3144 else
3145 {
3146 switch (vrc)
3147 {
3148 case VERR_NOT_SUPPORTED:
3149 hr = setError(VBOX_E_IPRT_ERROR,
3150 tr("Handling guest files not supported by installed Guest Additions"));
3151 break;
3152
3153 case VERR_GSTCTL_GUEST_ERROR:
3154 hr = GuestFile::i_setErrorExternal(this, guestRc);
3155 break;
3156
3157 default:
3158 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening guest file \"%s\" failed: %Rrc"),
3159 aPath.c_str(), vrc);
3160 break;
3161 }
3162 }
3163
3164 return hr;
3165#endif /* VBOX_WITH_GUEST_CONTROL */
3166}
3167
3168HRESULT GuestSession::fileQueryInfo(const com::Utf8Str &aPath, ComPtr<IGuestFsObjInfo> &aInfo)
3169
3170{
3171#ifndef VBOX_WITH_GUEST_CONTROL
3172 ReturnComNotImplemented();
3173#else
3174 LogFlowThisFuncEnter();
3175
3176 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3177 return setError(E_INVALIDARG, tr("No file to query information for specified"));
3178
3179 HRESULT hr = S_OK;
3180
3181 GuestFsObjData objData; int guestRc;
3182 int vrc = i_fileQueryInfoInternal(aPath, objData, &guestRc);
3183 if (RT_SUCCESS(vrc))
3184 {
3185 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
3186 hr = pFsObjInfo.createObject();
3187 if (FAILED(hr)) return hr;
3188
3189 vrc = pFsObjInfo->init(objData);
3190 if (RT_SUCCESS(vrc))
3191 {
3192 hr = pFsObjInfo.queryInterfaceTo(aInfo.asOutParam());
3193 if (FAILED(hr)) return hr;
3194 }
3195 }
3196
3197 if (RT_FAILURE(vrc))
3198 {
3199 switch (vrc)
3200 {
3201 case VERR_GSTCTL_GUEST_ERROR:
3202 hr = GuestProcess::i_setErrorExternal(this, guestRc);
3203 break;
3204
3205 case VERR_NOT_A_FILE:
3206 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a file"));
3207 break;
3208
3209 default:
3210 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), vrc);
3211 break;
3212 }
3213 }
3214
3215 return hr;
3216#endif /* VBOX_WITH_GUEST_CONTROL */
3217}
3218
3219HRESULT GuestSession::fileQuerySize(const com::Utf8Str &aPath, LONG64 *aSize)
3220{
3221#ifndef VBOX_WITH_GUEST_CONTROL
3222 ReturnComNotImplemented();
3223#else
3224 LogFlowThisFuncEnter();
3225
3226 if (RT_UNLIKELY((aPath.c_str()) == NULL || *(aPath.c_str()) == '\0'))
3227 return setError(E_INVALIDARG, tr("No file to query size for specified"));
3228
3229 HRESULT hr = S_OK;
3230
3231 int64_t llSize; int guestRc;
3232 int vrc = i_fileQuerySizeInternal(aPath, &llSize, &guestRc);
3233 if (RT_SUCCESS(vrc))
3234 *aSize = llSize;
3235 else
3236 {
3237 switch (vrc)
3238 {
3239 case VERR_GSTCTL_GUEST_ERROR:
3240 hr = GuestProcess::i_setErrorExternal(this, guestRc);
3241 break;
3242
3243 default:
3244 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), vrc);
3245 break;
3246 }
3247 }
3248
3249 return hr;
3250#endif /* VBOX_WITH_GUEST_CONTROL */
3251}
3252
3253HRESULT GuestSession::fileRename(const com::Utf8Str &aSource, const com::Utf8Str &aDest,
3254 const std::vector<PathRenameFlag_T> &aFlags)
3255{
3256#ifndef VBOX_WITH_GUEST_CONTROL
3257 ReturnComNotImplemented();
3258#else
3259 LogFlowThisFuncEnter();
3260
3261 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0'))
3262 return setError(E_INVALIDARG, tr("No source file to rename specified"));
3263
3264 if (RT_UNLIKELY((aDest.c_str()) == NULL || *(aDest.c_str()) == '\0'))
3265 return setError(E_INVALIDARG, tr("No destination file to rename the source to specified"));
3266
3267 HRESULT hr = i_isReadyExternal();
3268 if (FAILED(hr))
3269 return hr;
3270
3271 /* No flags; only remove the directory when empty. */
3272 uint32_t uFlags = 0;
3273
3274 int guestRc;
3275 int vrc = i_pathRenameInternal(aSource, aDest, uFlags, &guestRc);
3276 if (RT_FAILURE(vrc))
3277 {
3278 switch (vrc)
3279 {
3280 case VERR_NOT_SUPPORTED:
3281 hr = setError(VBOX_E_IPRT_ERROR,
3282 tr("Handling renaming guest files not supported by installed Guest Additions"));
3283 break;
3284
3285 case VERR_GSTCTL_GUEST_ERROR:
3286 /** @todo Proper guestRc to text translation needed. */
3287 hr = setError(VBOX_E_IPRT_ERROR,
3288 tr("Renaming guest file failed: %Rrc"), guestRc);
3289 break;
3290
3291 default:
3292 hr = setError(VBOX_E_IPRT_ERROR, tr("Renaming guest file \"%s\" failed: %Rrc"),
3293 aSource.c_str(), vrc);
3294 break;
3295 }
3296 }
3297
3298 return hr;
3299#endif /* VBOX_WITH_GUEST_CONTROL */
3300}
3301HRESULT GuestSession::fileSetACL(const com::Utf8Str &aFile, const com::Utf8Str &aAcl)
3302{
3303#ifndef VBOX_WITH_GUEST_CONTROL
3304 ReturnComNotImplemented();
3305#else
3306 LogFlowThisFuncEnter();
3307
3308 ReturnComNotImplemented();
3309#endif /* VBOX_WITH_GUEST_CONTROL */
3310}
3311
3312HRESULT GuestSession::processCreate(const com::Utf8Str &aExecutable, const std::vector<com::Utf8Str> &aArguments,
3313 const std::vector<com::Utf8Str> &aEnvironment,
3314 const std::vector<ProcessCreateFlag_T> &aFlags,
3315 ULONG aTimeoutMS, ComPtr<IGuestProcess> &aGuestProcess)
3316{
3317#ifndef VBOX_WITH_GUEST_CONTROL
3318 ReturnComNotImplemented();
3319#else
3320 LogFlowThisFuncEnter();
3321
3322 std::vector<LONG> affinityIgnored;
3323
3324 return processCreateEx(aExecutable, aArguments, aEnvironment, aFlags, aTimeoutMS, ProcessPriority_Default,
3325 affinityIgnored, aGuestProcess);
3326#endif /* VBOX_WITH_GUEST_CONTROL */
3327}
3328
3329HRESULT GuestSession::processCreateEx(const com::Utf8Str &aExecutable, const std::vector<com::Utf8Str> &aArguments,
3330 const std::vector<com::Utf8Str> &aEnvironment,
3331 const std::vector<ProcessCreateFlag_T> &aFlags, ULONG aTimeoutMS,
3332 ProcessPriority_T aPriority, const std::vector<LONG> &aAffinity,
3333 ComPtr<IGuestProcess> &aGuestProcess)
3334{
3335#ifndef VBOX_WITH_GUEST_CONTROL
3336 ReturnComNotImplemented();
3337#else
3338 LogFlowThisFuncEnter();
3339
3340 /*
3341 * Must have an executable to execute. If none is given, we try use the
3342 * zero'th argument.
3343 */
3344 const char *pszExecutable = aExecutable.c_str();
3345 if (RT_UNLIKELY(pszExecutable == NULL || *pszExecutable == '\0'))
3346 {
3347 if (aArguments.size() > 0)
3348 pszExecutable = aArguments[0].c_str();
3349 if (pszExecutable == NULL || *pszExecutable == '\0')
3350 return setError(E_INVALIDARG, tr("No command to execute specified"));
3351 }
3352
3353 /*
3354 * Check the session.
3355 */
3356 HRESULT hr = i_isReadyExternal();
3357 if (FAILED(hr))
3358 return hr;
3359
3360 /*
3361 * Build the process startup info.
3362 */
3363 GuestProcessStartupInfo procInfo;
3364
3365 /* Executable and arguments. */
3366 procInfo.mExecutable = pszExecutable;
3367 if (aArguments.size())
3368 for (size_t i = 0; i < aArguments.size(); i++)
3369 procInfo.mArguments.push_back(aArguments[i]);
3370
3371 /*
3372 * Create the process environment:
3373 * - Apply the session environment in a first step, and
3374 * - Apply environment variables specified by this call to
3375 * have the chance of overwriting/deleting session entries.
3376 */
3377 procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
3378
3379 int rc = VINF_SUCCESS;
3380 if (aEnvironment.size())
3381 for (size_t i = 0; i < aEnvironment.size() && RT_SUCCESS(rc); i++)
3382 {
3383 /** @todo r=bird: What ARE you trying to do here??? The documentation is crystal
3384 * clear on that each entry contains ONE pair, however,
3385 * GuestEnvironment::Set(const Utf8Str &) here will split up the input
3386 * into any number of pairs, from what I can tell. Such that for e.g.
3387 * "VBOX_LOG_DEST=file=/tmp/foobared.log" becomes "VBOX_LOG_DEST=file"
3388 * and "/tmp/foobared.log" - which I obviously don't want! */
3389 rc = procInfo.mEnvironment.Set(aEnvironment[i]);
3390 }
3391
3392 if (RT_SUCCESS(rc))
3393 {
3394 /* Convert the flag array into a mask. */
3395 if (aFlags.size())
3396 for (size_t i = 0; i < aFlags.size(); i++)
3397 procInfo.mFlags |= aFlags[i];
3398
3399 procInfo.mTimeoutMS = aTimeoutMS;
3400
3401 /** @todo use RTCPUSET instead of archaic 64-bit variables! */
3402 if (aAffinity.size())
3403 for (size_t i = 0; i < aAffinity.size(); i++)
3404 if (aAffinity[i])
3405 procInfo.mAffinity |= (uint64_t)1 << i;
3406
3407 procInfo.mPriority = aPriority;
3408
3409 /*
3410 * Create a guest process object.
3411 */
3412 ComObjPtr<GuestProcess> pProcess;
3413 rc = i_processCreateExInternal(procInfo, pProcess);
3414 if (RT_SUCCESS(rc))
3415 {
3416 /* Return guest session to the caller. */
3417 HRESULT hr2 = pProcess.queryInterfaceTo(aGuestProcess.asOutParam());
3418 if (SUCCEEDED(hr2))
3419 {
3420 /*
3421 * Start the process.
3422 */
3423 rc = pProcess->i_startProcessAsync();
3424 if (RT_FAILURE(rc))
3425 {
3426 /** @todo r=bird: What happens to the interface that *aGuestProcess points to
3427 * now? Looks like a leak or an undocument hack of sorts... */
3428 }
3429 }
3430 else
3431 rc = VERR_COM_OBJECT_NOT_FOUND;
3432 }
3433 }
3434
3435 /** @todo you're better off doing this is 'else if (rc == xxx') statements,
3436 * since there is just one place where you'll get
3437 * VERR_MAX_PROCS_REACHED in the above code. */
3438 if (RT_FAILURE(rc))
3439 {
3440 switch (rc)
3441 {
3442 case VERR_MAX_PROCS_REACHED:
3443 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest processes per session (%ld) reached"),
3444 VBOX_GUESTCTRL_MAX_OBJECTS);
3445 break;
3446
3447 /** @todo Add more errors here. */
3448
3449 default:
3450 hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest process, rc=%Rrc"), rc);
3451 break;
3452 }
3453 }
3454
3455 LogFlowFuncLeaveRC(rc);
3456 return hr;
3457#endif /* VBOX_WITH_GUEST_CONTROL */
3458}
3459
3460HRESULT GuestSession::processGet(ULONG aPid, ComPtr<IGuestProcess> &aGuestProcess)
3461
3462{
3463#ifndef VBOX_WITH_GUEST_CONTROL
3464 ReturnComNotImplemented();
3465#else
3466 LogFlowThisFunc(("PID=%RU32\n", aPid));
3467
3468 if (aPid == 0)
3469 return setError(E_INVALIDARG, tr("No valid process ID (PID) specified"));
3470
3471 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
3472
3473 HRESULT hr = S_OK;
3474
3475 ComObjPtr<GuestProcess> pProcess;
3476 int rc = i_processGetByPID(aPid, &pProcess);
3477 if (RT_FAILURE(rc))
3478 hr = setError(E_INVALIDARG, tr("No process with PID %RU32 found"), aPid);
3479
3480 /* This will set (*aProcess) to NULL if pProgress is NULL. */
3481 HRESULT hr2 = pProcess.queryInterfaceTo(aGuestProcess.asOutParam());
3482 if (SUCCEEDED(hr))
3483 hr = hr2;
3484
3485 LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", (IGuestProcess*)aGuestProcess, hr));
3486 return hr;
3487#endif /* VBOX_WITH_GUEST_CONTROL */
3488}
3489
3490HRESULT GuestSession::symlinkCreate(const com::Utf8Str &aSource, const com::Utf8Str &aTarget, SymlinkType_T aType)
3491{
3492#ifndef VBOX_WITH_GUEST_CONTROL
3493 ReturnComNotImplemented();
3494#else
3495 LogFlowThisFuncEnter();
3496
3497 ReturnComNotImplemented();
3498#endif /* VBOX_WITH_GUEST_CONTROL */
3499}
3500
3501HRESULT GuestSession::symlinkExists(const com::Utf8Str &aSymlink, BOOL *aExists)
3502
3503{
3504#ifndef VBOX_WITH_GUEST_CONTROL
3505 ReturnComNotImplemented();
3506#else
3507 LogFlowThisFuncEnter();
3508
3509 ReturnComNotImplemented();
3510#endif /* VBOX_WITH_GUEST_CONTROL */
3511}
3512
3513HRESULT GuestSession::symlinkRead(const com::Utf8Str &aSymlink, const std::vector<SymlinkReadFlag_T> &aFlags,
3514 com::Utf8Str &aTarget)
3515{
3516#ifndef VBOX_WITH_GUEST_CONTROL
3517 ReturnComNotImplemented();
3518#else
3519 LogFlowThisFuncEnter();
3520
3521 ReturnComNotImplemented();
3522#endif /* VBOX_WITH_GUEST_CONTROL */
3523}
3524
3525HRESULT GuestSession::symlinkRemoveDirectory(const com::Utf8Str &aPath)
3526{
3527#ifndef VBOX_WITH_GUEST_CONTROL
3528 ReturnComNotImplemented();
3529#else
3530 LogFlowThisFuncEnter();
3531
3532 ReturnComNotImplemented();
3533#endif /* VBOX_WITH_GUEST_CONTROL */
3534}
3535
3536HRESULT GuestSession::symlinkRemoveFile(const com::Utf8Str &aFile)
3537{
3538#ifndef VBOX_WITH_GUEST_CONTROL
3539 ReturnComNotImplemented();
3540#else
3541 LogFlowThisFuncEnter();
3542
3543 ReturnComNotImplemented();
3544#endif /* VBOX_WITH_GUEST_CONTROL */
3545}
3546
3547HRESULT GuestSession::waitFor(ULONG aWaitFor, ULONG aTimeoutMS, GuestSessionWaitResult_T *aReason)
3548{
3549#ifndef VBOX_WITH_GUEST_CONTROL
3550 ReturnComNotImplemented();
3551#else
3552 LogFlowThisFuncEnter();
3553
3554 /*
3555 * Note: Do not hold any locks here while waiting!
3556 */
3557 HRESULT hr = S_OK;
3558
3559 int guestRc; GuestSessionWaitResult_T waitResult;
3560 int vrc = i_waitFor(aWaitFor, aTimeoutMS, waitResult, &guestRc);
3561 if (RT_SUCCESS(vrc))
3562 *aReason = waitResult;
3563 else
3564 {
3565 switch (vrc)
3566 {
3567 case VERR_GSTCTL_GUEST_ERROR:
3568 hr = GuestSession::i_setErrorExternal(this, guestRc);
3569 break;
3570
3571 case VERR_TIMEOUT:
3572 *aReason = GuestSessionWaitResult_Timeout;
3573 break;
3574
3575 default:
3576 {
3577 const char *pszSessionName = mData.mSession.mName.c_str();
3578 hr = setError(VBOX_E_IPRT_ERROR,
3579 tr("Waiting for guest session \"%s\" failed: %Rrc"),
3580 pszSessionName ? pszSessionName : tr("Unnamed"), vrc);
3581 break;
3582 }
3583 }
3584 }
3585
3586 LogFlowFuncLeaveRC(vrc);
3587 return hr;
3588#endif /* VBOX_WITH_GUEST_CONTROL */
3589}
3590
3591HRESULT GuestSession::waitForArray(const std::vector<GuestSessionWaitForFlag_T> &aWaitFor, ULONG aTimeoutMS,
3592 GuestSessionWaitResult_T *aReason)
3593{
3594#ifndef VBOX_WITH_GUEST_CONTROL
3595 ReturnComNotImplemented();
3596#else
3597 LogFlowThisFuncEnter();
3598
3599 /*
3600 * Note: Do not hold any locks here while waiting!
3601 */
3602 uint32_t fWaitFor = GuestSessionWaitForFlag_None;
3603 for (size_t i = 0; i < aWaitFor.size(); i++)
3604 fWaitFor |= aWaitFor[i];
3605
3606 return WaitFor(fWaitFor, aTimeoutMS, aReason);
3607#endif /* VBOX_WITH_GUEST_CONTROL */
3608}
3609
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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