VirtualBox

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

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

Guest Control 2.0: Update.

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