VirtualBox

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

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

Main/GuestControl: forgot to actually start the mktemp process.

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