VirtualBox

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

Last change on this file since 42619 was 42618, checked in by vboxsync, 13 years ago

Main/GuestCtrl: add FileRemove API. Untested.

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

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