VirtualBox

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

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

Main/GuestCtrl: fixes to FileDelete and DirectoryCreateTemp.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 83.9 KB
Line 
1
2/* $Id: GuestSessionImpl.cpp 42682 2012-08-08 13:41:32Z 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.215389.xyz. 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 procInfo.mFlags = ProcessCreateFlag_Hidden
1756 | ProcessCreateFlag_WaitForStdOut;
1757 /* Construct arguments. */
1758 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
1759 procInfo.mArguments.push_back(Bstr(aTemplate)); /* The template we want to use. */
1760 }
1761 catch (...)
1762 {
1763 return E_OUTOFMEMORY;
1764 }
1765
1766 ComObjPtr<GuestProcess> pProcess;
1767 rc = processCreateExInteral(procInfo, pProcess);
1768 if (RT_SUCCESS(rc))
1769 {
1770 GuestProcessWaitResult waitRes;
1771 BYTE byBuf[_64K];
1772 size_t cbRead;
1773
1774 for (;;)
1775 {
1776 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
1777 30 * 1000 /* Timeout */, waitRes);
1778 if ( RT_FAILURE(rc)
1779 || waitRes.mResult == ProcessWaitResult_Terminate
1780 || waitRes.mResult == ProcessWaitResult_Error
1781 || waitRes.mResult == ProcessWaitResult_Timeout)
1782 {
1783 break;
1784 }
1785
1786 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
1787 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
1788 &cbRead);
1789 if (RT_FAILURE(rc))
1790 break;
1791
1792 if (cbRead)
1793 {
1794 rc = streamOut.AddData(byBuf, cbRead);
1795 if (RT_FAILURE(rc))
1796 break;
1797 }
1798 }
1799
1800 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n",
1801 rc, cbRead, streamOut.GetSize()));
1802 }
1803 else
1804 return setError(E_FAIL, tr("Error while starting temporary directory creation tool on guest: %Rrc"), rc);
1805 if (RT_FAILURE(rc))
1806 return setError(E_FAIL, tr("Error while running temporary directory creation tool: %Rrc"), rc);
1807 if (!streamOut.GetSize())
1808 return setError(E_FAIL, tr("No return code after creating temporary directory"));
1809 GuestProcessStreamBlock streamBlock;
1810 rc = streamOut.ParseBlock(streamBlock);
1811 if (RT_SUCCESS(rc))
1812 {
1813 streamBlock.GetString("name");
1814 int64_t i64rc;
1815 if (RT_FAILURE(streamBlock.GetInt64Ex("rc", &i64rc)))
1816 return setError(E_FAIL, tr("No return code after creating temporary directory"));
1817 if (RT_FAILURE((int)i64rc))
1818 return setError(VBOX_E_IPRT_ERROR, tr("File deletion failed: %Rrc"), rc);
1819 }
1820 else
1821 return setError(E_FAIL, tr("Error while getting return code from creating temporary directory: %Rrc"), rc);
1822 return S_OK;
1823#endif /* VBOX_WITH_GUEST_CONTROL */
1824}
1825
1826STDMETHODIMP GuestSession::DirectoryExists(IN_BSTR aPath, BOOL *aExists)
1827{
1828#ifndef VBOX_WITH_GUEST_CONTROL
1829 ReturnComNotImplemented();
1830#else
1831 LogFlowThisFuncEnter();
1832
1833 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1834 return setError(E_INVALIDARG, tr("No directory to check existence for specified"));
1835 CheckComArgOutPointerValid(aExists);
1836
1837 AutoCaller autoCaller(this);
1838 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1839
1840 HRESULT hr = S_OK;
1841
1842 GuestFsObjData objData;
1843 int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
1844 if (RT_SUCCESS(rc))
1845 {
1846 *aExists = objData.mType == FsObjType_Directory;
1847 }
1848 else
1849 {
1850 switch (rc)
1851 {
1852 /** @todo Add more errors here! */
1853
1854 default:
1855 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence failed: %Rrc"), rc);
1856 break;
1857 }
1858 }
1859
1860 return hr;
1861#endif /* VBOX_WITH_GUEST_CONTROL */
1862}
1863
1864STDMETHODIMP GuestSession::DirectoryOpen(IN_BSTR aPath, IN_BSTR aFilter, ComSafeArrayIn(DirectoryOpenFlag_T, aFlags), IGuestDirectory **aDirectory)
1865{
1866#ifndef VBOX_WITH_GUEST_CONTROL
1867 ReturnComNotImplemented();
1868#else
1869 LogFlowThisFuncEnter();
1870
1871 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
1872 return setError(E_INVALIDARG, tr("No directory to open specified"));
1873 if (RT_UNLIKELY((aFilter) != NULL && *(aFilter) != '\0'))
1874 return setError(E_INVALIDARG, tr("Directory filters not implemented yet"));
1875
1876 CheckComArgOutPointerValid(aDirectory);
1877
1878 AutoCaller autoCaller(this);
1879 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1880
1881 uint32_t fFlags = DirectoryOpenFlag_None;
1882 if (aFlags)
1883 {
1884 com::SafeArray<DirectoryOpenFlag_T> flags(ComSafeArrayInArg(aFlags));
1885 for (size_t i = 0; i < flags.size(); i++)
1886 fFlags |= flags[i];
1887
1888 if (fFlags)
1889 return setError(E_INVALIDARG, tr("Open flags (%#x) not implemented yet"), fFlags);
1890 }
1891
1892 HRESULT hr = S_OK;
1893
1894 ComObjPtr <GuestDirectory> pDirectory;
1895 int rc = directoryOpenInternal(Utf8Str(aPath), Utf8Str(aFilter), fFlags, pDirectory);
1896 if (RT_SUCCESS(rc))
1897 {
1898 if (aDirectory)
1899 {
1900 /* Return directory object to the caller. */
1901 hr = pDirectory.queryInterfaceTo(aDirectory);
1902 }
1903 else
1904 {
1905 rc = directoryClose(pDirectory);
1906 if (RT_FAILURE(rc))
1907 hr = setError(VBOX_E_IPRT_ERROR, tr("Unable to close directory object, rc=%Rrc"), rc);
1908 }
1909 }
1910 else
1911 {
1912 switch (rc)
1913 {
1914 case VERR_INVALID_PARAMETER:
1915 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Invalid parameters given"));
1916 break;
1917
1918 case VERR_BROKEN_PIPE:
1919 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: Unexpectedly aborted"));
1920 break;
1921
1922 default:
1923 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory failed: %Rrc"), rc);
1924 break;
1925 }
1926 }
1927
1928 return hr;
1929#endif /* VBOX_WITH_GUEST_CONTROL */
1930}
1931
1932STDMETHODIMP GuestSession::DirectoryQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
1933{
1934#ifndef VBOX_WITH_GUEST_CONTROL
1935 ReturnComNotImplemented();
1936#else
1937 LogFlowThisFuncEnter();
1938
1939 AutoCaller autoCaller(this);
1940 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1941
1942 ReturnComNotImplemented();
1943#endif /* VBOX_WITH_GUEST_CONTROL */
1944}
1945
1946STDMETHODIMP GuestSession::DirectoryRemove(IN_BSTR aPath)
1947{
1948#ifndef VBOX_WITH_GUEST_CONTROL
1949 ReturnComNotImplemented();
1950#else
1951 LogFlowThisFuncEnter();
1952
1953 AutoCaller autoCaller(this);
1954 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1955
1956 ReturnComNotImplemented();
1957#endif /* VBOX_WITH_GUEST_CONTROL */
1958}
1959
1960STDMETHODIMP GuestSession::DirectoryRemoveRecursive(IN_BSTR aPath, ComSafeArrayIn(DirectoryRemoveRecFlag_T, aFlags), IProgress **aProgress)
1961{
1962#ifndef VBOX_WITH_GUEST_CONTROL
1963 ReturnComNotImplemented();
1964#else
1965 LogFlowThisFuncEnter();
1966
1967 AutoCaller autoCaller(this);
1968 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1969
1970 ReturnComNotImplemented();
1971#endif /* VBOX_WITH_GUEST_CONTROL */
1972}
1973
1974STDMETHODIMP GuestSession::DirectoryRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
1975{
1976#ifndef VBOX_WITH_GUEST_CONTROL
1977 ReturnComNotImplemented();
1978#else
1979 LogFlowThisFuncEnter();
1980
1981 AutoCaller autoCaller(this);
1982 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1983
1984 ReturnComNotImplemented();
1985#endif /* VBOX_WITH_GUEST_CONTROL */
1986}
1987
1988STDMETHODIMP GuestSession::DirectorySetACL(IN_BSTR aPath, IN_BSTR aACL)
1989{
1990#ifndef VBOX_WITH_GUEST_CONTROL
1991 ReturnComNotImplemented();
1992#else
1993 LogFlowThisFuncEnter();
1994
1995 AutoCaller autoCaller(this);
1996 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1997
1998 ReturnComNotImplemented();
1999#endif /* VBOX_WITH_GUEST_CONTROL */
2000}
2001
2002STDMETHODIMP GuestSession::EnvironmentClear(void)
2003{
2004#ifndef VBOX_WITH_GUEST_CONTROL
2005 ReturnComNotImplemented();
2006#else
2007 LogFlowThisFuncEnter();
2008
2009 AutoCaller autoCaller(this);
2010 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2011
2012 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2013
2014 mData.mEnvironment.Clear();
2015
2016 LogFlowFuncLeaveRC(S_OK);
2017 return S_OK;
2018#endif /* VBOX_WITH_GUEST_CONTROL */
2019}
2020
2021STDMETHODIMP GuestSession::EnvironmentGet(IN_BSTR aName, BSTR *aValue)
2022{
2023#ifndef VBOX_WITH_GUEST_CONTROL
2024 ReturnComNotImplemented();
2025#else
2026 LogFlowThisFuncEnter();
2027
2028 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
2029 return setError(E_INVALIDARG, tr("No value name specified"));
2030
2031 CheckComArgOutPointerValid(aValue);
2032
2033 AutoCaller autoCaller(this);
2034 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2035
2036 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2037
2038 Bstr strValue(mData.mEnvironment.Get(Utf8Str(aName)));
2039 strValue.cloneTo(aValue);
2040
2041 LogFlowFuncLeaveRC(S_OK);
2042 return S_OK;
2043#endif /* VBOX_WITH_GUEST_CONTROL */
2044}
2045
2046STDMETHODIMP GuestSession::EnvironmentSet(IN_BSTR aName, IN_BSTR aValue)
2047{
2048#ifndef VBOX_WITH_GUEST_CONTROL
2049 ReturnComNotImplemented();
2050#else
2051 LogFlowThisFuncEnter();
2052
2053 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
2054 return setError(E_INVALIDARG, tr("No value name specified"));
2055
2056 AutoCaller autoCaller(this);
2057 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2058
2059 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2060
2061 int rc = mData.mEnvironment.Set(Utf8Str(aName), Utf8Str(aValue));
2062
2063 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
2064 LogFlowFuncLeaveRC(hr);
2065 return hr;
2066#endif /* VBOX_WITH_GUEST_CONTROL */
2067}
2068
2069STDMETHODIMP GuestSession::EnvironmentUnset(IN_BSTR aName)
2070{
2071#ifndef VBOX_WITH_GUEST_CONTROL
2072 ReturnComNotImplemented();
2073#else
2074 LogFlowThisFuncEnter();
2075
2076 AutoCaller autoCaller(this);
2077 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2078
2079 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2080
2081 mData.mEnvironment.Unset(Utf8Str(aName));
2082
2083 LogFlowFuncLeaveRC(S_OK);
2084 return S_OK;
2085#endif /* VBOX_WITH_GUEST_CONTROL */
2086}
2087
2088STDMETHODIMP GuestSession::FileCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aName, IGuestFile **aFile)
2089{
2090#ifndef VBOX_WITH_GUEST_CONTROL
2091 ReturnComNotImplemented();
2092#else
2093 LogFlowThisFuncEnter();
2094
2095 AutoCaller autoCaller(this);
2096 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2097
2098 ReturnComNotImplemented();
2099#endif /* VBOX_WITH_GUEST_CONTROL */
2100}
2101
2102STDMETHODIMP GuestSession::FileExists(IN_BSTR aPath, BOOL *aExists)
2103{
2104#ifndef VBOX_WITH_GUEST_CONTROL
2105 ReturnComNotImplemented();
2106#else
2107 LogFlowThisFuncEnter();
2108
2109 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2110 return setError(E_INVALIDARG, tr("No file to check existence for specified"));
2111 CheckComArgOutPointerValid(aExists);
2112
2113 AutoCaller autoCaller(this);
2114 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2115
2116 HRESULT hr = S_OK;
2117
2118 GuestFsObjData objData;
2119 int rc = fileQueryInfoInternal(Utf8Str(aPath), objData);
2120 if (RT_SUCCESS(rc))
2121 {
2122 *aExists = objData.mType == FsObjType_File;
2123 }
2124 else
2125 {
2126 switch (rc)
2127 {
2128 /** @todo Add more errors here! */
2129
2130 default:
2131 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file existence failed: %Rrc"), rc);
2132 break;
2133 }
2134 }
2135
2136 return hr;
2137#endif /* VBOX_WITH_GUEST_CONTROL */
2138}
2139
2140STDMETHODIMP GuestSession::FileRemove(IN_BSTR aPath)
2141{
2142#ifndef VBOX_WITH_GUEST_CONTROL
2143 ReturnComNotImplemented();
2144#else
2145 LogFlowThisFuncEnter();
2146
2147 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2148 return setError(E_INVALIDARG, tr("No file to remove specified"));
2149
2150 AutoCaller autoCaller(this);
2151 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2152
2153 GuestProcessStartupInfo procInfo;
2154 GuestProcessStream streamOut;
2155 int rc = VINF_SUCCESS;
2156
2157 try /* Can this be done without exceptions? */
2158 {
2159 Utf8Str strPath(aPath);
2160 procInfo.mName = Utf8StrFmt(tr("Removing file \"%s\"",
2161 strPath.c_str()));
2162 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_RM);
2163 procInfo.mFlags = ProcessCreateFlag_Hidden
2164 | ProcessCreateFlag_WaitForStdOut;
2165 /* Construct arguments. */
2166 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
2167 procInfo.mArguments.push_back(Bstr(aPath)); /* The directory we want to create. */
2168 }
2169 catch (...)
2170 {
2171 return E_OUTOFMEMORY;
2172 }
2173
2174 ComObjPtr<GuestProcess> pProcess;
2175 rc = processCreateExInteral(procInfo, pProcess);
2176 if (RT_SUCCESS(rc))
2177 rc = pProcess->startProcess();
2178 if (RT_SUCCESS(rc))
2179 {
2180 GuestProcessWaitResult waitRes;
2181 BYTE byBuf[_64K];
2182 size_t cbRead;
2183
2184 for (;;)
2185 {
2186 rc = pProcess->waitFor(ProcessWaitForFlag_StdOut,
2187 30 * 1000 /* Timeout */, waitRes);
2188 if ( RT_FAILURE(rc)
2189 || waitRes.mResult == ProcessWaitResult_Terminate
2190 || waitRes.mResult == ProcessWaitResult_Error
2191 || waitRes.mResult == ProcessWaitResult_Timeout)
2192 {
2193 break;
2194 }
2195
2196 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
2197 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
2198 &cbRead);
2199 if (RT_FAILURE(rc))
2200 break;
2201
2202 if (cbRead)
2203 {
2204 rc = streamOut.AddData(byBuf, cbRead);
2205 if (RT_FAILURE(rc))
2206 break;
2207 }
2208 }
2209
2210 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32, cbStreamOut=%RU32\n",
2211 rc, cbRead, streamOut.GetSize()));
2212 }
2213 else
2214 return setError(E_FAIL, tr("Error while starting delete tool on guest: %Rrc"), rc);
2215 if (RT_FAILURE(rc))
2216 return setError(E_FAIL, tr("Error while running delete tool on guest: %Rrc"), rc);
2217 if (!streamOut.GetSize())
2218 return setError(E_FAIL, tr("No return code after deleting file"));
2219 GuestProcessStreamBlock streamBlock;
2220 rc = streamOut.ParseBlock(streamBlock);
2221 if (RT_SUCCESS(rc))
2222 {
2223 streamBlock.GetString("fname");
2224 int64_t i64rc;
2225 if (RT_FAILURE(streamBlock.GetInt64Ex("rc", &i64rc)))
2226 return setError(E_FAIL, tr("No return code after deleting file"));
2227 if (RT_FAILURE((int)i64rc))
2228 return setError(VBOX_E_IPRT_ERROR, tr("File deletion failed: %Rrc"), rc);
2229 }
2230 else
2231 return setError(E_FAIL, tr("Error while getting return code from deleting file: %Rrc"), rc);
2232 return S_OK;
2233#endif /* VBOX_WITH_GUEST_CONTROL */
2234}
2235
2236STDMETHODIMP GuestSession::FileOpen(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, ULONG aCreationMode, LONG64 aOffset, IGuestFile **aFile)
2237{
2238#ifndef VBOX_WITH_GUEST_CONTROL
2239 ReturnComNotImplemented();
2240#else
2241 LogFlowThisFuncEnter();
2242
2243 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2244 return setError(E_INVALIDARG, tr("No file to open specified"));
2245 if (RT_UNLIKELY((aOpenMode) == NULL || *(aOpenMode) == '\0'))
2246 return setError(E_INVALIDARG, tr("No open mode specified"));
2247 if (RT_UNLIKELY((aDisposition) == NULL || *(aDisposition) == '\0'))
2248 return setError(E_INVALIDARG, tr("No disposition mode specified"));
2249
2250 CheckComArgOutPointerValid(aFile);
2251
2252 AutoCaller autoCaller(this);
2253 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2254
2255 /** @todo Validate open mode. */
2256 /** @todo Validate disposition mode. */
2257
2258 /** @todo Validate creation mode. */
2259 uint32_t uCreationMode = 0;
2260
2261 HRESULT hr = S_OK;
2262
2263 ComObjPtr <GuestFile> pFile;
2264 int rc = fileOpenInternal(Utf8Str(aPath), Utf8Str(aOpenMode), Utf8Str(aDisposition),
2265 aCreationMode, aOffset, pFile);
2266 if (RT_SUCCESS(rc))
2267 {
2268 /* Return directory object to the caller. */
2269 hr = pFile.queryInterfaceTo(aFile);
2270 }
2271 else
2272 {
2273 switch (rc)
2274 {
2275 /** @todo Add more error info! */
2276
2277 default:
2278 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
2279 break;
2280 }
2281 }
2282
2283 return hr;
2284#endif /* VBOX_WITH_GUEST_CONTROL */
2285}
2286
2287STDMETHODIMP GuestSession::FileQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
2288{
2289#ifndef VBOX_WITH_GUEST_CONTROL
2290 ReturnComNotImplemented();
2291#else
2292 LogFlowThisFuncEnter();
2293
2294 AutoCaller autoCaller(this);
2295 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2296
2297 ReturnComNotImplemented();
2298#endif /* VBOX_WITH_GUEST_CONTROL */
2299}
2300
2301STDMETHODIMP GuestSession::FileQuerySize(IN_BSTR aPath, LONG64 *aSize)
2302{
2303#ifndef VBOX_WITH_GUEST_CONTROL
2304 ReturnComNotImplemented();
2305#else
2306 LogFlowThisFuncEnter();
2307
2308 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2309 return setError(E_INVALIDARG, tr("No file to query size for specified"));
2310 CheckComArgOutPointerValid(aSize);
2311
2312 AutoCaller autoCaller(this);
2313 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2314
2315 HRESULT hr = S_OK;
2316
2317 int64_t llSize;
2318 int rc = fileQuerySizeInternal(Utf8Str(aPath), &llSize);
2319 if (RT_SUCCESS(rc))
2320 {
2321 *aSize = llSize;
2322 }
2323 else
2324 {
2325 switch (rc)
2326 {
2327 /** @todo Add more errors here! */
2328
2329 default:
2330 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), rc);
2331 break;
2332 }
2333 }
2334
2335 return hr;
2336#endif /* VBOX_WITH_GUEST_CONTROL */
2337}
2338
2339STDMETHODIMP GuestSession::FileRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
2340{
2341#ifndef VBOX_WITH_GUEST_CONTROL
2342 ReturnComNotImplemented();
2343#else
2344 LogFlowThisFuncEnter();
2345
2346 AutoCaller autoCaller(this);
2347 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2348
2349 ReturnComNotImplemented();
2350#endif /* VBOX_WITH_GUEST_CONTROL */
2351}
2352
2353STDMETHODIMP GuestSession::FileSetACL(IN_BSTR aPath, IN_BSTR aACL)
2354{
2355#ifndef VBOX_WITH_GUEST_CONTROL
2356 ReturnComNotImplemented();
2357#else
2358 LogFlowThisFuncEnter();
2359
2360 AutoCaller autoCaller(this);
2361 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2362
2363 ReturnComNotImplemented();
2364#endif /* VBOX_WITH_GUEST_CONTROL */
2365}
2366
2367STDMETHODIMP GuestSession::ProcessCreate(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
2368 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS, IGuestProcess **aProcess)
2369{
2370#ifndef VBOX_WITH_GUEST_CONTROL
2371 ReturnComNotImplemented();
2372#else
2373 LogFlowThisFuncEnter();
2374
2375 com::SafeArray<LONG> affinity;
2376
2377 HRESULT hr = ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),
2378 ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess);
2379 return hr;
2380#endif /* VBOX_WITH_GUEST_CONTROL */
2381}
2382
2383STDMETHODIMP GuestSession::ProcessCreateEx(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
2384 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS,
2385 ProcessPriority_T aPriority, ComSafeArrayIn(LONG, aAffinity),
2386 IGuestProcess **aProcess)
2387{
2388#ifndef VBOX_WITH_GUEST_CONTROL
2389 ReturnComNotImplemented();
2390#else
2391 LogFlowThisFuncEnter();
2392
2393 if (RT_UNLIKELY((aCommand) == NULL || *(aCommand) == '\0'))
2394 return setError(E_INVALIDARG, tr("No command to execute specified"));
2395 CheckComArgOutPointerValid(aProcess);
2396
2397 AutoCaller autoCaller(this);
2398 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2399
2400 GuestProcessStartupInfo procInfo;
2401 procInfo.mCommand = Utf8Str(aCommand);
2402
2403 if (aArguments)
2404 {
2405 com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments));
2406 for (size_t i = 0; i < arguments.size(); i++)
2407 procInfo.mArguments.push_back(Utf8Str(arguments[i]));
2408 }
2409
2410 int rc = VINF_SUCCESS;
2411
2412 /*
2413 * Create the process environment:
2414 * - Apply the session environment in a first step, and
2415 * - Apply environment variables specified by this call to
2416 * have the chance of overwriting/deleting session entries.
2417 */
2418 procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
2419
2420 if (aEnvironment)
2421 {
2422 com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aEnvironment));
2423 for (size_t i = 0; i < environment.size() && RT_SUCCESS(rc); i++)
2424 rc = procInfo.mEnvironment.Set(Utf8Str(environment[i]));
2425 }
2426
2427 HRESULT hr = S_OK;
2428
2429 if (RT_SUCCESS(rc))
2430 {
2431 if (aFlags)
2432 {
2433 com::SafeArray<ProcessCreateFlag_T> flags(ComSafeArrayInArg(aFlags));
2434 for (size_t i = 0; i < flags.size(); i++)
2435 procInfo.mFlags |= flags[i];
2436 }
2437
2438 procInfo.mTimeoutMS = aTimeoutMS;
2439
2440 if (aAffinity)
2441 {
2442 com::SafeArray<LONG> affinity(ComSafeArrayInArg(aAffinity));
2443 for (size_t i = 0; i < affinity.size(); i++)
2444 procInfo.mAffinity[i] = affinity[i]; /** @todo Really necessary? Later. */
2445 }
2446
2447 procInfo.mPriority = aPriority;
2448
2449 ComObjPtr<GuestProcess> pProcess;
2450 rc = processCreateExInteral(procInfo, pProcess);
2451 if (RT_SUCCESS(rc))
2452 {
2453 /* Return guest session to the caller. */
2454 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
2455 if (FAILED(hr2))
2456 rc = VERR_COM_OBJECT_NOT_FOUND;
2457
2458 if (RT_SUCCESS(rc))
2459 rc = pProcess->startProcessAsync();
2460 }
2461 }
2462
2463 if (RT_FAILURE(rc))
2464 {
2465 switch (rc)
2466 {
2467 case VERR_MAX_PROCS_REACHED:
2468 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest processes per session (%ld) reached"),
2469 VBOX_GUESTCTRL_MAX_PROCESSES);
2470 break;
2471
2472 /** @todo Add more errors here. */
2473
2474 default:
2475 hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest process, rc=%Rrc"), rc);
2476 break;
2477 }
2478 }
2479
2480 LogFlowFuncLeaveRC(rc);
2481 return hr;
2482#endif /* VBOX_WITH_GUEST_CONTROL */
2483}
2484
2485STDMETHODIMP GuestSession::ProcessGet(ULONG aPID, IGuestProcess **aProcess)
2486{
2487#ifndef VBOX_WITH_GUEST_CONTROL
2488 ReturnComNotImplemented();
2489#else
2490 LogFlowThisFunc(("aPID=%RU32\n", aPID));
2491
2492 CheckComArgOutPointerValid(aProcess);
2493 if (aPID == 0)
2494 return setError(E_INVALIDARG, tr("No valid process ID (PID) specified"));
2495
2496 AutoCaller autoCaller(this);
2497 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2498
2499 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2500
2501 HRESULT hr = S_OK;
2502
2503 ComObjPtr<GuestProcess> pProcess;
2504 int rc = processGetByPID(aPID, &pProcess);
2505 if (RT_FAILURE(rc))
2506 hr = setError(E_INVALIDARG, tr("No process with PID %RU32 found"), aPID);
2507
2508 /* This will set (*aProcess) to NULL if pProgress is NULL. */
2509 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
2510 if (SUCCEEDED(hr))
2511 hr = hr2;
2512
2513 LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", *aProcess, hr));
2514 return hr;
2515#endif /* VBOX_WITH_GUEST_CONTROL */
2516}
2517
2518STDMETHODIMP GuestSession::SymlinkCreate(IN_BSTR aSource, IN_BSTR aTarget, SymlinkType_T aType)
2519{
2520#ifndef VBOX_WITH_GUEST_CONTROL
2521 ReturnComNotImplemented();
2522#else
2523 LogFlowThisFuncEnter();
2524
2525 AutoCaller autoCaller(this);
2526 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2527
2528 ReturnComNotImplemented();
2529#endif /* VBOX_WITH_GUEST_CONTROL */
2530}
2531
2532STDMETHODIMP GuestSession::SymlinkExists(IN_BSTR aSymlink, BOOL *aExists)
2533{
2534#ifndef VBOX_WITH_GUEST_CONTROL
2535 ReturnComNotImplemented();
2536#else
2537 LogFlowThisFuncEnter();
2538
2539 AutoCaller autoCaller(this);
2540 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2541
2542 ReturnComNotImplemented();
2543#endif /* VBOX_WITH_GUEST_CONTROL */
2544}
2545
2546STDMETHODIMP GuestSession::SymlinkRead(IN_BSTR aSymlink, ComSafeArrayIn(SymlinkReadFlag_T, aFlags), BSTR *aTarget)
2547{
2548#ifndef VBOX_WITH_GUEST_CONTROL
2549 ReturnComNotImplemented();
2550#else
2551 LogFlowThisFuncEnter();
2552
2553 AutoCaller autoCaller(this);
2554 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2555
2556 ReturnComNotImplemented();
2557#endif /* VBOX_WITH_GUEST_CONTROL */
2558}
2559
2560STDMETHODIMP GuestSession::SymlinkRemoveDirectory(IN_BSTR aPath)
2561{
2562#ifndef VBOX_WITH_GUEST_CONTROL
2563 ReturnComNotImplemented();
2564#else
2565 LogFlowThisFuncEnter();
2566
2567 AutoCaller autoCaller(this);
2568 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2569
2570 ReturnComNotImplemented();
2571#endif /* VBOX_WITH_GUEST_CONTROL */
2572}
2573
2574STDMETHODIMP GuestSession::SymlinkRemoveFile(IN_BSTR aFile)
2575{
2576#ifndef VBOX_WITH_GUEST_CONTROL
2577 ReturnComNotImplemented();
2578#else
2579 LogFlowThisFuncEnter();
2580
2581 AutoCaller autoCaller(this);
2582 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2583
2584 ReturnComNotImplemented();
2585#endif /* VBOX_WITH_GUEST_CONTROL */
2586}
2587
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