VirtualBox

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

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

Guest Control 2.0: Bugfixes.

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