VirtualBox

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

Last change on this file since 42839 was 42810, checked in by vboxsync, 13 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.5 KB
Line 
1
2/* $Id: GuestSessionImpl.cpp 42810 2012-08-14 14:45:11Z 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 /* Note: There will be a race between creating and getting/initing the directory
768 object here. */
769 int rc = pFile->init(this /* Parent */,
770 strPath, strOpenMode, strDisposition, uCreationMode, iOffset);
771 if (RT_FAILURE(rc))
772 return rc;
773
774 /* Add the created directory to our vector. */
775 mData.mFiles.push_back(pFile);
776
777 LogFlowFunc(("Added new file \"%s\" (Session: %RU32\n",
778 strPath.c_str(), mData.mId));
779
780 LogFlowFuncLeaveRC(rc);
781 return rc;
782}
783
784int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)
785{
786 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
787
788 int rc = fsQueryInfoInternal(strPath, objData);
789 if (RT_SUCCESS(rc))
790 {
791 rc = objData.mType == FsObjType_File
792 ? VINF_SUCCESS : VERR_NOT_A_FILE;
793 }
794
795 LogFlowFuncLeaveRC(rc);
796 return rc;
797}
798
799int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize)
800{
801 AssertPtrReturn(pllSize, VERR_INVALID_POINTER);
802
803 GuestFsObjData objData;
804 int rc = fileQueryInfoInternal(strPath, objData);
805 if (RT_SUCCESS(rc))
806 {
807 if (objData.mType == FsObjType_File)
808 *pllSize = objData.mObjectSize;
809 else
810 rc = VERR_NOT_A_FILE;
811 }
812
813 return rc;
814}
815
816int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)
817{
818 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
819
820 GuestProcessStartupInfo procInfo;
821 procInfo.mName = Utf8StrFmt(tr("Querying info for \"%s\""), strPath.c_str());
822 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT);
823 procInfo.mFlags = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
824
825 /* Construct arguments. */
826 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
827 procInfo.mArguments.push_back(strPath);
828
829 GuestProcessStream streamOut;
830
831 ComObjPtr<GuestProcess> pProcess;
832 int rc = processCreateExInteral(procInfo, pProcess);
833 if (RT_SUCCESS(rc))
834 rc = pProcess->startProcess();
835 if (RT_SUCCESS(rc))
836 {
837 GuestProcessWaitResult waitRes;
838 BYTE byBuf[_64K];
839 size_t cbRead = 0;
840
841 /** @todo Merge with GuestDirectory::read. */
842 for (;;)
843 {
844 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
845 30 * 1000 /* Timeout */, waitRes);
846 if ( RT_FAILURE(rc)
847 || waitRes.mResult == ProcessWaitResult_Terminate
848 || waitRes.mResult == ProcessWaitResult_Error
849 || waitRes.mResult == ProcessWaitResult_Timeout)
850 {
851 break;
852 }
853
854 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
855 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
856 &cbRead);
857 if (RT_FAILURE(rc))
858 break;
859
860 if (cbRead)
861 {
862 rc = streamOut.AddData(byBuf, cbRead);
863 if (RT_FAILURE(rc))
864 break;
865 }
866 }
867
868 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64, cbStreamOut=%RU32\n",
869 rc, cbRead, streamOut.GetSize()));
870 }
871
872 if (RT_SUCCESS(rc))
873 {
874 GuestProcessStreamBlock streamBlock;
875 rc = streamOut.ParseBlock(streamBlock);
876 if (RT_SUCCESS(rc))
877 {
878 rc = objData.FromStat(streamBlock);
879 }
880 else
881 AssertMsgFailed(("Parsing stream block failed: %Rrc\n", rc));
882 }
883
884 LogFlowFuncLeaveRC(rc);
885 return rc;
886}
887
888const GuestCredentials& GuestSession::getCredentials(void)
889{
890 return mData.mCredentials;
891}
892
893const GuestEnvironment& GuestSession::getEnvironment(void)
894{
895 return mData.mEnvironment;
896}
897
898Utf8Str GuestSession::getName(void)
899{
900 return mData.mName;
901}
902
903int GuestSession::processClose(ComObjPtr<GuestProcess> pProcess)
904{
905 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
906
907 for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();
908 itProcs != mData.mProcesses.end(); ++itProcs)
909 {
910 if (pProcess == itProcs->second)
911 {
912 LogFlowFunc(("Removing process (Session: %RU32) with process ID=%RU32, guest PID=%RU32 (now total %ld processes)\n",
913 mData.mId, itProcs->second->getProcessID(), itProcs->second->getPID(), mData.mProcesses.size() - 1));
914
915 mData.mProcesses.erase(itProcs);
916 return VINF_SUCCESS;
917 }
918 }
919
920 return VERR_NOT_FOUND;
921}
922
923/**
924 * Creates but does *not* start the process yet. See GuestProcess::startProcess() or
925 * GuestProcess::startProcessAsync() for that.
926 *
927 * @return IPRT status code.
928 * @param procInfo
929 * @param pProcess
930 */
931int GuestSession::processCreateExInteral(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
932{
933 LogFlowFunc(("mCmd=%s, mFlags=%x, mTimeoutMS=%RU32\n",
934 procInfo.mCommand.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));
935#ifdef DEBUG
936 if (procInfo.mArguments.size())
937 {
938 LogFlowFunc(("Arguments:"));
939 ProcessArguments::const_iterator it = procInfo.mArguments.begin();
940 while (it != procInfo.mArguments.end())
941 {
942 LogFlow((" %s", (*it).c_str()));
943 it++;
944 }
945 LogFlow(("\n"));
946 }
947#endif
948
949 /* Validate flags. */
950 if (procInfo.mFlags)
951 {
952 if ( !(procInfo.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
953 && !(procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
954 && !(procInfo.mFlags & ProcessCreateFlag_Hidden)
955 && !(procInfo.mFlags & ProcessCreateFlag_NoProfile)
956 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
957 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdErr))
958 {
959 return VERR_INVALID_PARAMETER;
960 }
961 }
962
963 /* Adjust timeout. If set to 0, we define
964 * an infinite timeout. */
965 if (procInfo.mTimeoutMS == 0)
966 procInfo.mTimeoutMS = UINT32_MAX;
967
968 /** @tood Implement process priority + affinity. */
969
970 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
971
972 int rc = VERR_MAX_PROCS_REACHED;
973 if (mData.mProcesses.size() >= VBOX_GUESTCTRL_MAX_PROCESSES)
974 return rc;
975
976 /* Create a new (host-based) process ID and assign it. */
977 uint32_t uNewProcessID = 0;
978 ULONG uTries = 0;
979
980 for (;;)
981 {
982 /* Is the context ID already used? */
983 if (!processExists(uNewProcessID, NULL /* pProgress */))
984 {
985 /* Callback with context ID was not found. This means
986 * we can use this context ID for our new callback we want
987 * to add below. */
988 rc = VINF_SUCCESS;
989 break;
990 }
991 uNewProcessID++;
992 if (uNewProcessID == VBOX_GUESTCTRL_MAX_PROCESSES)
993 uNewProcessID = 0;
994
995 if (++uTries == UINT32_MAX)
996 break; /* Don't try too hard. */
997 }
998
999 if (RT_FAILURE(rc))
1000 return rc;
1001
1002 /* Create the process object. */
1003 HRESULT hr = pProcess.createObject();
1004 if (FAILED(hr))
1005 return VERR_COM_UNEXPECTED;
1006
1007 rc = pProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */,
1008 uNewProcessID, procInfo);
1009 if (RT_FAILURE(rc))
1010 return rc;
1011
1012 /* Add the created process to our map. */
1013 mData.mProcesses[uNewProcessID] = pProcess;
1014
1015 LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes)\n",
1016 mData.mId, uNewProcessID, mData.mProcesses.size()));
1017
1018 return rc;
1019}
1020
1021inline bool GuestSession::processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess)
1022{
1023 SessionProcesses::const_iterator it = mData.mProcesses.find(uProcessID);
1024 if (it != mData.mProcesses.end())
1025 {
1026 if (pProcess)
1027 *pProcess = it->second;
1028 return true;
1029 }
1030 return false;
1031}
1032
1033inline int GuestSession::processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess)
1034{
1035 AssertReturn(uPID, false);
1036 /* pProcess is optional. */
1037
1038 SessionProcesses::iterator it = mData.mProcesses.begin();
1039 for (; it != mData.mProcesses.end(); it++)
1040 {
1041 ComObjPtr<GuestProcess> pCurProc = it->second;
1042 AutoCaller procCaller(pCurProc);
1043 if (procCaller.rc())
1044 return VERR_COM_INVALID_OBJECT_STATE;
1045
1046 if (it->second->getPID() == uPID)
1047 {
1048 if (pProcess)
1049 *pProcess = pCurProc;
1050 return VINF_SUCCESS;
1051 }
1052 }
1053
1054 return VERR_NOT_FOUND;
1055}
1056
1057int GuestSession::startTaskAsync(const Utf8Str &strTaskDesc,
1058 GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress)
1059{
1060 LogFlowThisFunc(("strTaskDesc=%s, pTask=%p\n", strTaskDesc.c_str(), pTask));
1061
1062 AssertPtrReturn(pTask, VERR_INVALID_POINTER);
1063
1064 /* Create the progress object. */
1065 HRESULT hr = pProgress.createObject();
1066 if (FAILED(hr))
1067 return VERR_COM_UNEXPECTED;
1068
1069 hr = pProgress->init(static_cast<IGuestSession*>(this),
1070 Bstr(strTaskDesc).raw(),
1071 TRUE /* aCancelable */);
1072 if (FAILED(hr))
1073 return VERR_COM_UNEXPECTED;
1074
1075 /* Initialize our worker task. */
1076 std::auto_ptr<GuestSessionTask> task(pTask);
1077
1078 int rc = task->RunAsync(strTaskDesc, pProgress);
1079 if (RT_FAILURE(rc))
1080 return rc;
1081
1082 /* Don't destruct on success. */
1083 task.release();
1084
1085 LogFlowFuncLeaveRC(rc);
1086 return rc;
1087}
1088
1089/**
1090 * Queries/collects information prior to establishing a guest session.
1091 * This is necessary to know which guest control protocol version to use,
1092 * among other things (later).
1093 *
1094 * @return IPRT status code.
1095 */
1096int GuestSession::queryInfo(void)
1097{
1098#if 1
1099 /* Since the new functions were not implemented yet, force Main to use protocol ver 1. */
1100 mData.mProtocolVersion = 1;
1101#else
1102 /*
1103 * Try querying the guest control protocol version running on the guest.
1104 * This is done using the Guest Additions version
1105 */
1106 ComObjPtr<Guest> pGuest = mData.mParent;
1107 Assert(!pGuest.isNull());
1108
1109 uint32_t uVerAdditions = pGuest->getAdditionsVersion();
1110 mData.mProtocolVersion = ( VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions) >= 4
1111 && VBOX_FULL_VERSION_GET_MINOR(uVerAdditions) >= 2) /** @todo What's about v5.0 ? */
1112 ? 2 /* Guest control 2.0. */
1113 : 1; /* Legacy guest control (VBox < 4.2). */
1114 /* Build revision is ignored. */
1115
1116 /* Tell the user but don't bitch too often. */
1117 static short s_gctrlLegacyWarning = 0;
1118 if (s_gctrlLegacyWarning++ < 3) /** @todo Find a bit nicer text. */
1119 LogRel((tr("Warning: Guest Additions are older (%ld.%ld) than host capabilities for guest control, please upgrade them. Using protocol version %ld now\n"),
1120 VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions), VBOX_FULL_VERSION_GET_MINOR(uVerAdditions), mData.mProtocolVersion));
1121#endif
1122 return VINF_SUCCESS;
1123}
1124
1125// implementation of public methods
1126/////////////////////////////////////////////////////////////////////////////
1127
1128STDMETHODIMP GuestSession::Close(void)
1129{
1130#ifndef VBOX_WITH_GUEST_CONTROL
1131 ReturnComNotImplemented();
1132#else
1133 LogFlowThisFuncEnter();
1134
1135 uninit();
1136
1137 LogFlowFuncLeaveRC(S_OK);
1138 return S_OK;
1139#endif /* VBOX_WITH_GUEST_CONTROL */
1140}
1141
1142STDMETHODIMP GuestSession::CopyFrom(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
1143{
1144#ifndef VBOX_WITH_GUEST_CONTROL
1145 ReturnComNotImplemented();
1146#else
1147 CheckComArgStrNotEmptyOrNull(aSource);
1148 CheckComArgStrNotEmptyOrNull(aDest);
1149 CheckComArgOutPointerValid(aProgress);
1150
1151 LogFlowThisFuncEnter();
1152
1153 if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
1154 return setError(E_INVALIDARG, tr("No source specified"));
1155 if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
1156 return setError(E_INVALIDARG, tr("No destination specified"));
1157
1158 AutoCaller autoCaller(this);
1159 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1160
1161 uint32_t fFlags = CopyFileFlag_None;
1162 if (aFlags)
1163 {
1164 com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
1165 for (size_t i = 0; i < flags.size(); i++)
1166 fFlags |= flags[i];
1167 }
1168
1169 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1170
1171 HRESULT hr = S_OK;
1172
1173 ComObjPtr<Progress> pProgress;
1174 SessionTaskCopyFrom *pTask = new SessionTaskCopyFrom(this /* GuestSession */,
1175 Utf8Str(aSource), Utf8Str(aDest), fFlags);
1176 AssertPtrReturn(pTask, VERR_NO_MEMORY);
1177 int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from guest to \"%ls\" on the host"), aSource, aDest),
1178 pTask, pProgress);
1179 if (RT_SUCCESS(rc))
1180 {
1181 /* Return progress to the caller. */
1182 hr = pProgress.queryInterfaceTo(aProgress);
1183 }
1184 else
1185 hr = setError(VBOX_E_IPRT_ERROR,
1186 tr("Starting task for copying file \"%ls\" from guest to \"%ls\" on the host failed: %Rrc"), rc);
1187 return hr;
1188#endif /* VBOX_WITH_GUEST_CONTROL */
1189}
1190
1191STDMETHODIMP GuestSession::CopyTo(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
1192{
1193#ifndef VBOX_WITH_GUEST_CONTROL
1194 ReturnComNotImplemented();
1195#else
1196 CheckComArgStrNotEmptyOrNull(aSource);
1197 CheckComArgStrNotEmptyOrNull(aDest);
1198 CheckComArgOutPointerValid(aProgress);
1199
1200 LogFlowThisFuncEnter();
1201
1202 if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
1203 return setError(E_INVALIDARG, tr("No source specified"));
1204 if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
1205 return setError(E_INVALIDARG, tr("No destination specified"));
1206
1207 AutoCaller autoCaller(this);
1208 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1209
1210 uint32_t fFlags = CopyFileFlag_None;
1211 if (aFlags)
1212 {
1213 com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
1214 for (size_t i = 0; i < flags.size(); i++)
1215 fFlags |= flags[i];
1216 }
1217
1218 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1219
1220 HRESULT hr = S_OK;
1221
1222 ComObjPtr<Progress> pProgress;
1223 SessionTaskCopyTo *pTask = new SessionTaskCopyTo(this /* GuestSession */,
1224 Utf8Str(aSource), Utf8Str(aDest), fFlags);
1225 AssertPtrReturn(pTask, VERR_NO_MEMORY);
1226 int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from host to \"%ls\" on the guest"), aSource, aDest),
1227 pTask, pProgress);
1228 if (RT_SUCCESS(rc))
1229 {
1230 /* Return progress to the caller. */
1231 hr = pProgress.queryInterfaceTo(aProgress);
1232 }
1233 else
1234 hr = setError(VBOX_E_IPRT_ERROR,
1235 tr("Starting task for copying file \"%ls\" from host to \"%ls\" on the guest failed: %Rrc"), rc);
1236 return hr;
1237#endif /* VBOX_WITH_GUEST_CONTROL */
1238}
1239
1240STDMETHODIMP GuestSession::DirectoryCreate(IN_BSTR aPath, ULONG aMode,
1241 ComSafeArrayIn(DirectoryCreateFlag_T, aFlags))
1242{
1243#ifndef VBOX_WITH_GUEST_CONTROL
1244 ReturnComNotImplemented();
1245#else
1246 LogFlowThisFuncEnter();
1247
1248 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1249 return setError(E_INVALIDARG, tr("No directory to create specified"));
1250
1251 AutoCaller autoCaller(this);
1252 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1253
1254 uint32_t fFlags = DirectoryCreateFlag_None;
1255 if (aFlags)
1256 {
1257 com::SafeArray<DirectoryCreateFlag_T> flags(ComSafeArrayInArg(aFlags));
1258 for (size_t i = 0; i < flags.size(); i++)
1259 fFlags |= flags[i];
1260
1261 if (fFlags)
1262 {
1263 if (!(fFlags & DirectoryCreateFlag_Parents))
1264 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), fFlags);
1265 }
1266 }
1267
1268 HRESULT hr = S_OK;
1269
1270 ComObjPtr <GuestDirectory> pDirectory;
1271 int rc = directoryCreateInternal(Utf8Str(aPath), (uint32_t)aMode, fFlags);
1272 if (RT_FAILURE(rc))
1273 {
1274 switch (rc)
1275 {
1276 case VERR_INVALID_PARAMETER:
1277 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Invalid parameters given"));
1278 break;
1279
1280 case VERR_BROKEN_PIPE:
1281 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Unexpectedly aborted"));
1282 break;
1283
1284 case VERR_CANT_CREATE:
1285 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Could not create directory"));
1286 break;
1287
1288 default:
1289 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
1290 break;
1291 }
1292 }
1293
1294 return hr;
1295#endif /* VBOX_WITH_GUEST_CONTROL */
1296}
1297
1298STDMETHODIMP GuestSession::DirectoryCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, BSTR *aDirectory)
1299{
1300#ifndef VBOX_WITH_GUEST_CONTROL
1301 ReturnComNotImplemented();
1302#else
1303 LogFlowThisFuncEnter();
1304
1305 if (RT_UNLIKELY((aTemplate) == NULL || *(aTemplate) == '\0'))
1306 return setError(E_INVALIDARG, tr("No file to remove specified"));
1307
1308 AutoCaller autoCaller(this);
1309 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1310
1311 int rc = VINF_SUCCESS;
1312
1313 try /* Can this be done without exceptions? */
1314 {
1315 Utf8Str strName;
1316 if (RT_FAILURE(objectCreateTempInternal(Utf8Str(aTemplate),
1317 Utf8Str(aPath),
1318 true, strName, &rc)))
1319 return E_FAIL;
1320 HRESULT hrc = rc == VERR_INVALID_PARAMETER ? E_INVALIDARG
1321 : rc == VERR_NOT_SUPPORTED ? VBOX_E_NOT_SUPPORTED
1322 : RT_FAILURE(rc) ? VBOX_E_IPRT_ERROR
1323 : S_OK;
1324 if (FAILED(hrc))
1325 return setError(hrc, tr("Temporary directory creation failed: %Rrc"),
1326 rc);
1327 strName.cloneTo(aDirectory);
1328 return S_OK;
1329 }
1330 catch (...)
1331 {
1332 return E_OUTOFMEMORY;
1333 }
1334#endif /* VBOX_WITH_GUEST_CONTROL */
1335}
1336
1337STDMETHODIMP GuestSession::DirectoryExists(IN_BSTR aPath, BOOL *aExists)
1338{
1339#ifndef VBOX_WITH_GUEST_CONTROL
1340 ReturnComNotImplemented();
1341#else
1342 LogFlowThisFuncEnter();
1343
1344 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1345 return setError(E_INVALIDARG, tr("No directory to check existence for specified"));
1346 CheckComArgOutPointerValid(aExists);
1347
1348 AutoCaller autoCaller(this);
1349 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1350
1351 HRESULT hr = S_OK;
1352
1353 GuestFsObjData objData;
1354 int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
1355 if (RT_SUCCESS(rc))
1356 {
1357 *aExists = objData.mType == FsObjType_Directory;
1358 }
1359 else
1360 {
1361 switch (rc)
1362 {
1363 /** @todo Add more errors here! */
1364
1365 default:
1366 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence failed: %Rrc"), rc);
1367 break;
1368 }
1369 }
1370
1371 return hr;
1372#endif /* VBOX_WITH_GUEST_CONTROL */
1373}
1374
1375STDMETHODIMP GuestSession::DirectoryOpen(IN_BSTR aPath, IN_BSTR aFilter, ComSafeArrayIn(DirectoryOpenFlag_T, aFlags), IGuestDirectory **aDirectory)
1376{
1377#ifndef VBOX_WITH_GUEST_CONTROL
1378 ReturnComNotImplemented();
1379#else
1380 LogFlowThisFuncEnter();
1381
1382 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1383 return setError(E_INVALIDARG, tr("No directory to open specified"));
1384 if (RT_UNLIKELY((aFilter) != NULL && *(aFilter) != '\0'))
1385 return setError(E_INVALIDARG, tr("Directory filters not implemented yet"));
1386
1387 CheckComArgOutPointerValid(aDirectory);
1388
1389 AutoCaller autoCaller(this);
1390 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1391
1392 uint32_t fFlags = DirectoryOpenFlag_None;
1393 if (aFlags)
1394 {
1395 com::SafeArray<DirectoryOpenFlag_T> flags(ComSafeArrayInArg(aFlags));
1396 for (size_t i = 0; i < flags.size(); i++)
1397 fFlags |= flags[i];
1398
1399 if (fFlags)
1400 return setError(E_INVALIDARG, tr("Open flags (%#x) not implemented yet"), fFlags);
1401 }
1402
1403 HRESULT hr = S_OK;
1404
1405 ComObjPtr <GuestDirectory> pDirectory;
1406 int rc = directoryOpenInternal(Utf8Str(aPath), Utf8Str(aFilter), fFlags, pDirectory);
1407 if (RT_SUCCESS(rc))
1408 {
1409 if (aDirectory)
1410 {
1411 /* Return directory object to the caller. */
1412 hr = pDirectory.queryInterfaceTo(aDirectory);
1413 }
1414 else
1415 {
1416 rc = directoryClose(pDirectory);
1417 if (RT_FAILURE(rc))
1418 hr = setError(VBOX_E_IPRT_ERROR, tr("Unable to close directory object, rc=%Rrc"), rc);
1419 }
1420 }
1421 else
1422 {
1423 switch (rc)
1424 {
1425 case VERR_INVALID_PARAMETER:
1426 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Invalid parameters given"));
1427 break;
1428
1429 case VERR_BROKEN_PIPE:
1430 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Unexpectedly aborted"));
1431 break;
1432
1433 default:
1434 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: %Rrc"), rc);
1435 break;
1436 }
1437 }
1438
1439 return hr;
1440#endif /* VBOX_WITH_GUEST_CONTROL */
1441}
1442
1443STDMETHODIMP GuestSession::DirectoryQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
1444{
1445#ifndef VBOX_WITH_GUEST_CONTROL
1446 ReturnComNotImplemented();
1447#else
1448 LogFlowThisFuncEnter();
1449
1450 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1451 return setError(E_INVALIDARG, tr("No directory to query information for specified"));
1452 CheckComArgOutPointerValid(aInfo);
1453
1454 AutoCaller autoCaller(this);
1455 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1456
1457 HRESULT hr = S_OK;
1458
1459 GuestFsObjData objData;
1460 int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData);
1461 if (RT_SUCCESS(rc))
1462 {
1463 if (objData.mType == FsObjType_Directory)
1464 {
1465 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
1466 hr = pFsObjInfo.createObject();
1467 if (FAILED(hr))
1468 return VERR_COM_UNEXPECTED;
1469
1470 rc = pFsObjInfo->init(objData);
1471 if (RT_SUCCESS(rc))
1472 hr = pFsObjInfo.queryInterfaceTo(aInfo);
1473 }
1474 }
1475
1476 if (RT_FAILURE(rc))
1477 {
1478 switch (rc)
1479 {
1480 /** @todo Add more errors here! */
1481
1482 case VERR_NOT_A_DIRECTORY:
1483 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a directory"));
1484 break;
1485
1486 default:
1487 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information failed: %Rrc"), rc);
1488 break;
1489 }
1490 }
1491
1492 return hr;
1493#endif /* VBOX_WITH_GUEST_CONTROL */
1494}
1495
1496STDMETHODIMP GuestSession::DirectoryRemove(IN_BSTR aPath)
1497{
1498#ifndef VBOX_WITH_GUEST_CONTROL
1499 ReturnComNotImplemented();
1500#else
1501 LogFlowThisFuncEnter();
1502
1503 AutoCaller autoCaller(this);
1504 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1505
1506 ReturnComNotImplemented();
1507#endif /* VBOX_WITH_GUEST_CONTROL */
1508}
1509
1510STDMETHODIMP GuestSession::DirectoryRemoveRecursive(IN_BSTR aPath, ComSafeArrayIn(DirectoryRemoveRecFlag_T, aFlags), IProgress **aProgress)
1511{
1512#ifndef VBOX_WITH_GUEST_CONTROL
1513 ReturnComNotImplemented();
1514#else
1515 LogFlowThisFuncEnter();
1516
1517 AutoCaller autoCaller(this);
1518 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1519
1520 ReturnComNotImplemented();
1521#endif /* VBOX_WITH_GUEST_CONTROL */
1522}
1523
1524STDMETHODIMP GuestSession::DirectoryRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
1525{
1526#ifndef VBOX_WITH_GUEST_CONTROL
1527 ReturnComNotImplemented();
1528#else
1529 LogFlowThisFuncEnter();
1530
1531 AutoCaller autoCaller(this);
1532 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1533
1534 ReturnComNotImplemented();
1535#endif /* VBOX_WITH_GUEST_CONTROL */
1536}
1537
1538STDMETHODIMP GuestSession::DirectorySetACL(IN_BSTR aPath, IN_BSTR aACL)
1539{
1540#ifndef VBOX_WITH_GUEST_CONTROL
1541 ReturnComNotImplemented();
1542#else
1543 LogFlowThisFuncEnter();
1544
1545 AutoCaller autoCaller(this);
1546 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1547
1548 ReturnComNotImplemented();
1549#endif /* VBOX_WITH_GUEST_CONTROL */
1550}
1551
1552STDMETHODIMP GuestSession::EnvironmentClear(void)
1553{
1554#ifndef VBOX_WITH_GUEST_CONTROL
1555 ReturnComNotImplemented();
1556#else
1557 LogFlowThisFuncEnter();
1558
1559 AutoCaller autoCaller(this);
1560 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1561
1562 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1563
1564 mData.mEnvironment.Clear();
1565
1566 LogFlowFuncLeaveRC(S_OK);
1567 return S_OK;
1568#endif /* VBOX_WITH_GUEST_CONTROL */
1569}
1570
1571STDMETHODIMP GuestSession::EnvironmentGet(IN_BSTR aName, BSTR *aValue)
1572{
1573#ifndef VBOX_WITH_GUEST_CONTROL
1574 ReturnComNotImplemented();
1575#else
1576 LogFlowThisFuncEnter();
1577
1578 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
1579 return setError(E_INVALIDARG, tr("No value name specified"));
1580
1581 CheckComArgOutPointerValid(aValue);
1582
1583 AutoCaller autoCaller(this);
1584 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1585
1586 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1587
1588 Bstr strValue(mData.mEnvironment.Get(Utf8Str(aName)));
1589 strValue.cloneTo(aValue);
1590
1591 LogFlowFuncLeaveRC(S_OK);
1592 return S_OK;
1593#endif /* VBOX_WITH_GUEST_CONTROL */
1594}
1595
1596STDMETHODIMP GuestSession::EnvironmentSet(IN_BSTR aName, IN_BSTR aValue)
1597{
1598#ifndef VBOX_WITH_GUEST_CONTROL
1599 ReturnComNotImplemented();
1600#else
1601 LogFlowThisFuncEnter();
1602
1603 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
1604 return setError(E_INVALIDARG, tr("No value name specified"));
1605
1606 AutoCaller autoCaller(this);
1607 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1608
1609 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1610
1611 int rc = mData.mEnvironment.Set(Utf8Str(aName), Utf8Str(aValue));
1612
1613 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
1614 LogFlowFuncLeaveRC(hr);
1615 return hr;
1616#endif /* VBOX_WITH_GUEST_CONTROL */
1617}
1618
1619STDMETHODIMP GuestSession::EnvironmentUnset(IN_BSTR aName)
1620{
1621#ifndef VBOX_WITH_GUEST_CONTROL
1622 ReturnComNotImplemented();
1623#else
1624 LogFlowThisFuncEnter();
1625
1626 AutoCaller autoCaller(this);
1627 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1628
1629 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1630
1631 mData.mEnvironment.Unset(Utf8Str(aName));
1632
1633 LogFlowFuncLeaveRC(S_OK);
1634 return S_OK;
1635#endif /* VBOX_WITH_GUEST_CONTROL */
1636}
1637
1638STDMETHODIMP GuestSession::FileCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, IGuestFile **aFile)
1639{
1640#ifndef VBOX_WITH_GUEST_CONTROL
1641 ReturnComNotImplemented();
1642#else
1643 LogFlowThisFuncEnter();
1644
1645 AutoCaller autoCaller(this);
1646 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1647
1648 ReturnComNotImplemented();
1649#endif /* VBOX_WITH_GUEST_CONTROL */
1650}
1651
1652STDMETHODIMP GuestSession::FileExists(IN_BSTR aPath, BOOL *aExists)
1653{
1654#ifndef VBOX_WITH_GUEST_CONTROL
1655 ReturnComNotImplemented();
1656#else
1657 LogFlowThisFuncEnter();
1658
1659 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1660 return setError(E_INVALIDARG, tr("No file to check existence for specified"));
1661 CheckComArgOutPointerValid(aExists);
1662
1663 AutoCaller autoCaller(this);
1664 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1665
1666 HRESULT hr = S_OK;
1667
1668 GuestFsObjData objData;
1669 int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
1670 if (RT_SUCCESS(rc))
1671 {
1672 *aExists = objData.mType == FsObjType_File;
1673 }
1674 else
1675 {
1676 switch (rc)
1677 {
1678 /** @todo Add more errors here! */
1679
1680 default:
1681 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file existence failed: %Rrc"), rc);
1682 break;
1683 }
1684 }
1685
1686 return hr;
1687#endif /* VBOX_WITH_GUEST_CONTROL */
1688}
1689
1690STDMETHODIMP GuestSession::FileRemove(IN_BSTR aPath)
1691{
1692#ifndef VBOX_WITH_GUEST_CONTROL
1693 ReturnComNotImplemented();
1694#else
1695 LogFlowThisFuncEnter();
1696
1697 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1698 return setError(E_INVALIDARG, tr("No file to remove specified"));
1699
1700 AutoCaller autoCaller(this);
1701 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1702
1703 try /* Can this be done without exceptions? */
1704 {
1705 int rc2;
1706 int rc = fileRemoveInternal(Utf8Str(aPath), &rc2);
1707 if (RT_FAILURE((rc)))
1708 return setError(E_FAIL,
1709 tr("Internal error deleting file: %Rrc"), rc);
1710 else if (RT_FAILURE((rc2)))
1711 return setError(VBOX_E_IPRT_ERROR,
1712 tr("File deletion on guest returned: %Rrc"), rc2);
1713 }
1714 catch (...)
1715 {
1716 return E_OUTOFMEMORY;
1717 }
1718 return S_OK;
1719#endif /* VBOX_WITH_GUEST_CONTROL */
1720}
1721
1722STDMETHODIMP GuestSession::FileOpen(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, ULONG aCreationMode, LONG64 aOffset, IGuestFile **aFile)
1723{
1724#ifndef VBOX_WITH_GUEST_CONTROL
1725 ReturnComNotImplemented();
1726#else
1727 LogFlowThisFuncEnter();
1728
1729 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1730 return setError(E_INVALIDARG, tr("No file to open specified"));
1731 if (RT_UNLIKELY((aOpenMode) == NULL || *(aOpenMode) == '\0'))
1732 return setError(E_INVALIDARG, tr("No open mode specified"));
1733 if (RT_UNLIKELY((aDisposition) == NULL || *(aDisposition) == '\0'))
1734 return setError(E_INVALIDARG, tr("No disposition mode specified"));
1735
1736 CheckComArgOutPointerValid(aFile);
1737
1738 AutoCaller autoCaller(this);
1739 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1740
1741 /** @todo Validate open mode. */
1742 /** @todo Validate disposition mode. */
1743
1744 /** @todo Validate creation mode. */
1745 uint32_t uCreationMode = 0;
1746
1747 HRESULT hr = S_OK;
1748
1749 ComObjPtr <GuestFile> pFile;
1750 int rc = fileOpenInternal(Utf8Str(aPath), Utf8Str(aOpenMode), Utf8Str(aDisposition),
1751 aCreationMode, aOffset, pFile);
1752 if (RT_SUCCESS(rc))
1753 {
1754 /* Return directory object to the caller. */
1755 hr = pFile.queryInterfaceTo(aFile);
1756 }
1757 else
1758 {
1759 switch (rc)
1760 {
1761 /** @todo Add more error info! */
1762
1763 default:
1764 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
1765 break;
1766 }
1767 }
1768
1769 return hr;
1770#endif /* VBOX_WITH_GUEST_CONTROL */
1771}
1772
1773STDMETHODIMP GuestSession::FileQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
1774{
1775#ifndef VBOX_WITH_GUEST_CONTROL
1776 ReturnComNotImplemented();
1777#else
1778 LogFlowThisFuncEnter();
1779
1780 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1781 return setError(E_INVALIDARG, tr("No file to query information for specified"));
1782 CheckComArgOutPointerValid(aInfo);
1783
1784 AutoCaller autoCaller(this);
1785 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1786
1787 HRESULT hr = S_OK;
1788
1789 GuestFsObjData objData;
1790 int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
1791 if (RT_SUCCESS(rc))
1792 {
1793 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
1794 hr = pFsObjInfo.createObject();
1795 if (FAILED(hr))
1796 return VERR_COM_UNEXPECTED;
1797
1798 rc = pFsObjInfo->init(objData);
1799 if (RT_SUCCESS(rc))
1800 hr = pFsObjInfo.queryInterfaceTo(aInfo);
1801 }
1802
1803 if (RT_FAILURE(rc))
1804 {
1805 switch (rc)
1806 {
1807 /** @todo Add more errors here! */
1808
1809 case VERR_NOT_A_FILE:
1810 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a file"));
1811 break;
1812
1813 default:
1814 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), rc);
1815 break;
1816 }
1817 }
1818
1819 return hr;
1820#endif /* VBOX_WITH_GUEST_CONTROL */
1821}
1822
1823STDMETHODIMP GuestSession::FileQuerySize(IN_BSTR aPath, LONG64 *aSize)
1824{
1825#ifndef VBOX_WITH_GUEST_CONTROL
1826 ReturnComNotImplemented();
1827#else
1828 LogFlowThisFuncEnter();
1829
1830 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1831 return setError(E_INVALIDARG, tr("No file to query size for specified"));
1832 CheckComArgOutPointerValid(aSize);
1833
1834 AutoCaller autoCaller(this);
1835 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1836
1837 HRESULT hr = S_OK;
1838
1839 int64_t llSize;
1840 int rc = fileQuerySizeInternal(Utf8Str(aPath), &llSize);
1841 if (RT_SUCCESS(rc))
1842 {
1843 *aSize = llSize;
1844 }
1845 else
1846 {
1847 switch (rc)
1848 {
1849 /** @todo Add more errors here! */
1850
1851 default:
1852 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), rc);
1853 break;
1854 }
1855 }
1856
1857 return hr;
1858#endif /* VBOX_WITH_GUEST_CONTROL */
1859}
1860
1861STDMETHODIMP GuestSession::FileRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
1862{
1863#ifndef VBOX_WITH_GUEST_CONTROL
1864 ReturnComNotImplemented();
1865#else
1866 LogFlowThisFuncEnter();
1867
1868 AutoCaller autoCaller(this);
1869 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1870
1871 ReturnComNotImplemented();
1872#endif /* VBOX_WITH_GUEST_CONTROL */
1873}
1874
1875STDMETHODIMP GuestSession::FileSetACL(IN_BSTR aPath, IN_BSTR aACL)
1876{
1877#ifndef VBOX_WITH_GUEST_CONTROL
1878 ReturnComNotImplemented();
1879#else
1880 LogFlowThisFuncEnter();
1881
1882 AutoCaller autoCaller(this);
1883 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1884
1885 ReturnComNotImplemented();
1886#endif /* VBOX_WITH_GUEST_CONTROL */
1887}
1888
1889STDMETHODIMP GuestSession::ProcessCreate(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
1890 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS, IGuestProcess **aProcess)
1891{
1892#ifndef VBOX_WITH_GUEST_CONTROL
1893 ReturnComNotImplemented();
1894#else
1895 LogFlowThisFuncEnter();
1896
1897 com::SafeArray<LONG> affinity;
1898
1899 HRESULT hr = ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),
1900 ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess);
1901 return hr;
1902#endif /* VBOX_WITH_GUEST_CONTROL */
1903}
1904
1905STDMETHODIMP GuestSession::ProcessCreateEx(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
1906 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS,
1907 ProcessPriority_T aPriority, ComSafeArrayIn(LONG, aAffinity),
1908 IGuestProcess **aProcess)
1909{
1910#ifndef VBOX_WITH_GUEST_CONTROL
1911 ReturnComNotImplemented();
1912#else
1913 LogFlowThisFuncEnter();
1914
1915 if (RT_UNLIKELY((aCommand) == NULL || *(aCommand) == '\0'))
1916 return setError(E_INVALIDARG, tr("No command to execute specified"));
1917 CheckComArgOutPointerValid(aProcess);
1918
1919 AutoCaller autoCaller(this);
1920 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1921
1922 GuestProcessStartupInfo procInfo;
1923 procInfo.mCommand = Utf8Str(aCommand);
1924
1925 if (aArguments)
1926 {
1927 com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments));
1928 for (size_t i = 0; i < arguments.size(); i++)
1929 procInfo.mArguments.push_back(Utf8Str(arguments[i]));
1930 }
1931
1932 int rc = VINF_SUCCESS;
1933
1934 /*
1935 * Create the process environment:
1936 * - Apply the session environment in a first step, and
1937 * - Apply environment variables specified by this call to
1938 * have the chance of overwriting/deleting session entries.
1939 */
1940 procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
1941
1942 if (aEnvironment)
1943 {
1944 com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aEnvironment));
1945 for (size_t i = 0; i < environment.size() && RT_SUCCESS(rc); i++)
1946 rc = procInfo.mEnvironment.Set(Utf8Str(environment[i]));
1947 }
1948
1949 HRESULT hr = S_OK;
1950
1951 if (RT_SUCCESS(rc))
1952 {
1953 if (aFlags)
1954 {
1955 com::SafeArray<ProcessCreateFlag_T> flags(ComSafeArrayInArg(aFlags));
1956 for (size_t i = 0; i < flags.size(); i++)
1957 procInfo.mFlags |= flags[i];
1958 }
1959
1960 procInfo.mTimeoutMS = aTimeoutMS;
1961
1962 if (aAffinity)
1963 {
1964 com::SafeArray<LONG> affinity(ComSafeArrayInArg(aAffinity));
1965 for (size_t i = 0; i < affinity.size(); i++)
1966 procInfo.mAffinity[i] = affinity[i]; /** @todo Really necessary? Later. */
1967 }
1968
1969 procInfo.mPriority = aPriority;
1970
1971 ComObjPtr<GuestProcess> pProcess;
1972 rc = processCreateExInteral(procInfo, pProcess);
1973 if (RT_SUCCESS(rc))
1974 {
1975 /* Return guest session to the caller. */
1976 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
1977 if (FAILED(hr2))
1978 rc = VERR_COM_OBJECT_NOT_FOUND;
1979
1980 if (RT_SUCCESS(rc))
1981 rc = pProcess->startProcessAsync();
1982 }
1983 }
1984
1985 if (RT_FAILURE(rc))
1986 {
1987 switch (rc)
1988 {
1989 case VERR_MAX_PROCS_REACHED:
1990 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest processes per session (%ld) reached"),
1991 VBOX_GUESTCTRL_MAX_PROCESSES);
1992 break;
1993
1994 /** @todo Add more errors here. */
1995
1996 default:
1997 hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest process, rc=%Rrc"), rc);
1998 break;
1999 }
2000 }
2001
2002 LogFlowFuncLeaveRC(rc);
2003 return hr;
2004#endif /* VBOX_WITH_GUEST_CONTROL */
2005}
2006
2007STDMETHODIMP GuestSession::ProcessGet(ULONG aPID, IGuestProcess **aProcess)
2008{
2009#ifndef VBOX_WITH_GUEST_CONTROL
2010 ReturnComNotImplemented();
2011#else
2012 LogFlowThisFunc(("aPID=%RU32\n", aPID));
2013
2014 CheckComArgOutPointerValid(aProcess);
2015 if (aPID == 0)
2016 return setError(E_INVALIDARG, tr("No valid process ID (PID) specified"));
2017
2018 AutoCaller autoCaller(this);
2019 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2020
2021 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2022
2023 HRESULT hr = S_OK;
2024
2025 ComObjPtr<GuestProcess> pProcess;
2026 int rc = processGetByPID(aPID, &pProcess);
2027 if (RT_FAILURE(rc))
2028 hr = setError(E_INVALIDARG, tr("No process with PID %RU32 found"), aPID);
2029
2030 /* This will set (*aProcess) to NULL if pProgress is NULL. */
2031 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
2032 if (SUCCEEDED(hr))
2033 hr = hr2;
2034
2035 LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", *aProcess, hr));
2036 return hr;
2037#endif /* VBOX_WITH_GUEST_CONTROL */
2038}
2039
2040STDMETHODIMP GuestSession::SymlinkCreate(IN_BSTR aSource, IN_BSTR aTarget, SymlinkType_T aType)
2041{
2042#ifndef VBOX_WITH_GUEST_CONTROL
2043 ReturnComNotImplemented();
2044#else
2045 LogFlowThisFuncEnter();
2046
2047 AutoCaller autoCaller(this);
2048 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2049
2050 ReturnComNotImplemented();
2051#endif /* VBOX_WITH_GUEST_CONTROL */
2052}
2053
2054STDMETHODIMP GuestSession::SymlinkExists(IN_BSTR aSymlink, BOOL *aExists)
2055{
2056#ifndef VBOX_WITH_GUEST_CONTROL
2057 ReturnComNotImplemented();
2058#else
2059 LogFlowThisFuncEnter();
2060
2061 AutoCaller autoCaller(this);
2062 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2063
2064 ReturnComNotImplemented();
2065#endif /* VBOX_WITH_GUEST_CONTROL */
2066}
2067
2068STDMETHODIMP GuestSession::SymlinkRead(IN_BSTR aSymlink, ComSafeArrayIn(SymlinkReadFlag_T, aFlags), BSTR *aTarget)
2069{
2070#ifndef VBOX_WITH_GUEST_CONTROL
2071 ReturnComNotImplemented();
2072#else
2073 LogFlowThisFuncEnter();
2074
2075 AutoCaller autoCaller(this);
2076 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2077
2078 ReturnComNotImplemented();
2079#endif /* VBOX_WITH_GUEST_CONTROL */
2080}
2081
2082STDMETHODIMP GuestSession::SymlinkRemoveDirectory(IN_BSTR aPath)
2083{
2084#ifndef VBOX_WITH_GUEST_CONTROL
2085 ReturnComNotImplemented();
2086#else
2087 LogFlowThisFuncEnter();
2088
2089 AutoCaller autoCaller(this);
2090 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2091
2092 ReturnComNotImplemented();
2093#endif /* VBOX_WITH_GUEST_CONTROL */
2094}
2095
2096STDMETHODIMP GuestSession::SymlinkRemoveFile(IN_BSTR aFile)
2097{
2098#ifndef VBOX_WITH_GUEST_CONTROL
2099 ReturnComNotImplemented();
2100#else
2101 LogFlowThisFuncEnter();
2102
2103 AutoCaller autoCaller(this);
2104 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2105
2106 ReturnComNotImplemented();
2107#endif /* VBOX_WITH_GUEST_CONTROL */
2108}
2109
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