VirtualBox

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

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

Guest Control 2.0: Update.

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