VirtualBox

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

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

GuestCtrl: Infrastructure changes for handling and executing dedicated guest sessions and protocol versioning (untested, work in progress).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 69.9 KB
Line 
1
2/* $Id: GuestSessionImpl.cpp 44863 2013-02-28 12:18:17Z 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 "GuestSessionImpl.h"
25#include "GuestCtrlImplPrivate.h"
26
27#include "Global.h"
28#include "AutoCaller.h"
29#include "ProgressImpl.h"
30#include "VMMDev.h"
31
32#include <memory> /* For auto_ptr. */
33
34#include <iprt/env.h>
35#include <iprt/file.h> /* For CopyTo/From. */
36
37#include <VBox/com/array.h>
38#include <VBox/version.h>
39
40#ifdef LOG_GROUP
41 #undef LOG_GROUP
42#endif
43#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
44#include <VBox/log.h>
45
46// constructor / destructor
47/////////////////////////////////////////////////////////////////////////////
48
49DEFINE_EMPTY_CTOR_DTOR(GuestSession)
50
51HRESULT GuestSession::FinalConstruct(void)
52{
53 LogFlowThisFunc(("\n"));
54 return BaseFinalConstruct();
55}
56
57void GuestSession::FinalRelease(void)
58{
59 LogFlowThisFuncEnter();
60 uninit();
61 BaseFinalRelease();
62 LogFlowThisFuncLeave();
63}
64
65// public initializer/uninitializer for internal purposes only
66/////////////////////////////////////////////////////////////////////////////
67
68/**
69 * Initializes a guest session but does *not* open in on the guest side
70 * yet. This needs to be done via the openSession() call.
71 *
72 * @return IPRT status code.
73 * @param aGuest
74 * @param aSessionID
75 * @param aUser
76 * @param aPassword
77 * @param aDomain
78 * @param aName
79 */
80int GuestSession::init(Guest *aGuest, ULONG aSessionID,
81 Utf8Str aUser, Utf8Str aPassword, Utf8Str aDomain, Utf8Str aName)
82{
83 LogFlowThisFuncEnter();
84
85 AssertPtrReturn(aGuest, VERR_INVALID_POINTER);
86
87 /* Enclose the state transition NotReady->InInit->Ready. */
88 AutoInitSpan autoInitSpan(this);
89 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
90
91 mData.mTimeout = 30 * 60 * 1000; /* Session timeout is 30 mins by default. */
92 mData.mParent = aGuest;
93 mData.mId = aSessionID;
94
95 mData.mCredentials.mUser = aUser;
96 mData.mCredentials.mPassword = aPassword;
97 mData.mCredentials.mDomain = aDomain;
98 mData.mName = aName;
99 mData.mNumObjects = 0;
100
101 /* Confirm a successful initialization when it's the case. */
102 autoInitSpan.setSucceeded();
103
104 LogFlowFuncLeaveRC(VINF_SUCCESS);
105 return VINF_SUCCESS;
106}
107
108/**
109 * Uninitializes the instance.
110 * Called from FinalRelease().
111 */
112void GuestSession::uninit(void)
113{
114 LogFlowThisFuncEnter();
115
116 /* Enclose the state transition Ready->InUninit->NotReady. */
117 AutoUninitSpan autoUninitSpan(this);
118 if (autoUninitSpan.uninitDone())
119 return;
120
121 int rc = VINF_SUCCESS;
122
123#ifndef VBOX_WITH_GUEST_CONTROL
124 LogFlowThisFunc(("Closing directories (%RU64 total)\n",
125 mData.mDirectories.size()));
126 for (SessionDirectories::iterator itDirs = mData.mDirectories.begin();
127 itDirs != mData.mDirectories.end(); ++itDirs)
128 {
129#ifdef DEBUG
130 ULONG cRefs = (*itDirs)->AddRef();
131 LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itDirs), cRefs));
132 (*itDirs)->Release();
133#endif
134 (*itDirs)->uninit();
135 }
136 mData.mDirectories.clear();
137
138 LogFlowThisFunc(("Closing files (%RU64 total)\n",
139 mData.mFiles.size()));
140 for (SessionFiles::iterator itFiles = mData.mFiles.begin();
141 itFiles != mData.mFiles.end(); ++itFiles)
142 {
143#ifdef DEBUG
144 ULONG cRefs = (*itFiles)->AddRef();
145 LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itFiles), cRefs));
146 (*itFiles)->Release();
147#endif
148 (*itFiles)->uninit();
149 }
150 mData.mFiles.clear();
151
152 LogFlowThisFunc(("Closing processes (%RU64 total)\n",
153 mData.mProcesses.size()));
154 for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();
155 itProcs != mData.mProcesses.end(); ++itProcs)
156 {
157#ifdef DEBUG
158 ULONG cRefs = itProcs->second->AddRef();
159 LogFlowThisFunc(("pProcess=%p, cRefs=%RU32\n", itProcs->second, cRefs));
160 itProcs->second->Release();
161#endif
162 itProcs->second->uninit();
163 }
164 mData.mProcesses.clear();
165
166 LogFlowThisFunc(("mNumObjects=%RU32\n", mData.mNumObjects));
167#endif
168 LogFlowFuncLeaveRC(rc);
169}
170
171// implementation of public getters/setters for attributes
172/////////////////////////////////////////////////////////////////////////////
173
174STDMETHODIMP GuestSession::COMGETTER(User)(BSTR *aUser)
175{
176#ifndef VBOX_WITH_GUEST_CONTROL
177 ReturnComNotImplemented();
178#else
179 LogFlowThisFuncEnter();
180
181 CheckComArgOutPointerValid(aUser);
182
183 AutoCaller autoCaller(this);
184 if (FAILED(autoCaller.rc())) return autoCaller.rc();
185
186 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
187
188 mData.mCredentials.mUser.cloneTo(aUser);
189
190 LogFlowFuncLeaveRC(S_OK);
191 return S_OK;
192#endif /* VBOX_WITH_GUEST_CONTROL */
193}
194
195STDMETHODIMP GuestSession::COMGETTER(Domain)(BSTR *aDomain)
196{
197#ifndef VBOX_WITH_GUEST_CONTROL
198 ReturnComNotImplemented();
199#else
200 LogFlowThisFuncEnter();
201
202 CheckComArgOutPointerValid(aDomain);
203
204 AutoCaller autoCaller(this);
205 if (FAILED(autoCaller.rc())) return autoCaller.rc();
206
207 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
208
209 mData.mCredentials.mDomain.cloneTo(aDomain);
210
211 LogFlowFuncLeaveRC(S_OK);
212 return S_OK;
213#endif /* VBOX_WITH_GUEST_CONTROL */
214}
215
216STDMETHODIMP GuestSession::COMGETTER(Name)(BSTR *aName)
217{
218#ifndef VBOX_WITH_GUEST_CONTROL
219 ReturnComNotImplemented();
220#else
221 LogFlowThisFuncEnter();
222
223 CheckComArgOutPointerValid(aName);
224
225 AutoCaller autoCaller(this);
226 if (FAILED(autoCaller.rc())) return autoCaller.rc();
227
228 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
229
230 mData.mName.cloneTo(aName);
231
232 LogFlowFuncLeaveRC(S_OK);
233 return S_OK;
234#endif /* VBOX_WITH_GUEST_CONTROL */
235}
236
237STDMETHODIMP GuestSession::COMGETTER(Id)(ULONG *aId)
238{
239#ifndef VBOX_WITH_GUEST_CONTROL
240 ReturnComNotImplemented();
241#else
242 LogFlowThisFuncEnter();
243
244 CheckComArgOutPointerValid(aId);
245
246 AutoCaller autoCaller(this);
247 if (FAILED(autoCaller.rc())) return autoCaller.rc();
248
249 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
250
251 *aId = mData.mId;
252
253 LogFlowFuncLeaveRC(S_OK);
254 return S_OK;
255#endif /* VBOX_WITH_GUEST_CONTROL */
256}
257
258STDMETHODIMP GuestSession::COMGETTER(Timeout)(ULONG *aTimeout)
259{
260#ifndef VBOX_WITH_GUEST_CONTROL
261 ReturnComNotImplemented();
262#else
263 LogFlowThisFuncEnter();
264
265 CheckComArgOutPointerValid(aTimeout);
266
267 AutoCaller autoCaller(this);
268 if (FAILED(autoCaller.rc())) return autoCaller.rc();
269
270 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
271
272 *aTimeout = mData.mTimeout;
273
274 LogFlowFuncLeaveRC(S_OK);
275 return S_OK;
276#endif /* VBOX_WITH_GUEST_CONTROL */
277}
278
279STDMETHODIMP GuestSession::COMSETTER(Timeout)(ULONG aTimeout)
280{
281#ifndef VBOX_WITH_GUEST_CONTROL
282 ReturnComNotImplemented();
283#else
284 LogFlowThisFuncEnter();
285
286 AutoCaller autoCaller(this);
287 if (FAILED(autoCaller.rc())) return autoCaller.rc();
288
289 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
290
291 mData.mTimeout = aTimeout;
292
293 LogFlowFuncLeaveRC(S_OK);
294 return S_OK;
295#endif /* VBOX_WITH_GUEST_CONTROL */
296}
297
298STDMETHODIMP GuestSession::COMGETTER(Environment)(ComSafeArrayOut(BSTR, aEnvironment))
299{
300#ifndef VBOX_WITH_GUEST_CONTROL
301 ReturnComNotImplemented();
302#else
303 LogFlowThisFuncEnter();
304
305 CheckComArgOutSafeArrayPointerValid(aEnvironment);
306
307 AutoCaller autoCaller(this);
308 if (FAILED(autoCaller.rc())) return autoCaller.rc();
309
310 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
311
312 size_t cEnvVars = mData.mEnvironment.Size();
313 LogFlowThisFunc(("%s cEnvVars=%RU32\n", mData.mName.c_str(), cEnvVars));
314 com::SafeArray<BSTR> environment(cEnvVars);
315
316 for (size_t i = 0; i < cEnvVars; i++)
317 {
318 Bstr strEnv(mData.mEnvironment.Get(i));
319 strEnv.cloneTo(&environment[i]);
320 }
321 environment.detachTo(ComSafeArrayOutArg(aEnvironment));
322
323 LogFlowFuncLeaveRC(S_OK);
324 return S_OK;
325#endif /* VBOX_WITH_GUEST_CONTROL */
326}
327
328STDMETHODIMP GuestSession::COMSETTER(Environment)(ComSafeArrayIn(IN_BSTR, aValues))
329{
330#ifndef VBOX_WITH_GUEST_CONTROL
331 ReturnComNotImplemented();
332#else
333 LogFlowThisFuncEnter();
334
335 AutoCaller autoCaller(this);
336 if (FAILED(autoCaller.rc())) return autoCaller.rc();
337
338 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
339
340 com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aValues));
341
342 int rc = VINF_SUCCESS;
343 for (size_t i = 0; i < environment.size() && RT_SUCCESS(rc); i++)
344 {
345 Utf8Str strEnv(environment[i]);
346 if (!strEnv.isEmpty()) /* Silently skip empty entries. */
347 rc = mData.mEnvironment.Set(strEnv);
348 }
349
350 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
351 LogFlowFuncLeaveRC(hr);
352 return hr;
353#endif /* VBOX_WITH_GUEST_CONTROL */
354}
355
356STDMETHODIMP GuestSession::COMGETTER(Processes)(ComSafeArrayOut(IGuestProcess *, aProcesses))
357{
358#ifndef VBOX_WITH_GUEST_CONTROL
359 ReturnComNotImplemented();
360#else
361 LogFlowThisFuncEnter();
362
363 CheckComArgOutSafeArrayPointerValid(aProcesses);
364
365 AutoCaller autoCaller(this);
366 if (FAILED(autoCaller.rc())) return autoCaller.rc();
367
368 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
369
370 SafeIfaceArray<IGuestProcess> collection(mData.mProcesses);
371 collection.detachTo(ComSafeArrayOutArg(aProcesses));
372
373 LogFlowFuncLeaveRC(S_OK);
374 return S_OK;
375#endif /* VBOX_WITH_GUEST_CONTROL */
376}
377
378STDMETHODIMP GuestSession::COMGETTER(Directories)(ComSafeArrayOut(IGuestDirectory *, aDirectories))
379{
380#ifndef VBOX_WITH_GUEST_CONTROL
381 ReturnComNotImplemented();
382#else
383 LogFlowThisFuncEnter();
384
385 CheckComArgOutSafeArrayPointerValid(aDirectories);
386
387 AutoCaller autoCaller(this);
388 if (FAILED(autoCaller.rc())) return autoCaller.rc();
389
390 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
391
392 SafeIfaceArray<IGuestDirectory> collection(mData.mDirectories);
393 collection.detachTo(ComSafeArrayOutArg(aDirectories));
394
395 LogFlowFuncLeaveRC(S_OK);
396 return S_OK;
397#endif /* VBOX_WITH_GUEST_CONTROL */
398}
399
400STDMETHODIMP GuestSession::COMGETTER(Files)(ComSafeArrayOut(IGuestFile *, aFiles))
401{
402#ifndef VBOX_WITH_GUEST_CONTROL
403 ReturnComNotImplemented();
404#else
405 LogFlowThisFuncEnter();
406
407 CheckComArgOutSafeArrayPointerValid(aFiles);
408
409 AutoCaller autoCaller(this);
410 if (FAILED(autoCaller.rc())) return autoCaller.rc();
411
412 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
413
414 SafeIfaceArray<IGuestFile> collection(mData.mFiles);
415 collection.detachTo(ComSafeArrayOutArg(aFiles));
416
417 LogFlowFuncLeaveRC(S_OK);
418 return S_OK;
419#endif /* VBOX_WITH_GUEST_CONTROL */
420}
421
422// private methods
423///////////////////////////////////////////////////////////////////////////////
424
425int GuestSession::closeSession(uint32_t uFlags, uint32_t uTimeoutMS, int *pGuestRc)
426{
427 LogFlowThisFunc(("uFlags=%x, uTimeoutMS=%RU32\n", uFlags, uTimeoutMS));
428
429 /* Legacy Guest Additions don't support opening dedicated
430 guest sessions. */
431 if (mData.mProtocolVersion < 2)
432 {
433 LogFlowThisFunc(("Installed Guest Additions don't support closing separate sessions\n"));
434 return VINF_SUCCESS;
435 }
436
437 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
438
439 /* Destroy a pending callback request. */
440 mData.mCallback.Destroy();
441
442 int vrc = mData.mCallback.Init(CALLBACKTYPE_SESSION_NOTIFY);
443
444 alock.release(); /* Drop the write lock again. */
445
446 if (RT_SUCCESS(vrc))
447 {
448 uint32_t uContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(mData.mId, 0 /* Object */, 0 /* Count */);
449
450 VBOXHGCMSVCPARM paParms[4];
451
452 int i = 0;
453 paParms[i++].setUInt32(uContextID);
454 paParms[i++].setUInt32(0 /* Flags, unused. */);
455
456 vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms);
457 }
458
459 if (RT_SUCCESS(vrc))
460 {
461 /*
462 * Let's wait for the process being started.
463 * Note: Be sure not keeping a AutoRead/WriteLock here.
464 */
465 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
466 vrc = mData.mCallback.Wait(uTimeoutMS);
467 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
468 {
469 int guestRc = mData.mCallback.GetResultCode();
470 if (pGuestRc)
471 *pGuestRc = guestRc;
472 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
473 }
474 else
475 vrc = VERR_TIMEOUT;
476 }
477
478 AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS);
479
480 mData.mCallback.Destroy();
481
482 LogFlowFuncLeaveRC(vrc);
483 return vrc;
484}
485
486int GuestSession::directoryRemoveFromList(GuestDirectory *pDirectory)
487{
488 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
489
490 for (SessionDirectories::iterator itDirs = mData.mDirectories.begin();
491 itDirs != mData.mDirectories.end(); ++itDirs)
492 {
493 if (pDirectory == (*itDirs))
494 {
495 Bstr strName;
496 HRESULT hr = (*itDirs)->COMGETTER(DirectoryName)(strName.asOutParam());
497 ComAssertComRC(hr);
498
499 Assert(mData.mDirectories.size());
500 LogFlowFunc(("Removing directory \"%s\" (Session: %RU32) (now total %ld directories)\n",
501 Utf8Str(strName).c_str(), mData.mId, mData.mDirectories.size() - 1));
502
503 mData.mDirectories.erase(itDirs);
504 return VINF_SUCCESS;
505 }
506 }
507
508 return VERR_NOT_FOUND;
509}
510
511int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags, int *pGuestRc)
512{
513 LogFlowThisFunc(("strPath=%s, uMode=%x, uFlags=%x\n",
514 strPath.c_str(), uMode, uFlags));
515
516 GuestProcessStartupInfo procInfo;
517 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
518 procInfo.mFlags = ProcessCreateFlag_Hidden;
519
520 int vrc = VINF_SUCCESS;
521
522 /* Construct arguments. */
523 if (uFlags & DirectoryCreateFlag_Parents)
524 procInfo.mArguments.push_back(Utf8Str("--parents")); /* We also want to create the parent directories. */
525 if (uMode)
526 {
527 procInfo.mArguments.push_back(Utf8Str("--mode")); /* Set the creation mode. */
528
529 char szMode[16];
530 if (RTStrPrintf(szMode, sizeof(szMode), "%o", uMode))
531 {
532 procInfo.mArguments.push_back(Utf8Str(szMode));
533 }
534 else
535 vrc = VERR_BUFFER_OVERFLOW;
536 }
537 procInfo.mArguments.push_back(strPath); /* The directory we want to create. */
538
539 if (RT_SUCCESS(vrc))
540 {
541 int guestRc;
542 GuestProcessTool procTool;
543 vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
544 if (RT_SUCCESS(vrc))
545 {
546 if (RT_SUCCESS(guestRc))
547 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
548 }
549
550 if (RT_SUCCESS(vrc))
551 {
552 if (RT_SUCCESS(guestRc))
553 guestRc = procTool.TerminatedOk(NULL /* Exit code */);
554 }
555
556 if (vrc == VERR_GENERAL_FAILURE) /** @todo Special guest control rc needed! */
557 *pGuestRc = guestRc;
558 }
559
560 LogFlowFuncLeaveRC(vrc);
561 return vrc;
562}
563
564int GuestSession::directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
565{
566 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
567
568 int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc);
569 if (RT_SUCCESS(vrc))
570 {
571 vrc = objData.mType == FsObjType_Directory
572 ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
573 }
574
575 LogFlowFuncLeaveRC(vrc);
576 return vrc;
577}
578
579int GuestSession::objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath,
580 bool fDirectory, const Utf8Str &strName, int *pGuestRc)
581{
582 GuestProcessStartupInfo procInfo;
583 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
584 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
585 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
586 if (fDirectory)
587 procInfo.mArguments.push_back(Utf8Str("-d"));
588 if (strPath.length()) /* Otherwise use /tmp or equivalent. */
589 {
590 procInfo.mArguments.push_back(Utf8Str("-t"));
591 procInfo.mArguments.push_back(strPath);
592 }
593 procInfo.mArguments.push_back(strTemplate);
594
595 GuestProcessTool procTool; int guestRc;
596 int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
597 if (RT_SUCCESS(vrc))
598 {
599 if (RT_SUCCESS(guestRc))
600 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
601 }
602
603 if (RT_SUCCESS(vrc))
604 {
605 if (RT_SUCCESS(guestRc))
606 guestRc = procTool.TerminatedOk(NULL /* Exit code */);
607 }
608
609 if ( vrc == VERR_GENERAL_FAILURE /** @todo Special guest control rc needed! */
610 && pGuestRc)
611 *pGuestRc = guestRc;
612
613 LogFlowFuncLeaveRC(vrc);
614 return vrc;
615}
616
617int GuestSession::directoryOpenInternal(const Utf8Str &strPath, const Utf8Str &strFilter,
618 uint32_t uFlags, ComObjPtr<GuestDirectory> &pDirectory)
619{
620 LogFlowThisFunc(("strPath=%s, strPath=%s, uFlags=%x\n",
621 strPath.c_str(), strFilter.c_str(), uFlags));
622
623 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
624
625 /* Create the directory object. */
626 HRESULT hr = pDirectory.createObject();
627 if (FAILED(hr))
628 return VERR_COM_UNEXPECTED;
629
630 int vrc = pDirectory->init(this /* Parent */,
631 strPath, strFilter, uFlags);
632 if (RT_FAILURE(vrc))
633 return vrc;
634
635 /* Add the created directory to our vector. */
636 mData.mDirectories.push_back(pDirectory);
637
638 LogFlowFunc(("Added new directory \"%s\" (Session: %RU32)\n",
639 strPath.c_str(), mData.mId));
640
641 LogFlowFuncLeaveRC(vrc);
642 return vrc;
643}
644
645int GuestSession::dispatchToFile(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
646{
647 LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
648
649 AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
650 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
651
652 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
653
654 uint32_t uFileID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID);
655#ifdef DEBUG
656 LogFlowFunc(("uFileID=%RU32 (%RU32 total)\n",
657 uFileID, mData.mFiles.size()));
658#endif
659 int rc;
660 SessionFiles::const_iterator itFile
661 = mData.mFiles.find(uFileID);
662 if (itFile != mData.mFiles.end())
663 {
664 ComObjPtr<GuestFile> pFile(itFile->second);
665 Assert(!pFile.isNull());
666
667 alock.release();
668
669 rc = pFile->callbackDispatcher(pCtxCb, pSvcCb);
670 }
671 else
672 rc = VERR_NOT_FOUND;
673
674 LogFlowFuncLeaveRC(rc);
675 return rc;
676}
677
678int GuestSession::dispatchToProcess(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
679{
680 LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
681
682 AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
683 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
684
685 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
686
687 uint32_t uProcessID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID);
688#ifdef DEBUG
689 LogFlowFunc(("uProcessID=%RU32 (%RU32 total)\n",
690 uProcessID, mData.mProcesses.size()));
691#endif
692 int rc;
693 SessionProcesses::const_iterator itProc
694 = mData.mProcesses.find(uProcessID);
695 if (itProc != mData.mProcesses.end())
696 {
697 ComObjPtr<GuestProcess> pProcess(itProc->second);
698 Assert(!pProcess.isNull());
699
700 /* Set protocol version so that pSvcCb can
701 * be interpreted right. */
702 pCtxCb->uProtocol = mData.mProtocolVersion;
703
704 alock.release();
705 rc = pProcess->callbackDispatcher(pCtxCb, pSvcCb);
706 }
707 else
708 rc = VERR_NOT_FOUND;
709
710 LogFlowFuncLeaveRC(rc);
711 return rc;
712}
713
714int GuestSession::dispatchToThis(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
715{
716 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
717 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
718
719 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
720
721#ifdef DEBUG
722 LogFlowThisFunc(("ID=%RU32, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
723 mData.mId, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
724#endif
725
726 int rc = VINF_SUCCESS;
727 switch (pCbCtx->uFunction)
728 {
729 case GUEST_SESSION_NOTIFY:
730 {
731 rc = onSessionStatusChange(pCbCtx,
732 &mData.mCallback, pSvcCb);
733 break;
734 }
735
736 default:
737 /* Silently skip unknown callbacks. */
738 break;
739 }
740
741 LogFlowFuncLeaveRC(rc);
742 return rc;
743}
744
745inline bool GuestSession::fileExists(uint32_t uFileID, ComObjPtr<GuestFile> *pFile)
746{
747 SessionFiles::const_iterator it = mData.mFiles.find(uFileID);
748 if (it != mData.mFiles.end())
749 {
750 if (pFile)
751 *pFile = it->second;
752 return true;
753 }
754 return false;
755}
756
757int GuestSession::fileRemoveFromList(GuestFile *pFile)
758{
759 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
760
761 for (SessionFiles::iterator itFiles = mData.mFiles.begin();
762 itFiles != mData.mFiles.end(); ++itFiles)
763 {
764 if (pFile == itFiles->second)
765 {
766 GuestFile *pThis = itFiles->second;
767 AssertPtr(pThis);
768
769 Bstr strName;
770 HRESULT hr = pThis->COMGETTER(FileName)(strName.asOutParam());
771 ComAssertComRC(hr);
772
773 Assert(mData.mNumObjects);
774 LogFlowThisFunc(("Removing file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n",
775 Utf8Str(strName).c_str(), mData.mId, mData.mFiles.size() - 1, mData.mNumObjects - 1));
776#ifdef DEBUG
777 ULONG cRefs = pFile->AddRef();
778 LogFlowThisFunc(("pObject=%p, cRefs=%RU32\n", pFile, cRefs));
779 pFile->Release();
780#endif
781 mData.mFiles.erase(itFiles);
782 mData.mNumObjects--;
783 return VINF_SUCCESS;
784 }
785 }
786
787 return VERR_NOT_FOUND;
788}
789
790int GuestSession::fileRemoveInternal(const Utf8Str &strPath, int *pGuestRc)
791{
792 GuestProcessStartupInfo procInfo;
793 GuestProcessStream streamOut;
794
795 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_RM);
796 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
797 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
798 procInfo.mArguments.push_back(strPath); /* The file we want to remove. */
799
800 GuestProcessTool procTool; int guestRc;
801 int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
802 if (RT_SUCCESS(vrc))
803 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
804
805 if (RT_SUCCESS(vrc))
806 {
807 if (RT_SUCCESS(guestRc))
808 guestRc = procTool.TerminatedOk(NULL /* Exit code */);
809 }
810
811 if ( vrc == VERR_GENERAL_FAILURE /** @todo Special guest control rc needed! */
812 && pGuestRc)
813 *pGuestRc = guestRc;
814
815 LogFlowFuncLeaveRC(vrc);
816 return vrc;
817}
818
819int GuestSession::fileOpenInternal(const GuestFileOpenInfo &openInfo, ComObjPtr<GuestFile> &pFile, int *pGuestRc)
820{
821 LogFlowThisFunc(("strPath=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%x, iOffset=%RI64\n",
822 openInfo.mFileName.c_str(), openInfo.mOpenMode.c_str(), openInfo.mDisposition.c_str(),
823 openInfo.mCreationMode, openInfo.mInitialOffset));
824
825 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
826
827 int rc = VERR_MAX_PROCS_REACHED;
828 if (mData.mNumObjects >= VBOX_GUESTCTRL_MAX_OBJECTS)
829 return rc;
830
831 /* Create a new (host-based) file ID and assign it. */
832 uint32_t uNewFileID = 0;
833 ULONG uTries = 0;
834
835 for (;;)
836 {
837 /* Is the file ID already used? */
838 if (!fileExists(uNewFileID, NULL /* pProgress */))
839 {
840 /* Callback with context ID was not found. This means
841 * we can use this context ID for our new callback we want
842 * to add below. */
843 rc = VINF_SUCCESS;
844 break;
845 }
846 uNewFileID++;
847 if (uNewFileID == VBOX_GUESTCTRL_MAX_OBJECTS)
848 uNewFileID = 0;
849
850 if (++uTries == UINT32_MAX)
851 break; /* Don't try too hard. */
852 }
853
854 if (RT_FAILURE(rc))
855 return rc;
856
857 /* Create the directory object. */
858 HRESULT hr = pFile.createObject();
859 if (FAILED(hr))
860 return VERR_COM_UNEXPECTED;
861
862 Console *pConsole = mData.mParent->getConsole();
863 AssertPtr(pConsole);
864
865 rc = pFile->init(pConsole, this /* GuestSession */,
866 uNewFileID, openInfo);
867 if (RT_FAILURE(rc))
868 return rc;
869
870 /* Add the created file to our vector. */
871 mData.mFiles[uNewFileID] = pFile;
872 mData.mNumObjects++;
873 Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS);
874
875 LogFlowFunc(("Added new file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n",
876 openInfo.mFileName.c_str(), mData.mId, mData.mFiles.size(), mData.mNumObjects));
877
878 LogFlowFuncLeaveRC(rc);
879 return rc;
880}
881
882int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
883{
884 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
885
886 int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc);
887 if (RT_SUCCESS(vrc))
888 {
889 vrc = objData.mType == FsObjType_File
890 ? VINF_SUCCESS : VERR_NOT_A_FILE;
891 }
892
893 LogFlowFuncLeaveRC(vrc);
894 return vrc;
895}
896
897int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize, int *pGuestRc)
898{
899 AssertPtrReturn(pllSize, VERR_INVALID_POINTER);
900
901 GuestFsObjData objData;
902 int vrc = fileQueryInfoInternal(strPath, objData, pGuestRc);
903 if (RT_SUCCESS(vrc))
904 *pllSize = objData.mObjectSize;
905
906 return vrc;
907}
908
909int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
910{
911 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
912
913 /** @todo Merge this with IGuestFile::queryInfo(). */
914 GuestProcessStartupInfo procInfo;
915 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT);
916 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
917
918 /* Construct arguments. */
919 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
920 procInfo.mArguments.push_back(strPath);
921
922 GuestProcessTool procTool; int guestRc;
923 int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
924 if (RT_SUCCESS(vrc))
925 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
926 if (RT_SUCCESS(vrc))
927 {
928 guestRc = procTool.TerminatedOk(NULL /* Exit code */);
929 if (RT_SUCCESS(guestRc))
930 {
931 GuestProcessStreamBlock curBlock;
932 vrc = procTool.GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, curBlock);
933 /** @todo Check for more / validate blocks! */
934 if (RT_SUCCESS(vrc))
935 vrc = objData.FromStat(curBlock);
936 }
937 }
938
939 if ( vrc == VERR_GENERAL_FAILURE /** @todo Special guest control rc needed! */
940 && pGuestRc)
941 *pGuestRc = guestRc;
942
943 LogFlowFuncLeaveRC(vrc);
944 return vrc;
945}
946
947const GuestCredentials& GuestSession::getCredentials(void)
948{
949 return mData.mCredentials;
950}
951
952const GuestEnvironment& GuestSession::getEnvironment(void)
953{
954 return mData.mEnvironment;
955}
956
957Utf8Str GuestSession::getName(void)
958{
959 return mData.mName;
960}
961
962/** No locking! */
963int GuestSession::onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
964 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
965{
966 /* pCallback is optional. */
967 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
968
969 if (pSvcCbData->mParms < 3)
970 return VERR_INVALID_PARAMETER;
971
972 CALLBACKDATA_SESSION_NOTIFY dataCb;
973 /* pSvcCb->mpaParms[0] always contains the context ID. */
974 pSvcCbData->mpaParms[1].getUInt32(&dataCb.uType);
975 pSvcCbData->mpaParms[2].getUInt32(&dataCb.uResult);
976
977 int rcCb = dataCb.uResult; /** @todo uint32_t vs. int. */
978
979 LogFlowThisFunc(("ID=%RU32, uType=%RU32, rc=%Rrc, pCallback=%p, pData=%p\n",
980 mData.mId, dataCb.uType, rcCb, pCallback, pSvcCbData));
981
982 int vrc = VINF_SUCCESS;
983
984 /*
985 * Now do the signalling stuff.
986 */
987 if (pCallback)
988 {
989 vrc = pCallback->SetData(&dataCb, sizeof(dataCb));
990
991 int rc2 = pCallback->Signal(rcCb);
992 if (RT_SUCCESS(vrc))
993 vrc = rc2;
994 }
995
996 LogFlowFuncLeaveRC(vrc);
997 return vrc;
998}
999
1000int GuestSession::openSession(uint32_t uFlags, uint32_t uTimeoutMS, int *pGuestRc)
1001{
1002 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1003
1004 LogFlowThisFunc(("uProtocolVersion=%RU32, uFlags=%x, uTimeoutMS=%RU32\n",
1005 mData.mProtocolVersion, uFlags, uTimeoutMS));
1006
1007 /* Legacy Guest Additions don't support opening dedicated
1008 guest sessions. */
1009 if (mData.mProtocolVersion < 2)
1010 {
1011 LogFlowThisFunc(("Installed Guest Additions don't support opening separate sessions\n"));
1012 return VINF_SUCCESS;
1013 }
1014
1015 /** @todo uFlags validation. */
1016
1017 /* Destroy a pending callback request. */
1018 mData.mCallback.Destroy();
1019
1020 int vrc = mData.mCallback.Init(CALLBACKTYPE_SESSION_NOTIFY);
1021
1022 alock.release(); /* Drop the write lock again. */
1023
1024 if (RT_SUCCESS(vrc))
1025 {
1026 uint32_t uContextID =
1027 VBOX_GUESTCTRL_CONTEXTID_MAKE(mData.mId, 0 /* Object */, 0 /* Count */);
1028
1029 VBOXHGCMSVCPARM paParms[8];
1030
1031 int i = 0;
1032 paParms[i++].setUInt32(uContextID);
1033 paParms[i++].setUInt32(mData.mProtocolVersion);
1034 paParms[i++].setPointer((void*)mData.mCredentials.mUser.c_str(),
1035 (ULONG)mData.mCredentials.mUser.length() + 1);
1036 paParms[i++].setPointer((void*)mData.mCredentials.mPassword.c_str(),
1037 (ULONG)mData.mCredentials.mPassword.length() + 1);
1038 paParms[i++].setPointer((void*)mData.mCredentials.mDomain.c_str(),
1039 (ULONG)mData.mCredentials.mDomain.length() + 1);
1040 paParms[i++].setUInt32(uFlags);
1041
1042 vrc = sendCommand(HOST_SESSION_CREATE, i, paParms);
1043 }
1044
1045 if (RT_SUCCESS(vrc))
1046 {
1047 /*
1048 * Let's wait for the process being started.
1049 * Note: Be sure not keeping a AutoRead/WriteLock here.
1050 */
1051 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
1052 vrc = mData.mCallback.Wait(uTimeoutMS);
1053 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
1054 {
1055 int guestRc = mData.mCallback.GetResultCode();
1056 if (pGuestRc)
1057 *pGuestRc = guestRc;
1058 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
1059 }
1060 else
1061 vrc = VERR_TIMEOUT;
1062 }
1063
1064 AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS);
1065
1066 /* Destroy callback. */
1067 mData.mCallback.Destroy();
1068
1069 LogFlowFuncLeaveRC(vrc);
1070 return vrc;
1071}
1072
1073int GuestSession::processRemoveFromList(GuestProcess *pProcess)
1074{
1075 LogFlowThisFuncEnter();
1076
1077 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1078
1079 int rc = VERR_NOT_FOUND;
1080
1081 ULONG uPID;
1082 HRESULT hr = pProcess->COMGETTER(PID)(&uPID);
1083
1084 LogFlowFunc(("Closing process (PID=%RU32) ...\n", uPID));
1085
1086 for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();
1087 itProcs != mData.mProcesses.end(); ++itProcs)
1088 {
1089 if (pProcess == itProcs->second)
1090 {
1091 GuestProcess *pCurProc = itProcs->second;
1092 AssertPtr(pCurProc);
1093
1094 hr = pCurProc->COMGETTER(PID)(&uPID);
1095 ComAssertComRC(hr);
1096
1097 Assert(mData.mNumObjects);
1098 LogFlowFunc(("Removing process (Session: %RU32) with process ID=%RU32, guest PID=%RU32 (now total %ld processes, %ld objects)\n",
1099 mData.mId, pCurProc->getObjectID(), uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1));
1100
1101 mData.mProcesses.erase(itProcs);
1102 mData.mNumObjects--;
1103
1104 rc = VINF_SUCCESS;
1105 break;
1106 }
1107 }
1108
1109 LogFlowFuncLeaveRC(rc);
1110 return rc;
1111}
1112
1113/**
1114 * Creates but does *not* start the process yet. See GuestProcess::startProcess() or
1115 * GuestProcess::startProcessAsync() for that.
1116 *
1117 * @return IPRT status code.
1118 * @param procInfo
1119 * @param pProcess
1120 */
1121int GuestSession::processCreateExInteral(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
1122{
1123 LogFlowFunc(("mCmd=%s, mFlags=%x, mTimeoutMS=%RU32\n",
1124 procInfo.mCommand.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));
1125#ifdef DEBUG
1126 if (procInfo.mArguments.size())
1127 {
1128 LogFlowFunc(("Arguments:"));
1129 ProcessArguments::const_iterator it = procInfo.mArguments.begin();
1130 while (it != procInfo.mArguments.end())
1131 {
1132 LogFlow((" %s", (*it).c_str()));
1133 it++;
1134 }
1135 LogFlow(("\n"));
1136 }
1137#endif
1138
1139 /* Validate flags. */
1140 if (procInfo.mFlags)
1141 {
1142 if ( !(procInfo.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
1143 && !(procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1144 && !(procInfo.mFlags & ProcessCreateFlag_Hidden)
1145 && !(procInfo.mFlags & ProcessCreateFlag_NoProfile)
1146 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1147 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdErr))
1148 {
1149 return VERR_INVALID_PARAMETER;
1150 }
1151 }
1152
1153 if ( (procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1154 && ( (procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1155 || (procInfo.mFlags & ProcessCreateFlag_WaitForStdErr)
1156 )
1157 )
1158 {
1159 return VERR_INVALID_PARAMETER;
1160 }
1161
1162 /* Adjust timeout. If set to 0, we define
1163 * an infinite timeout. */
1164 if (procInfo.mTimeoutMS == 0)
1165 procInfo.mTimeoutMS = UINT32_MAX;
1166
1167 /** @tood Implement process priority + affinity. */
1168
1169 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1170
1171 int rc = VERR_MAX_PROCS_REACHED;
1172 if (mData.mNumObjects >= VBOX_GUESTCTRL_MAX_OBJECTS)
1173 return rc;
1174
1175 /* Create a new (host-based) process ID and assign it. */
1176 uint32_t uNewProcessID = 0;
1177 ULONG uTries = 0;
1178
1179 for (;;)
1180 {
1181 /* Is the context ID already used? */
1182 if (!processExists(uNewProcessID, NULL /* pProgress */))
1183 {
1184 /* Callback with context ID was not found. This means
1185 * we can use this context ID for our new callback we want
1186 * to add below. */
1187 rc = VINF_SUCCESS;
1188 break;
1189 }
1190 uNewProcessID++;
1191 if (uNewProcessID == VBOX_GUESTCTRL_MAX_OBJECTS)
1192 uNewProcessID = 0;
1193
1194 if (++uTries == UINT32_MAX)
1195 break; /* Don't try too hard. */
1196 }
1197
1198 if (RT_FAILURE(rc))
1199 return rc;
1200
1201 /* Create the process object. */
1202 HRESULT hr = pProcess.createObject();
1203 if (FAILED(hr))
1204 return VERR_COM_UNEXPECTED;
1205
1206 rc = pProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */,
1207 uNewProcessID, procInfo);
1208 if (RT_FAILURE(rc))
1209 return rc;
1210
1211 /* Add the created process to our map. */
1212 mData.mProcesses[uNewProcessID] = pProcess;
1213 mData.mNumObjects++;
1214 Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS);
1215
1216 LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes, %ld objects)\n",
1217 mData.mId, uNewProcessID, mData.mProcesses.size(), mData.mNumObjects));
1218
1219 return rc;
1220}
1221
1222inline bool GuestSession::processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess)
1223{
1224 SessionProcesses::const_iterator it = mData.mProcesses.find(uProcessID);
1225 if (it != mData.mProcesses.end())
1226 {
1227 if (pProcess)
1228 *pProcess = it->second;
1229 return true;
1230 }
1231 return false;
1232}
1233
1234inline int GuestSession::processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess)
1235{
1236 AssertReturn(uPID, false);
1237 /* pProcess is optional. */
1238
1239 SessionProcesses::iterator itProcs = mData.mProcesses.begin();
1240 for (; itProcs != mData.mProcesses.end(); itProcs++)
1241 {
1242 ComObjPtr<GuestProcess> pCurProc = itProcs->second;
1243 AutoCaller procCaller(pCurProc);
1244 if (procCaller.rc())
1245 return VERR_COM_INVALID_OBJECT_STATE;
1246
1247 ULONG uCurPID;
1248 HRESULT hr = pCurProc->COMGETTER(PID)(&uCurPID);
1249 ComAssertComRC(hr);
1250
1251 if (uCurPID == uPID)
1252 {
1253 if (pProcess)
1254 *pProcess = pCurProc;
1255 return VINF_SUCCESS;
1256 }
1257 }
1258
1259 return VERR_NOT_FOUND;
1260}
1261
1262int GuestSession::sendCommand(uint32_t uFunction,
1263 uint32_t uParms, PVBOXHGCMSVCPARM paParms)
1264{
1265 LogFlowThisFuncEnter();
1266
1267#ifndef VBOX_GUESTCTRL_TEST_CASE
1268 ComObjPtr<Console> pConsole = mData.mParent->getConsole();
1269 Assert(!pConsole.isNull());
1270
1271 /* Forward the information to the VMM device. */
1272 VMMDev *pVMMDev = pConsole->getVMMDev();
1273 AssertPtr(pVMMDev);
1274
1275 LogFlowThisFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms));
1276 int vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, uParms, paParms);
1277 if (RT_FAILURE(vrc))
1278 {
1279 /** @todo What to do here? */
1280 }
1281#else
1282 /* Not needed within testcases. */
1283 int vrc = VINF_SUCCESS;
1284#endif
1285 LogFlowFuncLeaveRC(vrc);
1286 return vrc;
1287}
1288
1289int GuestSession::startTaskAsync(const Utf8Str &strTaskDesc,
1290 GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress)
1291{
1292 LogFlowThisFunc(("strTaskDesc=%s, pTask=%p\n", strTaskDesc.c_str(), pTask));
1293
1294 AssertPtrReturn(pTask, VERR_INVALID_POINTER);
1295
1296 /* Create the progress object. */
1297 HRESULT hr = pProgress.createObject();
1298 if (FAILED(hr))
1299 return VERR_COM_UNEXPECTED;
1300
1301 hr = pProgress->init(static_cast<IGuestSession*>(this),
1302 Bstr(strTaskDesc).raw(),
1303 TRUE /* aCancelable */);
1304 if (FAILED(hr))
1305 return VERR_COM_UNEXPECTED;
1306
1307 /* Initialize our worker task. */
1308 std::auto_ptr<GuestSessionTask> task(pTask);
1309
1310 int rc = task->RunAsync(strTaskDesc, pProgress);
1311 if (RT_FAILURE(rc))
1312 return rc;
1313
1314 /* Don't destruct on success. */
1315 task.release();
1316
1317 LogFlowFuncLeaveRC(rc);
1318 return rc;
1319}
1320
1321/**
1322 * Queries/collects information prior to establishing a guest session.
1323 * This is necessary to know which guest control protocol version to use,
1324 * among other things (later).
1325 *
1326 * @return IPRT status code.
1327 */
1328int GuestSession::queryInfo(void)
1329{
1330#if 1
1331 /* Since the new functions were not implemented yet, force Main to use protocol ver 1. */
1332 mData.mProtocolVersion = 2;
1333#else
1334 /*
1335 * Try querying the guest control protocol version running on the guest.
1336 * This is done using the Guest Additions version
1337 */
1338 ComObjPtr<Guest> pGuest = mData.mParent;
1339 Assert(!pGuest.isNull());
1340
1341 uint32_t uVerAdditions = pGuest->getAdditionsVersion();
1342 mData.mProtocolVersion = ( VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions) >= 4
1343 && VBOX_FULL_VERSION_GET_MINOR(uVerAdditions) >= 3) /** @todo What's about v5.0 ? */
1344 ? 2 /* Guest control 2.0. */
1345 : 1; /* Legacy guest control (VBox < 4.3). */
1346 /* Build revision is ignored. */
1347
1348 /* Tell the user but don't bitch too often. */
1349 static short s_gctrlLegacyWarning = 0;
1350 if (s_gctrlLegacyWarning++ < 3) /** @todo Find a bit nicer text. */
1351 LogRel((tr("Warning: Guest Additions are older (%ld.%ld) than host capabilities for guest control, please upgrade them. Using protocol version %ld now\n"),
1352 VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions), VBOX_FULL_VERSION_GET_MINOR(uVerAdditions), mData.mProtocolVersion));
1353#endif
1354 return VINF_SUCCESS;
1355}
1356
1357// implementation of public methods
1358/////////////////////////////////////////////////////////////////////////////
1359
1360STDMETHODIMP GuestSession::Close(void)
1361{
1362#ifndef VBOX_WITH_GUEST_CONTROL
1363 ReturnComNotImplemented();
1364#else
1365 LogFlowThisFuncEnter();
1366
1367 AutoCaller autoCaller(this);
1368 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1369
1370 /* Close session on guest session. */
1371 int guestRc;
1372 int rc = closeSession(0 /* Flags */, 30 * 1000 /* Timeout */,
1373 &guestRc);
1374 if (RT_FAILURE(rc))
1375 {
1376
1377 }
1378
1379 /* Remove ourselves from the session list. */
1380 mData.mParent->sessionRemove(this);
1381
1382 /*
1383 * Release autocaller before calling uninit.
1384 */
1385 autoCaller.release();
1386
1387 uninit();
1388
1389 LogFlowFuncLeave();
1390 return S_OK;
1391#endif /* VBOX_WITH_GUEST_CONTROL */
1392}
1393
1394STDMETHODIMP GuestSession::CopyFrom(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
1395{
1396#ifndef VBOX_WITH_GUEST_CONTROL
1397 ReturnComNotImplemented();
1398#else
1399 CheckComArgStrNotEmptyOrNull(aSource);
1400 CheckComArgStrNotEmptyOrNull(aDest);
1401 CheckComArgOutPointerValid(aProgress);
1402
1403 LogFlowThisFuncEnter();
1404
1405 if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
1406 return setError(E_INVALIDARG, tr("No source specified"));
1407 if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
1408 return setError(E_INVALIDARG, tr("No destination specified"));
1409
1410 AutoCaller autoCaller(this);
1411 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1412
1413 uint32_t fFlags = CopyFileFlag_None;
1414 if (aFlags)
1415 {
1416 com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
1417 for (size_t i = 0; i < flags.size(); i++)
1418 fFlags |= flags[i];
1419 }
1420
1421 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1422
1423 HRESULT hr = S_OK;
1424
1425 try
1426 {
1427 ComObjPtr<Progress> pProgress;
1428 SessionTaskCopyFrom *pTask = new SessionTaskCopyFrom(this /* GuestSession */,
1429 Utf8Str(aSource), Utf8Str(aDest), fFlags);
1430 int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from guest to \"%ls\" on the host"), aSource, aDest),
1431 pTask, pProgress);
1432 if (RT_SUCCESS(rc))
1433 {
1434 /* Return progress to the caller. */
1435 hr = pProgress.queryInterfaceTo(aProgress);
1436 }
1437 else
1438 hr = setError(VBOX_E_IPRT_ERROR,
1439 tr("Starting task for copying file \"%ls\" from guest to \"%ls\" on the host failed: %Rrc"), rc);
1440 }
1441 catch(std::bad_alloc &)
1442 {
1443 hr = E_OUTOFMEMORY;
1444 }
1445
1446 return hr;
1447#endif /* VBOX_WITH_GUEST_CONTROL */
1448}
1449
1450STDMETHODIMP GuestSession::CopyTo(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
1451{
1452#ifndef VBOX_WITH_GUEST_CONTROL
1453 ReturnComNotImplemented();
1454#else
1455 CheckComArgStrNotEmptyOrNull(aSource);
1456 CheckComArgStrNotEmptyOrNull(aDest);
1457 CheckComArgOutPointerValid(aProgress);
1458
1459 LogFlowThisFuncEnter();
1460
1461 if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
1462 return setError(E_INVALIDARG, tr("No source specified"));
1463 if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
1464 return setError(E_INVALIDARG, tr("No destination specified"));
1465
1466 AutoCaller autoCaller(this);
1467 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1468
1469 uint32_t fFlags = CopyFileFlag_None;
1470 if (aFlags)
1471 {
1472 com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
1473 for (size_t i = 0; i < flags.size(); i++)
1474 fFlags |= flags[i];
1475 }
1476
1477 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1478
1479 HRESULT hr = S_OK;
1480
1481 try
1482 {
1483 ComObjPtr<Progress> pProgress;
1484 SessionTaskCopyTo *pTask = new SessionTaskCopyTo(this /* GuestSession */,
1485 Utf8Str(aSource), Utf8Str(aDest), fFlags);
1486 AssertPtrReturn(pTask, E_OUTOFMEMORY);
1487 int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from host to \"%ls\" on the guest"), aSource, aDest),
1488 pTask, pProgress);
1489 if (RT_SUCCESS(rc))
1490 {
1491 /* Return progress to the caller. */
1492 hr = pProgress.queryInterfaceTo(aProgress);
1493 }
1494 else
1495 hr = setError(VBOX_E_IPRT_ERROR,
1496 tr("Starting task for copying file \"%ls\" from host to \"%ls\" on the guest failed: %Rrc"), rc);
1497 }
1498 catch(std::bad_alloc &)
1499 {
1500 hr = E_OUTOFMEMORY;
1501 }
1502
1503 return hr;
1504#endif /* VBOX_WITH_GUEST_CONTROL */
1505}
1506
1507STDMETHODIMP GuestSession::DirectoryCreate(IN_BSTR aPath, ULONG aMode,
1508 ComSafeArrayIn(DirectoryCreateFlag_T, aFlags))
1509{
1510#ifndef VBOX_WITH_GUEST_CONTROL
1511 ReturnComNotImplemented();
1512#else
1513 LogFlowThisFuncEnter();
1514
1515 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1516 return setError(E_INVALIDARG, tr("No directory to create specified"));
1517
1518 AutoCaller autoCaller(this);
1519 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1520
1521 uint32_t fFlags = DirectoryCreateFlag_None;
1522 if (aFlags)
1523 {
1524 com::SafeArray<DirectoryCreateFlag_T> flags(ComSafeArrayInArg(aFlags));
1525 for (size_t i = 0; i < flags.size(); i++)
1526 fFlags |= flags[i];
1527
1528 if (fFlags)
1529 {
1530 if (!(fFlags & DirectoryCreateFlag_Parents))
1531 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), fFlags);
1532 }
1533 }
1534
1535 HRESULT hr = S_OK;
1536
1537 ComObjPtr <GuestDirectory> pDirectory; int guestRc;
1538 int rc = directoryCreateInternal(Utf8Str(aPath), (uint32_t)aMode, fFlags, &guestRc);
1539 if (RT_FAILURE(rc))
1540 {
1541 switch (rc)
1542 {
1543 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
1544 hr = GuestProcess::setErrorExternal(this, guestRc);
1545 break;
1546
1547 case VERR_INVALID_PARAMETER:
1548 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Invalid parameters given"));
1549 break;
1550
1551 case VERR_BROKEN_PIPE:
1552 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Unexpectedly aborted"));
1553 break;
1554
1555 case VERR_CANT_CREATE:
1556 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Could not create directory"));
1557 break;
1558
1559 default:
1560 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
1561 break;
1562 }
1563 }
1564
1565 return hr;
1566#endif /* VBOX_WITH_GUEST_CONTROL */
1567}
1568
1569STDMETHODIMP GuestSession::DirectoryCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, BSTR *aDirectory)
1570{
1571#ifndef VBOX_WITH_GUEST_CONTROL
1572 ReturnComNotImplemented();
1573#else
1574 LogFlowThisFuncEnter();
1575
1576 if (RT_UNLIKELY((aTemplate) == NULL || *(aTemplate) == '\0'))
1577 return setError(E_INVALIDARG, tr("No template specified"));
1578 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1579 return setError(E_INVALIDARG, tr("No directory name specified"));
1580 CheckComArgOutPointerValid(aDirectory);
1581
1582 AutoCaller autoCaller(this);
1583 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1584
1585 HRESULT hr = S_OK;
1586
1587 Utf8Str strName; int guestRc;
1588 int rc = objectCreateTempInternal(Utf8Str(aTemplate),
1589 Utf8Str(aPath),
1590 true /* Directory */, strName, &guestRc);
1591 if (RT_SUCCESS(rc))
1592 {
1593 strName.cloneTo(aDirectory);
1594 }
1595 else
1596 {
1597 switch (rc)
1598 {
1599 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
1600 hr = GuestProcess::setErrorExternal(this, guestRc);
1601 break;
1602
1603 default:
1604 hr = setError(VBOX_E_IPRT_ERROR, tr("Temporary directory creation \"%s\" with template \"%s\" failed: %Rrc"),
1605 Utf8Str(aPath).c_str(), Utf8Str(aTemplate).c_str(), rc);
1606 break;
1607 }
1608 }
1609
1610 return hr;
1611#endif /* VBOX_WITH_GUEST_CONTROL */
1612}
1613
1614STDMETHODIMP GuestSession::DirectoryExists(IN_BSTR aPath, BOOL *aExists)
1615{
1616#ifndef VBOX_WITH_GUEST_CONTROL
1617 ReturnComNotImplemented();
1618#else
1619 LogFlowThisFuncEnter();
1620
1621 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1622 return setError(E_INVALIDARG, tr("No directory to check existence for specified"));
1623 CheckComArgOutPointerValid(aExists);
1624
1625 AutoCaller autoCaller(this);
1626 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1627
1628 HRESULT hr = S_OK;
1629
1630 GuestFsObjData objData; int guestRc;
1631 int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
1632 if (RT_SUCCESS(rc))
1633 {
1634 *aExists = objData.mType == FsObjType_Directory;
1635 }
1636 else
1637 {
1638 switch (rc)
1639 {
1640 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
1641 hr = GuestProcess::setErrorExternal(this, guestRc);
1642 break;
1643
1644 default:
1645 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence \"%s\" failed: %Rrc"),
1646 Utf8Str(aPath).c_str(), rc);
1647 break;
1648 }
1649 }
1650
1651 return hr;
1652#endif /* VBOX_WITH_GUEST_CONTROL */
1653}
1654
1655STDMETHODIMP GuestSession::DirectoryOpen(IN_BSTR aPath, IN_BSTR aFilter, ComSafeArrayIn(DirectoryOpenFlag_T, aFlags), IGuestDirectory **aDirectory)
1656{
1657#ifndef VBOX_WITH_GUEST_CONTROL
1658 ReturnComNotImplemented();
1659#else
1660 LogFlowThisFuncEnter();
1661
1662 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1663 return setError(E_INVALIDARG, tr("No directory to open specified"));
1664 if (RT_UNLIKELY((aFilter) != NULL && *(aFilter) != '\0'))
1665 return setError(E_INVALIDARG, tr("Directory filters are not implemented yet"));
1666 CheckComArgOutPointerValid(aDirectory);
1667
1668 AutoCaller autoCaller(this);
1669 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1670
1671 uint32_t fFlags = DirectoryOpenFlag_None;
1672 if (aFlags)
1673 {
1674 com::SafeArray<DirectoryOpenFlag_T> flags(ComSafeArrayInArg(aFlags));
1675 for (size_t i = 0; i < flags.size(); i++)
1676 fFlags |= flags[i];
1677
1678 if (fFlags)
1679 return setError(E_INVALIDARG, tr("Open flags (%#x) not implemented yet"), fFlags);
1680 }
1681
1682 HRESULT hr = S_OK;
1683
1684 ComObjPtr <GuestDirectory> pDirectory;
1685 int rc = directoryOpenInternal(Utf8Str(aPath), Utf8Str(aFilter), fFlags, pDirectory);
1686 if (RT_SUCCESS(rc))
1687 {
1688 /* Return directory object to the caller. */
1689 hr = pDirectory.queryInterfaceTo(aDirectory);
1690 }
1691 else
1692 {
1693 switch (rc)
1694 {
1695 case VERR_INVALID_PARAMETER:
1696 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed; invalid parameters given",
1697 Utf8Str(aPath).c_str()));
1698 break;
1699
1700 default:
1701 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed: %Rrc"),
1702 Utf8Str(aPath).c_str(),rc);
1703 break;
1704 }
1705 }
1706
1707 return hr;
1708#endif /* VBOX_WITH_GUEST_CONTROL */
1709}
1710
1711STDMETHODIMP GuestSession::DirectoryQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
1712{
1713#ifndef VBOX_WITH_GUEST_CONTROL
1714 ReturnComNotImplemented();
1715#else
1716 LogFlowThisFuncEnter();
1717
1718 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1719 return setError(E_INVALIDARG, tr("No directory to query information for specified"));
1720 CheckComArgOutPointerValid(aInfo);
1721
1722 AutoCaller autoCaller(this);
1723 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1724
1725 HRESULT hr = S_OK;
1726
1727 GuestFsObjData objData; int guestRc;
1728 int vrc = directoryQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
1729 if (RT_SUCCESS(vrc))
1730 {
1731 if (objData.mType == FsObjType_Directory)
1732 {
1733 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
1734 hr = pFsObjInfo.createObject();
1735 if (FAILED(hr)) return hr;
1736
1737 vrc = pFsObjInfo->init(objData);
1738 if (RT_SUCCESS(vrc))
1739 {
1740 hr = pFsObjInfo.queryInterfaceTo(aInfo);
1741 if (FAILED(hr)) return hr;
1742 }
1743 }
1744 }
1745
1746 if (RT_FAILURE(vrc))
1747 {
1748 switch (vrc)
1749 {
1750 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
1751 hr = GuestProcess::setErrorExternal(this, guestRc);
1752 break;
1753
1754 case VERR_NOT_A_DIRECTORY:
1755 hr = setError(VBOX_E_IPRT_ERROR, tr("Element \"%s\" exists but is not a directory",
1756 Utf8Str(aPath).c_str()));
1757 break;
1758
1759 default:
1760 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information for \"%s\" failed: %Rrc"),
1761 Utf8Str(aPath).c_str(), vrc);
1762 break;
1763 }
1764 }
1765
1766 return hr;
1767#endif /* VBOX_WITH_GUEST_CONTROL */
1768}
1769
1770STDMETHODIMP GuestSession::DirectoryRemove(IN_BSTR aPath)
1771{
1772#ifndef VBOX_WITH_GUEST_CONTROL
1773 ReturnComNotImplemented();
1774#else
1775 LogFlowThisFuncEnter();
1776
1777 AutoCaller autoCaller(this);
1778 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1779
1780 ReturnComNotImplemented();
1781#endif /* VBOX_WITH_GUEST_CONTROL */
1782}
1783
1784STDMETHODIMP GuestSession::DirectoryRemoveRecursive(IN_BSTR aPath, ComSafeArrayIn(DirectoryRemoveRecFlag_T, aFlags), IProgress **aProgress)
1785{
1786#ifndef VBOX_WITH_GUEST_CONTROL
1787 ReturnComNotImplemented();
1788#else
1789 LogFlowThisFuncEnter();
1790
1791 AutoCaller autoCaller(this);
1792 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1793
1794 ReturnComNotImplemented();
1795#endif /* VBOX_WITH_GUEST_CONTROL */
1796}
1797
1798STDMETHODIMP GuestSession::DirectoryRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
1799{
1800#ifndef VBOX_WITH_GUEST_CONTROL
1801 ReturnComNotImplemented();
1802#else
1803 LogFlowThisFuncEnter();
1804
1805 AutoCaller autoCaller(this);
1806 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1807
1808 ReturnComNotImplemented();
1809#endif /* VBOX_WITH_GUEST_CONTROL */
1810}
1811
1812STDMETHODIMP GuestSession::DirectorySetACL(IN_BSTR aPath, IN_BSTR aACL)
1813{
1814#ifndef VBOX_WITH_GUEST_CONTROL
1815 ReturnComNotImplemented();
1816#else
1817 LogFlowThisFuncEnter();
1818
1819 AutoCaller autoCaller(this);
1820 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1821
1822 ReturnComNotImplemented();
1823#endif /* VBOX_WITH_GUEST_CONTROL */
1824}
1825
1826STDMETHODIMP GuestSession::EnvironmentClear(void)
1827{
1828#ifndef VBOX_WITH_GUEST_CONTROL
1829 ReturnComNotImplemented();
1830#else
1831 LogFlowThisFuncEnter();
1832
1833 AutoCaller autoCaller(this);
1834 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1835
1836 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1837
1838 mData.mEnvironment.Clear();
1839
1840 LogFlowFuncLeaveRC(S_OK);
1841 return S_OK;
1842#endif /* VBOX_WITH_GUEST_CONTROL */
1843}
1844
1845STDMETHODIMP GuestSession::EnvironmentGet(IN_BSTR aName, BSTR *aValue)
1846{
1847#ifndef VBOX_WITH_GUEST_CONTROL
1848 ReturnComNotImplemented();
1849#else
1850 LogFlowThisFuncEnter();
1851
1852 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
1853 return setError(E_INVALIDARG, tr("No value name specified"));
1854
1855 CheckComArgOutPointerValid(aValue);
1856
1857 AutoCaller autoCaller(this);
1858 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1859
1860 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1861
1862 Bstr strValue(mData.mEnvironment.Get(Utf8Str(aName)));
1863 strValue.cloneTo(aValue);
1864
1865 LogFlowFuncLeaveRC(S_OK);
1866 return S_OK;
1867#endif /* VBOX_WITH_GUEST_CONTROL */
1868}
1869
1870STDMETHODIMP GuestSession::EnvironmentSet(IN_BSTR aName, IN_BSTR aValue)
1871{
1872#ifndef VBOX_WITH_GUEST_CONTROL
1873 ReturnComNotImplemented();
1874#else
1875 LogFlowThisFuncEnter();
1876
1877 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
1878 return setError(E_INVALIDARG, tr("No value name specified"));
1879
1880 AutoCaller autoCaller(this);
1881 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1882
1883 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1884
1885 int rc = mData.mEnvironment.Set(Utf8Str(aName), Utf8Str(aValue));
1886
1887 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
1888 LogFlowFuncLeaveRC(hr);
1889 return hr;
1890#endif /* VBOX_WITH_GUEST_CONTROL */
1891}
1892
1893STDMETHODIMP GuestSession::EnvironmentUnset(IN_BSTR aName)
1894{
1895#ifndef VBOX_WITH_GUEST_CONTROL
1896 ReturnComNotImplemented();
1897#else
1898 LogFlowThisFuncEnter();
1899
1900 AutoCaller autoCaller(this);
1901 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1902
1903 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1904
1905 mData.mEnvironment.Unset(Utf8Str(aName));
1906
1907 LogFlowFuncLeaveRC(S_OK);
1908 return S_OK;
1909#endif /* VBOX_WITH_GUEST_CONTROL */
1910}
1911
1912STDMETHODIMP GuestSession::FileCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, IGuestFile **aFile)
1913{
1914#ifndef VBOX_WITH_GUEST_CONTROL
1915 ReturnComNotImplemented();
1916#else
1917 LogFlowThisFuncEnter();
1918
1919 AutoCaller autoCaller(this);
1920 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1921
1922 ReturnComNotImplemented();
1923#endif /* VBOX_WITH_GUEST_CONTROL */
1924}
1925
1926STDMETHODIMP GuestSession::FileExists(IN_BSTR aPath, BOOL *aExists)
1927{
1928#ifndef VBOX_WITH_GUEST_CONTROL
1929 ReturnComNotImplemented();
1930#else
1931 LogFlowThisFuncEnter();
1932
1933 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1934 return setError(E_INVALIDARG, tr("No file to check existence for specified"));
1935 CheckComArgOutPointerValid(aExists);
1936
1937 AutoCaller autoCaller(this);
1938 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1939
1940 GuestFsObjData objData; int guestRc;
1941 int vrc = fileQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
1942 if (RT_SUCCESS(vrc))
1943 {
1944 *aExists = TRUE;
1945 return S_OK;
1946 }
1947
1948 HRESULT hr = S_OK;
1949
1950 switch (vrc)
1951 {
1952 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
1953 hr = GuestProcess::setErrorExternal(this, guestRc);
1954 break;
1955
1956 case VERR_NOT_A_FILE:
1957 *aExists = FALSE;
1958 break;
1959
1960 default:
1961 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information for \"%s\" failed: %Rrc"),
1962 Utf8Str(aPath).c_str(), vrc);
1963 break;
1964 }
1965
1966 return hr;
1967#endif /* VBOX_WITH_GUEST_CONTROL */
1968}
1969
1970STDMETHODIMP GuestSession::FileRemove(IN_BSTR aPath)
1971{
1972#ifndef VBOX_WITH_GUEST_CONTROL
1973 ReturnComNotImplemented();
1974#else
1975 LogFlowThisFuncEnter();
1976
1977 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1978 return setError(E_INVALIDARG, tr("No file to remove specified"));
1979
1980 AutoCaller autoCaller(this);
1981 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1982
1983 HRESULT hr = S_OK;
1984
1985 int guestRc;
1986 int vrc = fileRemoveInternal(Utf8Str(aPath), &guestRc);
1987 if (RT_FAILURE(vrc))
1988 {
1989 switch (vrc)
1990 {
1991 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
1992 hr = GuestProcess::setErrorExternal(this, guestRc);
1993 break;
1994
1995 default:
1996 hr = setError(VBOX_E_IPRT_ERROR, tr("Removing file \"%s\" failed: %Rrc"),
1997 Utf8Str(aPath).c_str(), vrc);
1998 break;
1999 }
2000 }
2001
2002 return hr;
2003#endif /* VBOX_WITH_GUEST_CONTROL */
2004}
2005
2006STDMETHODIMP GuestSession::FileOpen(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, ULONG aCreationMode, LONG64 aOffset, IGuestFile **aFile)
2007{
2008#ifndef VBOX_WITH_GUEST_CONTROL
2009 ReturnComNotImplemented();
2010#else
2011 LogFlowThisFuncEnter();
2012
2013 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2014 return setError(E_INVALIDARG, tr("No file to open specified"));
2015 if (RT_UNLIKELY((aOpenMode) == NULL || *(aOpenMode) == '\0'))
2016 return setError(E_INVALIDARG, tr("No open mode specified"));
2017 if (RT_UNLIKELY((aDisposition) == NULL || *(aDisposition) == '\0'))
2018 return setError(E_INVALIDARG, tr("No disposition mode specified"));
2019
2020 CheckComArgOutPointerValid(aFile);
2021
2022 AutoCaller autoCaller(this);
2023 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2024
2025 /** @todo Validate open mode. */
2026 /** @todo Validate disposition mode. */
2027
2028 /** @todo Validate creation mode. */
2029 uint32_t uCreationMode = 0;
2030
2031 HRESULT hr = S_OK;
2032
2033 GuestFileOpenInfo openInfo;
2034 openInfo.mFileName = Utf8Str(aPath);
2035 openInfo.mOpenMode = Utf8Str(aOpenMode);
2036 openInfo.mDisposition = Utf8Str(aDisposition);
2037 openInfo.mCreationMode = aCreationMode;
2038 openInfo.mInitialOffset = aOffset;
2039
2040 ComObjPtr <GuestFile> pFile; int guestRc;
2041 int vrc = fileOpenInternal(openInfo, pFile, &guestRc);
2042 if (RT_SUCCESS(vrc))
2043 {
2044 /* Return directory object to the caller. */
2045 hr = pFile.queryInterfaceTo(aFile);
2046 }
2047 else
2048 {
2049 switch (vrc)
2050 {
2051 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
2052 hr = GuestProcess::setErrorExternal(this, guestRc);
2053 break;
2054
2055 default:
2056 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening file \"%s\" failed: %Rrc"),
2057 Utf8Str(aPath).c_str(), vrc);
2058 break;
2059 }
2060 }
2061
2062 return hr;
2063#endif /* VBOX_WITH_GUEST_CONTROL */
2064}
2065
2066STDMETHODIMP GuestSession::FileQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
2067{
2068#ifndef VBOX_WITH_GUEST_CONTROL
2069 ReturnComNotImplemented();
2070#else
2071 LogFlowThisFuncEnter();
2072
2073 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2074 return setError(E_INVALIDARG, tr("No file to query information for specified"));
2075 CheckComArgOutPointerValid(aInfo);
2076
2077 AutoCaller autoCaller(this);
2078 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2079
2080 HRESULT hr = S_OK;
2081
2082 GuestFsObjData objData; int guestRc;
2083 int vrc = fileQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
2084 if (RT_SUCCESS(vrc))
2085 {
2086 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
2087 hr = pFsObjInfo.createObject();
2088 if (FAILED(hr)) return hr;
2089
2090 vrc = pFsObjInfo->init(objData);
2091 if (RT_SUCCESS(vrc))
2092 {
2093 hr = pFsObjInfo.queryInterfaceTo(aInfo);
2094 if (FAILED(hr)) return hr;
2095 }
2096 }
2097
2098 if (RT_FAILURE(vrc))
2099 {
2100 switch (vrc)
2101 {
2102 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
2103 hr = GuestProcess::setErrorExternal(this, guestRc);
2104 break;
2105
2106 case VERR_NOT_A_FILE:
2107 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a file"));
2108 break;
2109
2110 default:
2111 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), vrc);
2112 break;
2113 }
2114 }
2115
2116 return hr;
2117#endif /* VBOX_WITH_GUEST_CONTROL */
2118}
2119
2120STDMETHODIMP GuestSession::FileQuerySize(IN_BSTR aPath, LONG64 *aSize)
2121{
2122#ifndef VBOX_WITH_GUEST_CONTROL
2123 ReturnComNotImplemented();
2124#else
2125 LogFlowThisFuncEnter();
2126
2127 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2128 return setError(E_INVALIDARG, tr("No file to query size for specified"));
2129 CheckComArgOutPointerValid(aSize);
2130
2131 AutoCaller autoCaller(this);
2132 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2133
2134 HRESULT hr = S_OK;
2135
2136 int64_t llSize; int guestRc;
2137 int vrc = fileQuerySizeInternal(Utf8Str(aPath), &llSize, &guestRc);
2138 if (RT_SUCCESS(vrc))
2139 {
2140 *aSize = llSize;
2141 }
2142 else
2143 {
2144 switch (vrc)
2145 {
2146 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
2147 hr = GuestProcess::setErrorExternal(this, guestRc);
2148 break;
2149
2150 default:
2151 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), vrc);
2152 break;
2153 }
2154 }
2155
2156 return hr;
2157#endif /* VBOX_WITH_GUEST_CONTROL */
2158}
2159
2160STDMETHODIMP GuestSession::FileRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
2161{
2162#ifndef VBOX_WITH_GUEST_CONTROL
2163 ReturnComNotImplemented();
2164#else
2165 LogFlowThisFuncEnter();
2166
2167 AutoCaller autoCaller(this);
2168 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2169
2170 ReturnComNotImplemented();
2171#endif /* VBOX_WITH_GUEST_CONTROL */
2172}
2173
2174STDMETHODIMP GuestSession::FileSetACL(IN_BSTR aPath, IN_BSTR aACL)
2175{
2176#ifndef VBOX_WITH_GUEST_CONTROL
2177 ReturnComNotImplemented();
2178#else
2179 LogFlowThisFuncEnter();
2180
2181 AutoCaller autoCaller(this);
2182 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2183
2184 ReturnComNotImplemented();
2185#endif /* VBOX_WITH_GUEST_CONTROL */
2186}
2187
2188STDMETHODIMP GuestSession::ProcessCreate(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
2189 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS, IGuestProcess **aProcess)
2190{
2191#ifndef VBOX_WITH_GUEST_CONTROL
2192 ReturnComNotImplemented();
2193#else
2194 LogFlowThisFuncEnter();
2195
2196 com::SafeArray<LONG> affinity;
2197
2198 return ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),
2199 ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess);
2200#endif /* VBOX_WITH_GUEST_CONTROL */
2201}
2202
2203STDMETHODIMP GuestSession::ProcessCreateEx(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
2204 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS,
2205 ProcessPriority_T aPriority, ComSafeArrayIn(LONG, aAffinity),
2206 IGuestProcess **aProcess)
2207{
2208#ifndef VBOX_WITH_GUEST_CONTROL
2209 ReturnComNotImplemented();
2210#else
2211 LogFlowThisFuncEnter();
2212
2213 if (RT_UNLIKELY((aCommand) == NULL || *(aCommand) == '\0'))
2214 return setError(E_INVALIDARG, tr("No command to execute specified"));
2215 CheckComArgOutPointerValid(aProcess);
2216
2217 AutoCaller autoCaller(this);
2218 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2219
2220 GuestProcessStartupInfo procInfo;
2221 procInfo.mCommand = Utf8Str(aCommand);
2222
2223 if (aArguments)
2224 {
2225 com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments));
2226 for (size_t i = 0; i < arguments.size(); i++)
2227 procInfo.mArguments.push_back(Utf8Str(arguments[i]));
2228 }
2229
2230 int rc = VINF_SUCCESS;
2231
2232 /*
2233 * Create the process environment:
2234 * - Apply the session environment in a first step, and
2235 * - Apply environment variables specified by this call to
2236 * have the chance of overwriting/deleting session entries.
2237 */
2238 procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
2239
2240 if (aEnvironment)
2241 {
2242 com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aEnvironment));
2243 for (size_t i = 0; i < environment.size() && RT_SUCCESS(rc); i++)
2244 rc = procInfo.mEnvironment.Set(Utf8Str(environment[i]));
2245 }
2246
2247 HRESULT hr = S_OK;
2248
2249 if (RT_SUCCESS(rc))
2250 {
2251 if (aFlags)
2252 {
2253 com::SafeArray<ProcessCreateFlag_T> flags(ComSafeArrayInArg(aFlags));
2254 for (size_t i = 0; i < flags.size(); i++)
2255 procInfo.mFlags |= flags[i];
2256 }
2257
2258 procInfo.mTimeoutMS = aTimeoutMS;
2259
2260 if (aAffinity)
2261 {
2262 com::SafeArray<LONG> affinity(ComSafeArrayInArg(aAffinity));
2263 for (size_t i = 0; i < affinity.size(); i++)
2264 {
2265 if (affinity[i])
2266 procInfo.mAffinity |= (uint64_t)1 << i;
2267 }
2268 }
2269
2270 procInfo.mPriority = aPriority;
2271
2272 ComObjPtr<GuestProcess> pProcess;
2273 rc = processCreateExInteral(procInfo, pProcess);
2274 if (RT_SUCCESS(rc))
2275 {
2276 /* Return guest session to the caller. */
2277 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
2278 if (FAILED(hr2))
2279 rc = VERR_COM_OBJECT_NOT_FOUND;
2280
2281 if (RT_SUCCESS(rc))
2282 rc = pProcess->startProcessAsync();
2283 }
2284 }
2285
2286 if (RT_FAILURE(rc))
2287 {
2288 switch (rc)
2289 {
2290 case VERR_MAX_PROCS_REACHED:
2291 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest objects per session (%ld) reached"),
2292 VBOX_GUESTCTRL_MAX_OBJECTS);
2293 break;
2294
2295 /** @todo Add more errors here. */
2296
2297 default:
2298 hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest process, rc=%Rrc"), rc);
2299 break;
2300 }
2301 }
2302
2303 LogFlowFuncLeaveRC(rc);
2304 return hr;
2305#endif /* VBOX_WITH_GUEST_CONTROL */
2306}
2307
2308STDMETHODIMP GuestSession::ProcessGet(ULONG aPID, IGuestProcess **aProcess)
2309{
2310#ifndef VBOX_WITH_GUEST_CONTROL
2311 ReturnComNotImplemented();
2312#else
2313 LogFlowThisFunc(("aPID=%RU32\n", aPID));
2314
2315 CheckComArgOutPointerValid(aProcess);
2316 if (aPID == 0)
2317 return setError(E_INVALIDARG, tr("No valid process ID (PID) specified"));
2318
2319 AutoCaller autoCaller(this);
2320 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2321
2322 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2323
2324 HRESULT hr = S_OK;
2325
2326 ComObjPtr<GuestProcess> pProcess;
2327 int rc = processGetByPID(aPID, &pProcess);
2328 if (RT_FAILURE(rc))
2329 hr = setError(E_INVALIDARG, tr("No process with PID %RU32 found"), aPID);
2330
2331 /* This will set (*aProcess) to NULL if pProgress is NULL. */
2332 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
2333 if (SUCCEEDED(hr))
2334 hr = hr2;
2335
2336 LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", *aProcess, hr));
2337 return hr;
2338#endif /* VBOX_WITH_GUEST_CONTROL */
2339}
2340
2341STDMETHODIMP GuestSession::SymlinkCreate(IN_BSTR aSource, IN_BSTR aTarget, SymlinkType_T aType)
2342{
2343#ifndef VBOX_WITH_GUEST_CONTROL
2344 ReturnComNotImplemented();
2345#else
2346 LogFlowThisFuncEnter();
2347
2348 AutoCaller autoCaller(this);
2349 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2350
2351 ReturnComNotImplemented();
2352#endif /* VBOX_WITH_GUEST_CONTROL */
2353}
2354
2355STDMETHODIMP GuestSession::SymlinkExists(IN_BSTR aSymlink, BOOL *aExists)
2356{
2357#ifndef VBOX_WITH_GUEST_CONTROL
2358 ReturnComNotImplemented();
2359#else
2360 LogFlowThisFuncEnter();
2361
2362 AutoCaller autoCaller(this);
2363 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2364
2365 ReturnComNotImplemented();
2366#endif /* VBOX_WITH_GUEST_CONTROL */
2367}
2368
2369STDMETHODIMP GuestSession::SymlinkRead(IN_BSTR aSymlink, ComSafeArrayIn(SymlinkReadFlag_T, aFlags), BSTR *aTarget)
2370{
2371#ifndef VBOX_WITH_GUEST_CONTROL
2372 ReturnComNotImplemented();
2373#else
2374 LogFlowThisFuncEnter();
2375
2376 AutoCaller autoCaller(this);
2377 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2378
2379 ReturnComNotImplemented();
2380#endif /* VBOX_WITH_GUEST_CONTROL */
2381}
2382
2383STDMETHODIMP GuestSession::SymlinkRemoveDirectory(IN_BSTR aPath)
2384{
2385#ifndef VBOX_WITH_GUEST_CONTROL
2386 ReturnComNotImplemented();
2387#else
2388 LogFlowThisFuncEnter();
2389
2390 AutoCaller autoCaller(this);
2391 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2392
2393 ReturnComNotImplemented();
2394#endif /* VBOX_WITH_GUEST_CONTROL */
2395}
2396
2397STDMETHODIMP GuestSession::SymlinkRemoveFile(IN_BSTR aFile)
2398{
2399#ifndef VBOX_WITH_GUEST_CONTROL
2400 ReturnComNotImplemented();
2401#else
2402 LogFlowThisFuncEnter();
2403
2404 AutoCaller autoCaller(this);
2405 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2406
2407 ReturnComNotImplemented();
2408#endif /* VBOX_WITH_GUEST_CONTROL */
2409}
2410
Note: See TracBrowser for help on using the repository browser.

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