VirtualBox

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

Last change on this file since 45418 was 45418, checked in by vboxsync, 12 years ago

Build fix.

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