VirtualBox

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

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

Main/GuestCtrl: split off the implementation of FileRemove into fileRemoveInternal.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 84.4 KB
Line 
1
2/* $Id: GuestSessionImpl.cpp 42691 2012-08-08 19:15:02Z 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
1174/**
1175 * Implementation of FileRemove(). Can throw an exception due to the use of
1176 * Utf8Str, Utf8StrFmt and std::vector near the beginning (and others?). The
1177 * caller should catch this. On success, *prc will be set to the return code
1178 * of the delete operation to distinguish between API and command failure.
1179 */
1180int GuestSession::fileRemoveInternal(Utf8Str strPath, int *prc)
1181{
1182 GuestProcessStartupInfo procInfo;
1183 GuestProcessStream streamOut;
1184 int rc = VINF_SUCCESS;
1185
1186 AssertPtrReturn(prc, VERR_INVALID_POINTER);
1187 procInfo.mName = Utf8StrFmt(tr("Removing file \"%s\"",
1188 strPath.c_str()));
1189 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_RM);
1190 procInfo.mFlags = ProcessCreateFlag_Hidden
1191 | ProcessCreateFlag_WaitForStdOut;
1192 /* Construct arguments. */
1193 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
1194 procInfo.mArguments.push_back(strPath); /* The directory we want to create. */
1195
1196 ComObjPtr<GuestProcess> pProcess;
1197 rc = processCreateExInteral(procInfo, pProcess);
1198 if (RT_SUCCESS(rc))
1199 rc = pProcess->startProcess();
1200 if (RT_SUCCESS(rc))
1201 {
1202 GuestProcessWaitResult waitRes;
1203 BYTE byBuf[_64K];
1204 size_t cbRead;
1205
1206 for (;;)
1207 {
1208 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
1209 30 * 1000 /* Timeout */, waitRes);
1210 if ( RT_FAILURE(rc)
1211 || waitRes.mResult == ProcessWaitResult_Terminate
1212 || waitRes.mResult == ProcessWaitResult_Error
1213 || waitRes.mResult == ProcessWaitResult_Timeout)
1214 {
1215 break;
1216 }
1217
1218 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
1219 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
1220 &cbRead);
1221 if (RT_FAILURE(rc))
1222 break;
1223
1224 if (cbRead)
1225 {
1226 rc = streamOut.AddData(byBuf, cbRead);
1227 if (RT_FAILURE(rc))
1228 break;
1229 }
1230 }
1231
1232 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n",
1233 rc, cbRead, streamOut.GetSize()));
1234 }
1235 else
1236 LogThisFunc(("Error starting delete tool on guest: %Rrc\n", rc));
1237 if (RT_FAILURE(rc))
1238 LogThisFunc(("Error running delete tool on guest: %Rrc\n", rc));
1239 else if (!streamOut.GetSize())
1240 {
1241 LogThisFunc(("No return code after deleting file"));
1242 rc = VERR_NO_DATA;
1243 }
1244 if (RT_SUCCESS(rc))
1245 {
1246 GuestProcessStreamBlock streamBlock;
1247 int64_t i64rc;
1248 rc = streamOut.ParseBlock(streamBlock);
1249 streamBlock.GetString("fname");
1250 rc = streamBlock.GetInt64Ex("rc", &i64rc);
1251 if (RT_SUCCESS(rc))
1252 *prc = (int)i64rc;
1253 }
1254 else
1255 Log(("Error getting return code from deleting file: %Rrc\n", rc));
1256 return rc;
1257}
1258
1259int GuestSession::fileOpenInternal(const Utf8Str &strPath, const Utf8Str &strOpenMode, const Utf8Str &strDisposition,
1260 uint32_t uCreationMode, int64_t iOffset, ComObjPtr<GuestFile> &pFile)
1261{
1262 LogFlowThisFunc(("strPath=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%x, iOffset=%RI64\n",
1263 strPath.c_str(), strOpenMode.c_str(), strDisposition.c_str(), uCreationMode, iOffset));
1264 int rc;
1265
1266 try
1267 {
1268 /* Create the directory object. */
1269 HRESULT hr = pFile.createObject();
1270 if (FAILED(hr)) throw VERR_COM_UNEXPECTED;
1271
1272 /* Note: There will be a race between creating and getting/initing the directory
1273 object here. */
1274 rc = pFile->init(this /* Parent */,
1275 strPath, strOpenMode, strDisposition, uCreationMode, iOffset);
1276 if (RT_FAILURE(rc)) throw rc;
1277
1278 /* Add the created directory to our vector. */
1279 mData.mFiles.push_back(pFile);
1280
1281 LogFlowFunc(("Added new file \"%s\" (Session: %RU32\n",
1282 strPath.c_str(), mData.mId));
1283 }
1284 catch (int rc2)
1285 {
1286 rc = rc2;
1287 }
1288
1289 LogFlowFuncLeaveRC(rc);
1290 return rc;
1291}
1292
1293/* Note: Will work on directories and others, too. */
1294int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData)
1295{
1296 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
1297
1298 GuestProcessStartupInfo procInfo;
1299 procInfo.mName = Utf8StrFmt(tr("Querying info for \"%s\""), strPath.c_str());
1300 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT);
1301 procInfo.mFlags = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
1302
1303 /* Construct arguments. */
1304 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
1305 procInfo.mArguments.push_back(strPath);
1306
1307 GuestProcessStream streamOut;
1308
1309 ComObjPtr<GuestProcess> pProcess;
1310 int rc = processCreateExInteral(procInfo, pProcess);
1311 if (RT_SUCCESS(rc))
1312 rc = pProcess->startProcess();
1313 if (RT_SUCCESS(rc))
1314 {
1315 GuestProcessWaitResult waitRes;
1316 BYTE byBuf[_64K];
1317 size_t cbRead = 0;
1318
1319 /** @todo Merge with GuestDirectory::read. */
1320 for (;;)
1321 {
1322 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
1323 30 * 1000 /* Timeout */, waitRes);
1324 if ( RT_FAILURE(rc)
1325 || waitRes.mResult == ProcessWaitResult_Terminate
1326 || waitRes.mResult == ProcessWaitResult_Error
1327 || waitRes.mResult == ProcessWaitResult_Timeout)
1328 {
1329 break;
1330 }
1331
1332 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
1333 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
1334 &cbRead);
1335 if (RT_FAILURE(rc))
1336 break;
1337
1338 if (cbRead)
1339 {
1340 rc = streamOut.AddData(byBuf, cbRead);
1341 if (RT_FAILURE(rc))
1342 break;
1343 }
1344 }
1345
1346 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64, cbStreamOut=%RU32\n",
1347 rc, cbRead, streamOut.GetSize()));
1348 }
1349
1350 if (RT_SUCCESS(rc))
1351 {
1352 GuestProcessStreamBlock streamBlock;
1353 rc = streamOut.ParseBlock(streamBlock);
1354 if (RT_SUCCESS(rc))
1355 {
1356 rc = objData.FromStat(streamBlock);
1357 }
1358 else
1359 AssertMsgFailed(("Parsing stream block failed: %Rrc\n", rc));
1360 }
1361
1362 LogFlowFuncLeaveRC(rc);
1363 return rc;
1364}
1365
1366int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize)
1367{
1368 AssertPtrReturn(pllSize, VERR_INVALID_POINTER);
1369
1370 GuestFsObjData objData;
1371 int rc = fileQueryInfoInternal(strPath, objData);
1372 if (RT_SUCCESS(rc))
1373 {
1374 if (objData.mType == FsObjType_File)
1375 *pllSize = objData.mObjectSize;
1376 else
1377 rc = VERR_NOT_A_FILE;
1378 }
1379
1380 return rc;
1381}
1382
1383const GuestCredentials& GuestSession::getCredentials(void)
1384{
1385 return mData.mCredentials;
1386}
1387
1388const GuestEnvironment& GuestSession::getEnvironment(void)
1389{
1390 return mData.mEnvironment;
1391}
1392
1393Utf8Str GuestSession::getName(void)
1394{
1395 return mData.mName;
1396}
1397
1398int GuestSession::processClose(ComObjPtr<GuestProcess> pProcess)
1399{
1400 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1401
1402 for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();
1403 itProcs != mData.mProcesses.end(); ++itProcs)
1404 {
1405 if (pProcess == itProcs->second)
1406 {
1407 LogFlowFunc(("Removing process (Session: %RU32) with process ID=%RU32, guest PID=%RU32 (now total %ld processes)\n",
1408 mData.mId, itProcs->second->getProcessID(), itProcs->second->getPID(), mData.mProcesses.size() - 1));
1409
1410 mData.mProcesses.erase(itProcs);
1411 return VINF_SUCCESS;
1412 }
1413 }
1414
1415 return VERR_NOT_FOUND;
1416}
1417
1418/**
1419 * Creates but does *not* start the process yet. See GuestProcess::startProcess() or
1420 * GuestProcess::startProcessAsync() for that.
1421 *
1422 * @return IPRT status code.
1423 * @param procInfo
1424 * @param pProcess
1425 */
1426int GuestSession::processCreateExInteral(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
1427{
1428 LogFlowFunc(("mCmd=%s, mFlags=%x, mTimeoutMS=%RU32\n",
1429 procInfo.mCommand.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));
1430#ifdef DEBUG
1431 if (procInfo.mArguments.size())
1432 {
1433 LogFlowFunc(("Arguments:"));
1434 ProcessArguments::const_iterator it = procInfo.mArguments.begin();
1435 while (it != procInfo.mArguments.end())
1436 {
1437 LogFlow((" %s", (*it).c_str()));
1438 it++;
1439 }
1440 LogFlow(("\n"));
1441 }
1442#endif
1443
1444 /* Validate flags. */
1445 if (procInfo.mFlags)
1446 {
1447 if ( !(procInfo.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
1448 && !(procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1449 && !(procInfo.mFlags & ProcessCreateFlag_Hidden)
1450 && !(procInfo.mFlags & ProcessCreateFlag_NoProfile)
1451 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1452 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdErr))
1453 {
1454 return VERR_INVALID_PARAMETER;
1455 }
1456 }
1457
1458 /* Adjust timeout. If set to 0, we define
1459 * an infinite timeout. */
1460 if (procInfo.mTimeoutMS == 0)
1461 procInfo.mTimeoutMS = UINT32_MAX;
1462
1463 /** @tood Implement process priority + affinity. */
1464
1465 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1466
1467 int rc = VERR_MAX_PROCS_REACHED;
1468 if (mData.mProcesses.size() >= VBOX_GUESTCTRL_MAX_PROCESSES)
1469 return rc;
1470
1471 /* Create a new (host-based) process ID and assign it. */
1472 uint32_t uNewProcessID = 0;
1473 ULONG uTries = 0;
1474
1475 for (;;)
1476 {
1477 /* Is the context ID already used? */
1478 if (!processExists(uNewProcessID, NULL /* pProgress */))
1479 {
1480 /* Callback with context ID was not found. This means
1481 * we can use this context ID for our new callback we want
1482 * to add below. */
1483 rc = VINF_SUCCESS;
1484 break;
1485 }
1486 uNewProcessID++;
1487 if (uNewProcessID == VBOX_GUESTCTRL_MAX_PROCESSES)
1488 uNewProcessID = 0;
1489
1490 if (++uTries == UINT32_MAX)
1491 break; /* Don't try too hard. */
1492 }
1493 if (RT_FAILURE(rc)) return rc;
1494
1495 try
1496 {
1497 /* Create the process object. */
1498 HRESULT hr = pProcess.createObject();
1499 if (FAILED(hr)) throw VERR_COM_UNEXPECTED;
1500
1501 rc = pProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */,
1502 uNewProcessID, procInfo);
1503 if (RT_FAILURE(rc)) throw rc;
1504
1505 /* Add the created process to our map. */
1506 mData.mProcesses[uNewProcessID] = pProcess;
1507
1508 LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes)\n",
1509 mData.mId, uNewProcessID, mData.mProcesses.size()));
1510 }
1511 catch (int rc2)
1512 {
1513 rc = rc2;
1514 }
1515
1516 return rc;
1517}
1518
1519inline bool GuestSession::processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess)
1520{
1521 SessionProcesses::const_iterator it = mData.mProcesses.find(uProcessID);
1522 if (it != mData.mProcesses.end())
1523 {
1524 if (pProcess)
1525 *pProcess = it->second;
1526 return true;
1527 }
1528 return false;
1529}
1530
1531inline int GuestSession::processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess)
1532{
1533 AssertReturn(uPID, false);
1534 /* pProcess is optional. */
1535
1536 SessionProcesses::iterator it = mData.mProcesses.begin();
1537 for (; it != mData.mProcesses.end(); it++)
1538 {
1539 ComObjPtr<GuestProcess> pCurProc = it->second;
1540 AutoCaller procCaller(pCurProc);
1541 if (procCaller.rc())
1542 return VERR_COM_INVALID_OBJECT_STATE;
1543
1544 if (it->second->getPID() == uPID)
1545 {
1546 if (pProcess)
1547 *pProcess = pCurProc;
1548 return VINF_SUCCESS;
1549 }
1550 }
1551
1552 return VERR_NOT_FOUND;
1553}
1554
1555int GuestSession::startTaskAsync(const Utf8Str &strTaskDesc,
1556 GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress)
1557{
1558 LogFlowThisFunc(("strTaskDesc=%s, pTask=%p\n", strTaskDesc.c_str(), pTask));
1559
1560 AssertPtrReturn(pTask, VERR_INVALID_POINTER);
1561
1562 int rc;
1563
1564 try
1565 {
1566 /* Create the progress object. */
1567 HRESULT hr = pProgress.createObject();
1568 if (FAILED(hr)) throw VERR_COM_UNEXPECTED;
1569
1570 hr = pProgress->init(static_cast<IGuestSession*>(this),
1571 Bstr(strTaskDesc).raw(),
1572 TRUE /* aCancelable */);
1573 if (FAILED(hr)) throw VERR_COM_UNEXPECTED;
1574
1575 /* Initialize our worker task. */
1576 std::auto_ptr<GuestSessionTask> task(pTask);
1577
1578 rc = task->RunAsync(strTaskDesc, pProgress);
1579 if (FAILED(rc)) throw rc;
1580
1581 /* Don't destruct on success. */
1582 task.release();
1583 }
1584 catch (int rc2)
1585 {
1586 rc = rc2;
1587 }
1588
1589 LogFlowFuncLeaveRC(rc);
1590 return rc;
1591}
1592
1593/**
1594 * Queries/collects information prior to establishing a guest session.
1595 * This is necessary to know which guest control protocol version to use,
1596 * among other things (later).
1597 *
1598 * @return IPRT status code.
1599 */
1600int GuestSession::queryInfo(void)
1601{
1602#if 1
1603 /* Since the new functions were not implemented yet, force Main to use protocol ver 1. */
1604 mData.mProtocolVersion = 1;
1605#else
1606 /*
1607 * Try querying the guest control protocol version running on the guest.
1608 * This is done using the Guest Additions version
1609 */
1610 ComObjPtr<Guest> pGuest = mData.mParent;
1611 Assert(!pGuest.isNull());
1612
1613 uint32_t uVerAdditions = pGuest->getAdditionsVersion();
1614 mData.mProtocolVersion = ( VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions) >= 4
1615 && VBOX_FULL_VERSION_GET_MINOR(uVerAdditions) >= 2) /** @todo What's about v5.0 ? */
1616 ? 2 /* Guest control 2.0. */
1617 : 1; /* Legacy guest control (VBox < 4.2). */
1618 /* Build revision is ignored. */
1619
1620 /* Tell the user but don't bitch too often. */
1621 static short s_gctrlLegacyWarning = 0;
1622 if (s_gctrlLegacyWarning++ < 3) /** @todo Find a bit nicer text. */
1623 LogRel((tr("Warning: Guest Additions are older (%ld.%ld) than host capabilities for guest control, please upgrade them. Using protocol version %ld now\n"),
1624 VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions), VBOX_FULL_VERSION_GET_MINOR(uVerAdditions), mData.mProtocolVersion));
1625#endif
1626 return VINF_SUCCESS;
1627}
1628
1629// implementation of public methods
1630/////////////////////////////////////////////////////////////////////////////
1631
1632STDMETHODIMP GuestSession::Close(void)
1633{
1634#ifndef VBOX_WITH_GUEST_CONTROL
1635 ReturnComNotImplemented();
1636#else
1637 LogFlowThisFuncEnter();
1638
1639 uninit();
1640
1641 LogFlowFuncLeaveRC(S_OK);
1642 return S_OK;
1643#endif /* VBOX_WITH_GUEST_CONTROL */
1644}
1645
1646STDMETHODIMP GuestSession::CopyFrom(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
1647{
1648#ifndef VBOX_WITH_GUEST_CONTROL
1649 ReturnComNotImplemented();
1650#else
1651 CheckComArgStrNotEmptyOrNull(aSource);
1652 CheckComArgStrNotEmptyOrNull(aDest);
1653 CheckComArgOutPointerValid(aProgress);
1654
1655 LogFlowThisFuncEnter();
1656
1657 if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
1658 return setError(E_INVALIDARG, tr("No source specified"));
1659 if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
1660 return setError(E_INVALIDARG, tr("No destination specified"));
1661
1662 AutoCaller autoCaller(this);
1663 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1664
1665 uint32_t fFlags = CopyFileFlag_None;
1666 if (aFlags)
1667 {
1668 com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
1669 for (size_t i = 0; i < flags.size(); i++)
1670 fFlags |= flags[i];
1671 }
1672
1673 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1674
1675 HRESULT hr = S_OK;
1676
1677 ComObjPtr<Progress> pProgress;
1678 SessionTaskCopyFrom *pTask = new SessionTaskCopyFrom(this /* GuestSession */,
1679 Utf8Str(aSource), Utf8Str(aDest), fFlags);
1680 AssertPtrReturn(pTask, VERR_NO_MEMORY);
1681 int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from guest to \"%ls\" on the host"), aSource, aDest),
1682 pTask, pProgress);
1683 if (RT_SUCCESS(rc))
1684 {
1685 /* Return progress to the caller. */
1686 hr = pProgress.queryInterfaceTo(aProgress);
1687 }
1688 else
1689 hr = setError(VBOX_E_IPRT_ERROR,
1690 tr("Starting task for copying file \"%ls\" from guest to \"%ls\" on the host failed: %Rrc"), rc);
1691 return hr;
1692#endif /* VBOX_WITH_GUEST_CONTROL */
1693}
1694
1695STDMETHODIMP GuestSession::CopyTo(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
1696{
1697#ifndef VBOX_WITH_GUEST_CONTROL
1698 ReturnComNotImplemented();
1699#else
1700 CheckComArgStrNotEmptyOrNull(aSource);
1701 CheckComArgStrNotEmptyOrNull(aDest);
1702 CheckComArgOutPointerValid(aProgress);
1703
1704 LogFlowThisFuncEnter();
1705
1706 if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
1707 return setError(E_INVALIDARG, tr("No source specified"));
1708 if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
1709 return setError(E_INVALIDARG, tr("No destination specified"));
1710
1711 AutoCaller autoCaller(this);
1712 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1713
1714 uint32_t fFlags = CopyFileFlag_None;
1715 if (aFlags)
1716 {
1717 com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
1718 for (size_t i = 0; i < flags.size(); i++)
1719 fFlags |= flags[i];
1720 }
1721
1722 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1723
1724 HRESULT hr = S_OK;
1725
1726 ComObjPtr<Progress> pProgress;
1727 SessionTaskCopyTo *pTask = new SessionTaskCopyTo(this /* GuestSession */,
1728 Utf8Str(aSource), Utf8Str(aDest), fFlags);
1729 AssertPtrReturn(pTask, VERR_NO_MEMORY);
1730 int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from host to \"%ls\" on the guest"), aSource, aDest),
1731 pTask, pProgress);
1732 if (RT_SUCCESS(rc))
1733 {
1734 /* Return progress to the caller. */
1735 hr = pProgress.queryInterfaceTo(aProgress);
1736 }
1737 else
1738 hr = setError(VBOX_E_IPRT_ERROR,
1739 tr("Starting task for copying file \"%ls\" from host to \"%ls\" on the guest failed: %Rrc"), rc);
1740 return hr;
1741#endif /* VBOX_WITH_GUEST_CONTROL */
1742}
1743
1744STDMETHODIMP GuestSession::DirectoryCreate(IN_BSTR aPath, ULONG aMode,
1745 ComSafeArrayIn(DirectoryCreateFlag_T, aFlags), IGuestDirectory **aDirectory)
1746{
1747#ifndef VBOX_WITH_GUEST_CONTROL
1748 ReturnComNotImplemented();
1749#else
1750 LogFlowThisFuncEnter();
1751
1752 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1753 return setError(E_INVALIDARG, tr("No directory to create specified"));
1754 /* aDirectory is optional. */
1755
1756 AutoCaller autoCaller(this);
1757 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1758
1759 uint32_t fFlags = DirectoryCreateFlag_None;
1760 if (aFlags)
1761 {
1762 com::SafeArray<DirectoryCreateFlag_T> flags(ComSafeArrayInArg(aFlags));
1763 for (size_t i = 0; i < flags.size(); i++)
1764 fFlags |= flags[i];
1765
1766 if (fFlags)
1767 {
1768 if (!(fFlags & DirectoryCreateFlag_Parents))
1769 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), fFlags);
1770 }
1771 }
1772
1773 HRESULT hr = S_OK;
1774
1775 ComObjPtr <GuestDirectory> pDirectory;
1776 int rc = directoryCreateInternal(Utf8Str(aPath), (uint32_t)aMode, fFlags, pDirectory);
1777 if (RT_SUCCESS(rc))
1778 {
1779 if (aDirectory)
1780 {
1781 /* Return directory object to the caller. */
1782 hr = pDirectory.queryInterfaceTo(aDirectory);
1783 }
1784 else
1785 {
1786 rc = directoryClose(pDirectory);
1787 if (RT_FAILURE(rc))
1788 hr = setError(VBOX_E_IPRT_ERROR, tr("Unable to close directory object, rc=%Rrc"), rc);
1789 }
1790 }
1791 else
1792 {
1793 switch (rc)
1794 {
1795 case VERR_INVALID_PARAMETER:
1796 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Invalid parameters given"));
1797 break;
1798
1799 case VERR_BROKEN_PIPE:
1800 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Unexpectedly aborted"));
1801 break;
1802
1803 case VERR_CANT_CREATE:
1804 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Could not create directory"));
1805 break;
1806
1807 default:
1808 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
1809 break;
1810 }
1811 }
1812
1813 return hr;
1814#endif /* VBOX_WITH_GUEST_CONTROL */
1815}
1816
1817STDMETHODIMP GuestSession::DirectoryCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aName, IGuestDirectory **aDirectory)
1818{
1819#ifndef VBOX_WITH_GUEST_CONTROL
1820 ReturnComNotImplemented();
1821#else
1822 LogFlowThisFuncEnter();
1823
1824 if (RT_UNLIKELY((aTemplate) == NULL || *(aTemplate) == '\0'))
1825 return setError(E_INVALIDARG, tr("No file to remove specified"));
1826
1827 AutoCaller autoCaller(this);
1828 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1829
1830 GuestProcessStartupInfo procInfo;
1831 GuestProcessStream streamOut;
1832 int rc = VINF_SUCCESS;
1833
1834 try /* Can this be done without exceptions? */
1835 {
1836 Utf8Str strTemplate(aTemplate);
1837 procInfo.mName = Utf8StrFmt(tr("Creating temporary directory from template \"%s\"",
1838 strTemplate.c_str()));
1839 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
1840 procInfo.mFlags = ProcessCreateFlag_Hidden
1841 | ProcessCreateFlag_WaitForStdOut;
1842 /* Construct arguments. */
1843 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
1844 procInfo.mArguments.push_back(Bstr(aTemplate)); /* The template we want to use. */
1845 }
1846 catch (...)
1847 {
1848 return E_OUTOFMEMORY;
1849 }
1850
1851 ComObjPtr<GuestProcess> pProcess;
1852 rc = processCreateExInteral(procInfo, pProcess);
1853 if (RT_SUCCESS(rc))
1854 {
1855 GuestProcessWaitResult waitRes;
1856 BYTE byBuf[_64K];
1857 size_t cbRead;
1858
1859 for (;;)
1860 {
1861 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
1862 30 * 1000 /* Timeout */, waitRes);
1863 if ( RT_FAILURE(rc)
1864 || waitRes.mResult == ProcessWaitResult_Terminate
1865 || waitRes.mResult == ProcessWaitResult_Error
1866 || waitRes.mResult == ProcessWaitResult_Timeout)
1867 {
1868 break;
1869 }
1870
1871 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
1872 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
1873 &cbRead);
1874 if (RT_FAILURE(rc))
1875 break;
1876
1877 if (cbRead)
1878 {
1879 rc = streamOut.AddData(byBuf, cbRead);
1880 if (RT_FAILURE(rc))
1881 break;
1882 }
1883 }
1884
1885 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n",
1886 rc, cbRead, streamOut.GetSize()));
1887 }
1888 else
1889 return setError(E_FAIL, tr("Error while starting temporary directory creation tool on guest: %Rrc"), rc);
1890 if (RT_FAILURE(rc))
1891 return setError(E_FAIL, tr("Error while running temporary directory creation tool: %Rrc"), rc);
1892 if (!streamOut.GetSize())
1893 return setError(E_FAIL, tr("No return code after creating temporary directory"));
1894 GuestProcessStreamBlock streamBlock;
1895 rc = streamOut.ParseBlock(streamBlock);
1896 if (RT_SUCCESS(rc))
1897 {
1898 streamBlock.GetString("name");
1899 int64_t i64rc;
1900 if (RT_FAILURE(streamBlock.GetInt64Ex("rc", &i64rc)))
1901 return setError(E_FAIL, tr("No return code after creating temporary directory"));
1902 if (RT_FAILURE((int)i64rc))
1903 return setError(VBOX_E_IPRT_ERROR, tr("File deletion failed: %Rrc"), rc);
1904 }
1905 else
1906 return setError(E_FAIL, tr("Error while getting return code from creating temporary directory: %Rrc"), rc);
1907 return S_OK;
1908#endif /* VBOX_WITH_GUEST_CONTROL */
1909}
1910
1911STDMETHODIMP GuestSession::DirectoryExists(IN_BSTR aPath, BOOL *aExists)
1912{
1913#ifndef VBOX_WITH_GUEST_CONTROL
1914 ReturnComNotImplemented();
1915#else
1916 LogFlowThisFuncEnter();
1917
1918 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1919 return setError(E_INVALIDARG, tr("No directory to check existence for specified"));
1920 CheckComArgOutPointerValid(aExists);
1921
1922 AutoCaller autoCaller(this);
1923 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1924
1925 HRESULT hr = S_OK;
1926
1927 GuestFsObjData objData;
1928 int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
1929 if (RT_SUCCESS(rc))
1930 {
1931 *aExists = objData.mType == FsObjType_Directory;
1932 }
1933 else
1934 {
1935 switch (rc)
1936 {
1937 /** @todo Add more errors here! */
1938
1939 default:
1940 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence failed: %Rrc"), rc);
1941 break;
1942 }
1943 }
1944
1945 return hr;
1946#endif /* VBOX_WITH_GUEST_CONTROL */
1947}
1948
1949STDMETHODIMP GuestSession::DirectoryOpen(IN_BSTR aPath, IN_BSTR aFilter, ComSafeArrayIn(DirectoryOpenFlag_T, aFlags), IGuestDirectory **aDirectory)
1950{
1951#ifndef VBOX_WITH_GUEST_CONTROL
1952 ReturnComNotImplemented();
1953#else
1954 LogFlowThisFuncEnter();
1955
1956 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1957 return setError(E_INVALIDARG, tr("No directory to open specified"));
1958 if (RT_UNLIKELY((aFilter) != NULL && *(aFilter) != '\0'))
1959 return setError(E_INVALIDARG, tr("Directory filters not implemented yet"));
1960
1961 CheckComArgOutPointerValid(aDirectory);
1962
1963 AutoCaller autoCaller(this);
1964 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1965
1966 uint32_t fFlags = DirectoryOpenFlag_None;
1967 if (aFlags)
1968 {
1969 com::SafeArray<DirectoryOpenFlag_T> flags(ComSafeArrayInArg(aFlags));
1970 for (size_t i = 0; i < flags.size(); i++)
1971 fFlags |= flags[i];
1972
1973 if (fFlags)
1974 return setError(E_INVALIDARG, tr("Open flags (%#x) not implemented yet"), fFlags);
1975 }
1976
1977 HRESULT hr = S_OK;
1978
1979 ComObjPtr <GuestDirectory> pDirectory;
1980 int rc = directoryOpenInternal(Utf8Str(aPath), Utf8Str(aFilter), fFlags, pDirectory);
1981 if (RT_SUCCESS(rc))
1982 {
1983 if (aDirectory)
1984 {
1985 /* Return directory object to the caller. */
1986 hr = pDirectory.queryInterfaceTo(aDirectory);
1987 }
1988 else
1989 {
1990 rc = directoryClose(pDirectory);
1991 if (RT_FAILURE(rc))
1992 hr = setError(VBOX_E_IPRT_ERROR, tr("Unable to close directory object, rc=%Rrc"), rc);
1993 }
1994 }
1995 else
1996 {
1997 switch (rc)
1998 {
1999 case VERR_INVALID_PARAMETER:
2000 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Invalid parameters given"));
2001 break;
2002
2003 case VERR_BROKEN_PIPE:
2004 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Unexpectedly aborted"));
2005 break;
2006
2007 default:
2008 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: %Rrc"), rc);
2009 break;
2010 }
2011 }
2012
2013 return hr;
2014#endif /* VBOX_WITH_GUEST_CONTROL */
2015}
2016
2017STDMETHODIMP GuestSession::DirectoryQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
2018{
2019#ifndef VBOX_WITH_GUEST_CONTROL
2020 ReturnComNotImplemented();
2021#else
2022 LogFlowThisFuncEnter();
2023
2024 AutoCaller autoCaller(this);
2025 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2026
2027 ReturnComNotImplemented();
2028#endif /* VBOX_WITH_GUEST_CONTROL */
2029}
2030
2031STDMETHODIMP GuestSession::DirectoryRemove(IN_BSTR aPath)
2032{
2033#ifndef VBOX_WITH_GUEST_CONTROL
2034 ReturnComNotImplemented();
2035#else
2036 LogFlowThisFuncEnter();
2037
2038 AutoCaller autoCaller(this);
2039 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2040
2041 ReturnComNotImplemented();
2042#endif /* VBOX_WITH_GUEST_CONTROL */
2043}
2044
2045STDMETHODIMP GuestSession::DirectoryRemoveRecursive(IN_BSTR aPath, ComSafeArrayIn(DirectoryRemoveRecFlag_T, aFlags), IProgress **aProgress)
2046{
2047#ifndef VBOX_WITH_GUEST_CONTROL
2048 ReturnComNotImplemented();
2049#else
2050 LogFlowThisFuncEnter();
2051
2052 AutoCaller autoCaller(this);
2053 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2054
2055 ReturnComNotImplemented();
2056#endif /* VBOX_WITH_GUEST_CONTROL */
2057}
2058
2059STDMETHODIMP GuestSession::DirectoryRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
2060{
2061#ifndef VBOX_WITH_GUEST_CONTROL
2062 ReturnComNotImplemented();
2063#else
2064 LogFlowThisFuncEnter();
2065
2066 AutoCaller autoCaller(this);
2067 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2068
2069 ReturnComNotImplemented();
2070#endif /* VBOX_WITH_GUEST_CONTROL */
2071}
2072
2073STDMETHODIMP GuestSession::DirectorySetACL(IN_BSTR aPath, IN_BSTR aACL)
2074{
2075#ifndef VBOX_WITH_GUEST_CONTROL
2076 ReturnComNotImplemented();
2077#else
2078 LogFlowThisFuncEnter();
2079
2080 AutoCaller autoCaller(this);
2081 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2082
2083 ReturnComNotImplemented();
2084#endif /* VBOX_WITH_GUEST_CONTROL */
2085}
2086
2087STDMETHODIMP GuestSession::EnvironmentClear(void)
2088{
2089#ifndef VBOX_WITH_GUEST_CONTROL
2090 ReturnComNotImplemented();
2091#else
2092 LogFlowThisFuncEnter();
2093
2094 AutoCaller autoCaller(this);
2095 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2096
2097 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2098
2099 mData.mEnvironment.Clear();
2100
2101 LogFlowFuncLeaveRC(S_OK);
2102 return S_OK;
2103#endif /* VBOX_WITH_GUEST_CONTROL */
2104}
2105
2106STDMETHODIMP GuestSession::EnvironmentGet(IN_BSTR aName, BSTR *aValue)
2107{
2108#ifndef VBOX_WITH_GUEST_CONTROL
2109 ReturnComNotImplemented();
2110#else
2111 LogFlowThisFuncEnter();
2112
2113 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
2114 return setError(E_INVALIDARG, tr("No value name specified"));
2115
2116 CheckComArgOutPointerValid(aValue);
2117
2118 AutoCaller autoCaller(this);
2119 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2120
2121 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2122
2123 Bstr strValue(mData.mEnvironment.Get(Utf8Str(aName)));
2124 strValue.cloneTo(aValue);
2125
2126 LogFlowFuncLeaveRC(S_OK);
2127 return S_OK;
2128#endif /* VBOX_WITH_GUEST_CONTROL */
2129}
2130
2131STDMETHODIMP GuestSession::EnvironmentSet(IN_BSTR aName, IN_BSTR aValue)
2132{
2133#ifndef VBOX_WITH_GUEST_CONTROL
2134 ReturnComNotImplemented();
2135#else
2136 LogFlowThisFuncEnter();
2137
2138 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
2139 return setError(E_INVALIDARG, tr("No value name specified"));
2140
2141 AutoCaller autoCaller(this);
2142 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2143
2144 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2145
2146 int rc = mData.mEnvironment.Set(Utf8Str(aName), Utf8Str(aValue));
2147
2148 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
2149 LogFlowFuncLeaveRC(hr);
2150 return hr;
2151#endif /* VBOX_WITH_GUEST_CONTROL */
2152}
2153
2154STDMETHODIMP GuestSession::EnvironmentUnset(IN_BSTR aName)
2155{
2156#ifndef VBOX_WITH_GUEST_CONTROL
2157 ReturnComNotImplemented();
2158#else
2159 LogFlowThisFuncEnter();
2160
2161 AutoCaller autoCaller(this);
2162 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2163
2164 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2165
2166 mData.mEnvironment.Unset(Utf8Str(aName));
2167
2168 LogFlowFuncLeaveRC(S_OK);
2169 return S_OK;
2170#endif /* VBOX_WITH_GUEST_CONTROL */
2171}
2172
2173STDMETHODIMP GuestSession::FileCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aName, IGuestFile **aFile)
2174{
2175#ifndef VBOX_WITH_GUEST_CONTROL
2176 ReturnComNotImplemented();
2177#else
2178 LogFlowThisFuncEnter();
2179
2180 AutoCaller autoCaller(this);
2181 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2182
2183 ReturnComNotImplemented();
2184#endif /* VBOX_WITH_GUEST_CONTROL */
2185}
2186
2187STDMETHODIMP GuestSession::FileExists(IN_BSTR aPath, BOOL *aExists)
2188{
2189#ifndef VBOX_WITH_GUEST_CONTROL
2190 ReturnComNotImplemented();
2191#else
2192 LogFlowThisFuncEnter();
2193
2194 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2195 return setError(E_INVALIDARG, tr("No file to check existence for specified"));
2196 CheckComArgOutPointerValid(aExists);
2197
2198 AutoCaller autoCaller(this);
2199 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2200
2201 HRESULT hr = S_OK;
2202
2203 GuestFsObjData objData;
2204 int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
2205 if (RT_SUCCESS(rc))
2206 {
2207 *aExists = objData.mType == FsObjType_File;
2208 }
2209 else
2210 {
2211 switch (rc)
2212 {
2213 /** @todo Add more errors here! */
2214
2215 default:
2216 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file existence failed: %Rrc"), rc);
2217 break;
2218 }
2219 }
2220
2221 return hr;
2222#endif /* VBOX_WITH_GUEST_CONTROL */
2223}
2224
2225STDMETHODIMP GuestSession::FileRemove(IN_BSTR aPath)
2226{
2227#ifndef VBOX_WITH_GUEST_CONTROL
2228 ReturnComNotImplemented();
2229#else
2230 LogFlowThisFuncEnter();
2231
2232 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2233 return setError(E_INVALIDARG, tr("No file to remove specified"));
2234
2235 AutoCaller autoCaller(this);
2236 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2237
2238 try /* Can this be done without exceptions? */
2239 {
2240 int rc2;
2241 int rc = fileRemoveInternal(Utf8Str(aPath), &rc2);
2242 if (RT_FAILURE((rc)))
2243 return setError(E_FAIL,
2244 tr("Internal error deleting file: %Rrc"), rc);
2245 else if (RT_FAILURE((rc2)))
2246 return setError(VBOX_E_IPRT_ERROR,
2247 tr("File deletion on guest returned: %Rrc"), rc2);
2248 }
2249 catch (...)
2250 {
2251 return E_OUTOFMEMORY;
2252 }
2253 return S_OK;
2254#endif /* VBOX_WITH_GUEST_CONTROL */
2255}
2256
2257STDMETHODIMP GuestSession::FileOpen(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, ULONG aCreationMode, LONG64 aOffset, IGuestFile **aFile)
2258{
2259#ifndef VBOX_WITH_GUEST_CONTROL
2260 ReturnComNotImplemented();
2261#else
2262 LogFlowThisFuncEnter();
2263
2264 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2265 return setError(E_INVALIDARG, tr("No file to open specified"));
2266 if (RT_UNLIKELY((aOpenMode) == NULL || *(aOpenMode) == '\0'))
2267 return setError(E_INVALIDARG, tr("No open mode specified"));
2268 if (RT_UNLIKELY((aDisposition) == NULL || *(aDisposition) == '\0'))
2269 return setError(E_INVALIDARG, tr("No disposition mode specified"));
2270
2271 CheckComArgOutPointerValid(aFile);
2272
2273 AutoCaller autoCaller(this);
2274 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2275
2276 /** @todo Validate open mode. */
2277 /** @todo Validate disposition mode. */
2278
2279 /** @todo Validate creation mode. */
2280 uint32_t uCreationMode = 0;
2281
2282 HRESULT hr = S_OK;
2283
2284 ComObjPtr <GuestFile> pFile;
2285 int rc = fileOpenInternal(Utf8Str(aPath), Utf8Str(aOpenMode), Utf8Str(aDisposition),
2286 aCreationMode, aOffset, pFile);
2287 if (RT_SUCCESS(rc))
2288 {
2289 /* Return directory object to the caller. */
2290 hr = pFile.queryInterfaceTo(aFile);
2291 }
2292 else
2293 {
2294 switch (rc)
2295 {
2296 /** @todo Add more error info! */
2297
2298 default:
2299 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
2300 break;
2301 }
2302 }
2303
2304 return hr;
2305#endif /* VBOX_WITH_GUEST_CONTROL */
2306}
2307
2308STDMETHODIMP GuestSession::FileQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
2309{
2310#ifndef VBOX_WITH_GUEST_CONTROL
2311 ReturnComNotImplemented();
2312#else
2313 LogFlowThisFuncEnter();
2314
2315 AutoCaller autoCaller(this);
2316 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2317
2318 ReturnComNotImplemented();
2319#endif /* VBOX_WITH_GUEST_CONTROL */
2320}
2321
2322STDMETHODIMP GuestSession::FileQuerySize(IN_BSTR aPath, LONG64 *aSize)
2323{
2324#ifndef VBOX_WITH_GUEST_CONTROL
2325 ReturnComNotImplemented();
2326#else
2327 LogFlowThisFuncEnter();
2328
2329 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2330 return setError(E_INVALIDARG, tr("No file to query size for specified"));
2331 CheckComArgOutPointerValid(aSize);
2332
2333 AutoCaller autoCaller(this);
2334 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2335
2336 HRESULT hr = S_OK;
2337
2338 int64_t llSize;
2339 int rc = fileQuerySizeInternal(Utf8Str(aPath), &llSize);
2340 if (RT_SUCCESS(rc))
2341 {
2342 *aSize = llSize;
2343 }
2344 else
2345 {
2346 switch (rc)
2347 {
2348 /** @todo Add more errors here! */
2349
2350 default:
2351 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), rc);
2352 break;
2353 }
2354 }
2355
2356 return hr;
2357#endif /* VBOX_WITH_GUEST_CONTROL */
2358}
2359
2360STDMETHODIMP GuestSession::FileRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
2361{
2362#ifndef VBOX_WITH_GUEST_CONTROL
2363 ReturnComNotImplemented();
2364#else
2365 LogFlowThisFuncEnter();
2366
2367 AutoCaller autoCaller(this);
2368 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2369
2370 ReturnComNotImplemented();
2371#endif /* VBOX_WITH_GUEST_CONTROL */
2372}
2373
2374STDMETHODIMP GuestSession::FileSetACL(IN_BSTR aPath, IN_BSTR aACL)
2375{
2376#ifndef VBOX_WITH_GUEST_CONTROL
2377 ReturnComNotImplemented();
2378#else
2379 LogFlowThisFuncEnter();
2380
2381 AutoCaller autoCaller(this);
2382 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2383
2384 ReturnComNotImplemented();
2385#endif /* VBOX_WITH_GUEST_CONTROL */
2386}
2387
2388STDMETHODIMP GuestSession::ProcessCreate(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
2389 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS, IGuestProcess **aProcess)
2390{
2391#ifndef VBOX_WITH_GUEST_CONTROL
2392 ReturnComNotImplemented();
2393#else
2394 LogFlowThisFuncEnter();
2395
2396 com::SafeArray<LONG> affinity;
2397
2398 HRESULT hr = ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),
2399 ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess);
2400 return hr;
2401#endif /* VBOX_WITH_GUEST_CONTROL */
2402}
2403
2404STDMETHODIMP GuestSession::ProcessCreateEx(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
2405 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS,
2406 ProcessPriority_T aPriority, ComSafeArrayIn(LONG, aAffinity),
2407 IGuestProcess **aProcess)
2408{
2409#ifndef VBOX_WITH_GUEST_CONTROL
2410 ReturnComNotImplemented();
2411#else
2412 LogFlowThisFuncEnter();
2413
2414 if (RT_UNLIKELY((aCommand) == NULL || *(aCommand) == '\0'))
2415 return setError(E_INVALIDARG, tr("No command to execute specified"));
2416 CheckComArgOutPointerValid(aProcess);
2417
2418 AutoCaller autoCaller(this);
2419 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2420
2421 GuestProcessStartupInfo procInfo;
2422 procInfo.mCommand = Utf8Str(aCommand);
2423
2424 if (aArguments)
2425 {
2426 com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments));
2427 for (size_t i = 0; i < arguments.size(); i++)
2428 procInfo.mArguments.push_back(Utf8Str(arguments[i]));
2429 }
2430
2431 int rc = VINF_SUCCESS;
2432
2433 /*
2434 * Create the process environment:
2435 * - Apply the session environment in a first step, and
2436 * - Apply environment variables specified by this call to
2437 * have the chance of overwriting/deleting session entries.
2438 */
2439 procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
2440
2441 if (aEnvironment)
2442 {
2443 com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aEnvironment));
2444 for (size_t i = 0; i < environment.size() && RT_SUCCESS(rc); i++)
2445 rc = procInfo.mEnvironment.Set(Utf8Str(environment[i]));
2446 }
2447
2448 HRESULT hr = S_OK;
2449
2450 if (RT_SUCCESS(rc))
2451 {
2452 if (aFlags)
2453 {
2454 com::SafeArray<ProcessCreateFlag_T> flags(ComSafeArrayInArg(aFlags));
2455 for (size_t i = 0; i < flags.size(); i++)
2456 procInfo.mFlags |= flags[i];
2457 }
2458
2459 procInfo.mTimeoutMS = aTimeoutMS;
2460
2461 if (aAffinity)
2462 {
2463 com::SafeArray<LONG> affinity(ComSafeArrayInArg(aAffinity));
2464 for (size_t i = 0; i < affinity.size(); i++)
2465 procInfo.mAffinity[i] = affinity[i]; /** @todo Really necessary? Later. */
2466 }
2467
2468 procInfo.mPriority = aPriority;
2469
2470 ComObjPtr<GuestProcess> pProcess;
2471 rc = processCreateExInteral(procInfo, pProcess);
2472 if (RT_SUCCESS(rc))
2473 {
2474 /* Return guest session to the caller. */
2475 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
2476 if (FAILED(hr2))
2477 rc = VERR_COM_OBJECT_NOT_FOUND;
2478
2479 if (RT_SUCCESS(rc))
2480 rc = pProcess->startProcessAsync();
2481 }
2482 }
2483
2484 if (RT_FAILURE(rc))
2485 {
2486 switch (rc)
2487 {
2488 case VERR_MAX_PROCS_REACHED:
2489 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest processes per session (%ld) reached"),
2490 VBOX_GUESTCTRL_MAX_PROCESSES);
2491 break;
2492
2493 /** @todo Add more errors here. */
2494
2495 default:
2496 hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest process, rc=%Rrc"), rc);
2497 break;
2498 }
2499 }
2500
2501 LogFlowFuncLeaveRC(rc);
2502 return hr;
2503#endif /* VBOX_WITH_GUEST_CONTROL */
2504}
2505
2506STDMETHODIMP GuestSession::ProcessGet(ULONG aPID, IGuestProcess **aProcess)
2507{
2508#ifndef VBOX_WITH_GUEST_CONTROL
2509 ReturnComNotImplemented();
2510#else
2511 LogFlowThisFunc(("aPID=%RU32\n", aPID));
2512
2513 CheckComArgOutPointerValid(aProcess);
2514 if (aPID == 0)
2515 return setError(E_INVALIDARG, tr("No valid process ID (PID) specified"));
2516
2517 AutoCaller autoCaller(this);
2518 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2519
2520 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2521
2522 HRESULT hr = S_OK;
2523
2524 ComObjPtr<GuestProcess> pProcess;
2525 int rc = processGetByPID(aPID, &pProcess);
2526 if (RT_FAILURE(rc))
2527 hr = setError(E_INVALIDARG, tr("No process with PID %RU32 found"), aPID);
2528
2529 /* This will set (*aProcess) to NULL if pProgress is NULL. */
2530 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
2531 if (SUCCEEDED(hr))
2532 hr = hr2;
2533
2534 LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", *aProcess, hr));
2535 return hr;
2536#endif /* VBOX_WITH_GUEST_CONTROL */
2537}
2538
2539STDMETHODIMP GuestSession::SymlinkCreate(IN_BSTR aSource, IN_BSTR aTarget, SymlinkType_T aType)
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::SymlinkExists(IN_BSTR aSymlink, BOOL *aExists)
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
2567STDMETHODIMP GuestSession::SymlinkRead(IN_BSTR aSymlink, ComSafeArrayIn(SymlinkReadFlag_T, aFlags), BSTR *aTarget)
2568{
2569#ifndef VBOX_WITH_GUEST_CONTROL
2570 ReturnComNotImplemented();
2571#else
2572 LogFlowThisFuncEnter();
2573
2574 AutoCaller autoCaller(this);
2575 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2576
2577 ReturnComNotImplemented();
2578#endif /* VBOX_WITH_GUEST_CONTROL */
2579}
2580
2581STDMETHODIMP GuestSession::SymlinkRemoveDirectory(IN_BSTR aPath)
2582{
2583#ifndef VBOX_WITH_GUEST_CONTROL
2584 ReturnComNotImplemented();
2585#else
2586 LogFlowThisFuncEnter();
2587
2588 AutoCaller autoCaller(this);
2589 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2590
2591 ReturnComNotImplemented();
2592#endif /* VBOX_WITH_GUEST_CONTROL */
2593}
2594
2595STDMETHODIMP GuestSession::SymlinkRemoveFile(IN_BSTR aFile)
2596{
2597#ifndef VBOX_WITH_GUEST_CONTROL
2598 ReturnComNotImplemented();
2599#else
2600 LogFlowThisFuncEnter();
2601
2602 AutoCaller autoCaller(this);
2603 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2604
2605 ReturnComNotImplemented();
2606#endif /* VBOX_WITH_GUEST_CONTROL */
2607}
2608
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