VirtualBox

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

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

6813 src-client/GuestSessionImpl.cpp vn 2

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

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