VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestFileImpl.cpp@ 45029

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

GuestCtrl: Infrastructure changes for handling and executing dedicated guest sessions and protocol versioning (untested, work in progress).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.7 KB
Line 
1
2/* $Id: GuestFileImpl.cpp 44863 2013-02-28 12:18:17Z vboxsync $ */
3/** @file
4 * VirtualBox Main - Guest file handling.
5 */
6
7/*
8 * Copyright (C) 2012-2013 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 "GuestFileImpl.h"
24#include "GuestSessionImpl.h"
25#include "GuestCtrlImplPrivate.h"
26#include "ConsoleImpl.h"
27
28#include "Global.h"
29#include "AutoCaller.h"
30
31#include <iprt/file.h>
32#include <VBox/com/array.h>
33
34#ifdef LOG_GROUP
35 #undef LOG_GROUP
36#endif
37#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
38#include <VBox/log.h>
39
40
41// constructor / destructor
42/////////////////////////////////////////////////////////////////////////////
43
44DEFINE_EMPTY_CTOR_DTOR(GuestFile)
45
46HRESULT GuestFile::FinalConstruct(void)
47{
48 LogFlowThisFunc(("\n"));
49 return BaseFinalConstruct();
50}
51
52void GuestFile::FinalRelease(void)
53{
54 LogFlowThisFuncEnter();
55 uninit();
56 BaseFinalRelease();
57 LogFlowThisFuncLeave();
58}
59
60// public initializer/uninitializer for internal purposes only
61/////////////////////////////////////////////////////////////////////////////
62
63int GuestFile::init(Console *pConsole, GuestSession *pSession, ULONG uFileID, const GuestFileOpenInfo &openInfo)
64{
65 LogFlowThisFunc(("pConsole=%p, pSession=%p, uFileID=%RU32, strPath=%s\n",
66 pConsole, pSession, uFileID, openInfo.mFileName.c_str()));
67
68 AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
69 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
70
71 /* Enclose the state transition NotReady->InInit->Ready. */
72 AutoInitSpan autoInitSpan(this);
73 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
74
75 int vrc = bindToSession(pConsole, pSession, uFileID /* Object ID */);
76 if (RT_SUCCESS(vrc))
77 {
78 mData.mInitialSize = 0;
79
80 /* Confirm a successful initialization when it's the case. */
81 autoInitSpan.setSucceeded();
82 return vrc;
83 }
84
85 autoInitSpan.setFailed();
86 return vrc;
87}
88
89/**
90 * Uninitializes the instance.
91 * Called from FinalRelease().
92 */
93void GuestFile::uninit(void)
94{
95 LogFlowThisFunc(("\n"));
96
97 /* Enclose the state transition Ready->InUninit->NotReady. */
98 AutoUninitSpan autoUninitSpan(this);
99 if (autoUninitSpan.uninitDone())
100 return;
101
102#ifdef VBOX_WITH_GUEST_CONTROL
103 /*
104 * Cancel + remove all callbacks + waiters.
105 * Note: Deleting them is the job of the caller!
106 */
107 callbackRemoveAll();
108#endif
109
110 LogFlowThisFuncLeave();
111}
112
113// implementation of public getters/setters for attributes
114/////////////////////////////////////////////////////////////////////////////
115
116STDMETHODIMP GuestFile::COMGETTER(CreationMode)(ULONG *aCreationMode)
117{
118#ifndef VBOX_WITH_GUEST_CONTROL
119 ReturnComNotImplemented();
120#else
121 AutoCaller autoCaller(this);
122 if (FAILED(autoCaller.rc())) return autoCaller.rc();
123
124 CheckComArgOutPointerValid(aCreationMode);
125
126 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
127
128 *aCreationMode = mData.mOpenInfo.mCreationMode;
129
130 return S_OK;
131#endif /* VBOX_WITH_GUEST_CONTROL */
132}
133
134/** @todo For 4.3: Change ULONG* to BSTR* ?*/
135STDMETHODIMP GuestFile::COMGETTER(Disposition)(ULONG *aDisposition)
136{
137#ifndef VBOX_WITH_GUEST_CONTROL
138 ReturnComNotImplemented();
139#else
140 AutoCaller autoCaller(this);
141 if (FAILED(autoCaller.rc())) return autoCaller.rc();
142
143 CheckComArgOutPointerValid(aDisposition);
144
145 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
146
147 *aDisposition = getDispositionFromString(mData.mOpenInfo.mDisposition);
148
149 return S_OK;
150#endif /* VBOX_WITH_GUEST_CONTROL */
151}
152
153STDMETHODIMP GuestFile::COMGETTER(FileName)(BSTR *aFileName)
154{
155#ifndef VBOX_WITH_GUEST_CONTROL
156 ReturnComNotImplemented();
157#else
158 AutoCaller autoCaller(this);
159 if (FAILED(autoCaller.rc())) return autoCaller.rc();
160
161 CheckComArgOutPointerValid(aFileName);
162
163 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
164
165 mData.mOpenInfo.mFileName.cloneTo(aFileName);
166
167 return S_OK;
168#endif /* VBOX_WITH_GUEST_CONTROL */
169}
170
171STDMETHODIMP GuestFile::COMGETTER(InitialSize)(LONG64 *aInitialSize)
172{
173#ifndef VBOX_WITH_GUEST_CONTROL
174 ReturnComNotImplemented();
175#else
176 AutoCaller autoCaller(this);
177 if (FAILED(autoCaller.rc())) return autoCaller.rc();
178
179 CheckComArgOutPointerValid(aInitialSize);
180
181 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
182
183 *aInitialSize = mData.mInitialSize;
184
185 return S_OK;
186#endif /* VBOX_WITH_GUEST_CONTROL */
187}
188
189STDMETHODIMP GuestFile::COMGETTER(Offset)(LONG64 *aOffset)
190{
191#ifndef VBOX_WITH_GUEST_CONTROL
192 ReturnComNotImplemented();
193#else
194 AutoCaller autoCaller(this);
195 if (FAILED(autoCaller.rc())) return autoCaller.rc();
196
197 CheckComArgOutPointerValid(aOffset);
198
199 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
200
201 *aOffset = mData.mOffCurrent;
202
203 return S_OK;
204#endif /* VBOX_WITH_GUEST_CONTROL */
205}
206
207/** @todo For 4.3: Change ULONG* to BSTR* ?*/
208STDMETHODIMP GuestFile::COMGETTER(OpenMode)(ULONG *aOpenMode)
209{
210#ifndef VBOX_WITH_GUEST_CONTROL
211 ReturnComNotImplemented();
212#else
213 AutoCaller autoCaller(this);
214 if (FAILED(autoCaller.rc())) return autoCaller.rc();
215
216 CheckComArgOutPointerValid(aOpenMode);
217
218 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
219
220 *aOpenMode = getOpenModeFromString(mData.mOpenInfo.mOpenMode);
221
222 return S_OK;
223#endif /* VBOX_WITH_GUEST_CONTROL */
224}
225
226// private methods
227/////////////////////////////////////////////////////////////////////////////
228
229int GuestFile::callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
230{
231#ifdef DEBUG
232 LogFlowThisFunc(("strName=%s, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
233 mData.mOpenInfo.mFileName.c_str(), pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
234#endif
235 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
236
237 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
238
239 /* Get the optional callback associated to this context ID.
240 * The callback may not be around anymore if just kept locally by the caller when
241 * doing the actual HGCM sending stuff. */
242 GuestCtrlCallback *pCallback = NULL;
243 GuestCtrlCallbacks::const_iterator it
244 = mData.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID));
245 if (it != mData.mCallbacks.end())
246 {
247 pCallback = it->second;
248 AssertPtr(pCallback);
249#ifdef DEBUG
250 LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n",
251 pCallback, pCbCtx->uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID)));
252#endif
253 }
254
255 int vrc;
256 switch (pCbCtx->uFunction)
257 {
258 case GUEST_DISCONNECTED:
259 vrc = onGuestDisconnected(pCbCtx, pCallback, pSvcCb); /* Affects all callbacks. */
260 break;
261
262 case GUEST_FILE_NOTIFY:
263 vrc = onFileNotify(pCbCtx, pCallback, pSvcCb);
264 break;
265
266 default:
267 /* Silently ignore not implemented functions. */
268 vrc = VERR_NOT_SUPPORTED;
269 break;
270 }
271
272#ifdef DEBUG
273 LogFlowFuncLeaveRC(vrc);
274#endif
275 return vrc;
276}
277
278/* static */
279uint32_t GuestFile::getDispositionFromString(const Utf8Str &strDisposition)
280{
281 return 0; /** @todo Implement me! */
282}
283
284/* static */
285uint32_t GuestFile::getOpenModeFromString(const Utf8Str &strOpenMode)
286{
287 uint32_t uOpenMode = 0;
288
289 const char *pc = strOpenMode.c_str();
290 while (*pc != '\0')
291 {
292 switch (*pc++)
293 {
294 case 'r':
295 uOpenMode |= RTFILE_O_READ;
296 break;
297
298 case 'w':
299 uOpenMode |= RTFILE_O_WRITE;
300 break;
301
302 default:
303 /* Silently skip unknown values. */
304 break;
305 }
306 }
307
308 return uOpenMode;
309}
310
311int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
312{
313 AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
314 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
315
316 if (pSvcCbData->mParms < 3)
317 return VERR_INVALID_PARAMETER;
318
319 uint32_t uType;
320 void *pvData; uint32_t cbData;
321 /* pSvcCb->mpaParms[0] always contains the context ID. */
322 pSvcCbData->mpaParms[1].getUInt32(&uType);
323 pSvcCbData->mpaParms[2].getPointer(&pvData, &cbData);
324
325 LogFlowThisFunc(("strName=%s, uType=%RU32, pvData=%p, cbData=%RU32, pCallback=%p\n",
326 mData.mOpenInfo.mFileName.c_str(), uType, pvData, cbData, pCallback));
327
328 /* Signal callback in every case (if available). */
329 int vrc = VINF_SUCCESS;
330 if (pCallback)
331 {
332 vrc = pCallback->SetData(pvData, cbData);
333
334 int rc2 = pCallback->Signal();
335 if (RT_SUCCESS(vrc))
336 vrc = rc2;
337 }
338
339 LogFlowFuncLeaveRC(vrc);
340 return vrc;
341}
342
343int GuestFile::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
344{
345 AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
346
347 LogFlowThisFunc(("strFile=%s, pCallback=%p\n", mData.mOpenInfo.mFileName.c_str(), pCallback));
348
349 /* First, signal callback in every case. */
350 if (pCallback)
351 pCallback->Signal();
352
353 /** @todo More on onGuestDisconnected? */
354 int vrc = VINF_SUCCESS;
355
356 LogFlowFuncLeaveRC(vrc);
357 return vrc;
358}
359
360int GuestFile::openFile(int *pGuestRc)
361{
362 LogFlowThisFunc(("strFile=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%RU32\n",
363 mData.mOpenInfo.mFileName.c_str(), mData.mOpenInfo.mOpenMode.c_str(),
364 mData.mOpenInfo.mDisposition.c_str(), mData.mOpenInfo.mCreationMode));
365
366 /* Wait until the caller function (if kicked off by a thread)
367 * has returned and continue operation. */
368 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
369
370 AssertPtr(mData.mSession);
371 uint32_t uProtocol = mData.mSession->getProtocolVersion();
372 if (uProtocol < 2)
373 return VERR_NOT_SUPPORTED;
374
375 int vrc = VINF_SUCCESS;
376 uint32_t uContextID = 0;
377
378 GuestCtrlCallback *pCallbackOpen;
379 try
380 {
381 pCallbackOpen = new GuestCtrlCallback();
382 }
383 catch(std::bad_alloc &)
384 {
385 vrc = VERR_NO_MEMORY;
386 }
387
388 if (RT_SUCCESS(vrc))
389 {
390 /* Create callback and add it to the map. */
391 vrc = pCallbackOpen->Init(CALLBACKTYPE_FILE_OPEN);
392 if (RT_SUCCESS(vrc))
393 vrc = callbackAdd(pCallbackOpen, &uContextID);
394 }
395
396 if (RT_SUCCESS(vrc))
397 {
398 GuestSession *pSession = mData.mSession;
399 AssertPtr(pSession);
400
401 const GuestCredentials &sessionCreds = pSession->getCredentials();
402
403 if (RT_SUCCESS(vrc))
404 {
405 /* Prepare HGCM call. */
406 VBOXHGCMSVCPARM paParms[8];
407 int i = 0;
408 paParms[i++].setUInt32(uContextID);
409 paParms[i++].setPointer((void*)mData.mOpenInfo.mFileName.c_str(),
410 (ULONG)mData.mOpenInfo.mFileName.length() + 1);
411 paParms[i++].setPointer((void*)mData.mOpenInfo.mOpenMode.c_str(),
412 (ULONG)mData.mOpenInfo.mOpenMode.length() + 1);
413 paParms[i++].setPointer((void*)mData.mOpenInfo.mDisposition.c_str(),
414 (ULONG)mData.mOpenInfo.mDisposition.length() + 1);
415 paParms[i++].setUInt32(mData.mOpenInfo.mCreationMode);
416 paParms[i++].setUInt64(mData.mOpenInfo.mInitialOffset);
417
418 /* Note: Don't hold the write lock in here. */
419 vrc = sendCommand(HOST_FILE_OPEN, i, paParms);
420 }
421
422 /* Drop the write lock again before waiting. */
423 alock.release();
424
425 if (RT_SUCCESS(vrc))
426 {
427 /*
428 * Let's wait for the process being started.
429 * Note: Be sure not keeping a AutoRead/WriteLock here.
430 */
431 LogFlowThisFunc(("Waiting for callback (30s) ...\n"));
432 vrc = pCallbackOpen->Wait(30 * 1000 /* Wait 30s max. */);
433 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
434 {
435 int guestRc = pCallbackOpen->GetResultCode();
436 if (RT_SUCCESS(guestRc))
437 {
438
439 }
440
441 if (pGuestRc)
442 *pGuestRc = guestRc;
443 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
444 }
445 else
446 vrc = VERR_TIMEOUT;
447 }
448
449 AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS);
450
451 AssertPtr(pCallbackOpen);
452 int rc2 = callbackRemove(uContextID);
453 if (RT_SUCCESS(vrc))
454 vrc = rc2;
455 }
456
457 LogFlowFuncLeaveRC(vrc);
458 return vrc;
459}
460
461// implementation of public methods
462/////////////////////////////////////////////////////////////////////////////
463
464STDMETHODIMP GuestFile::Close(void)
465{
466#ifndef VBOX_WITH_GUEST_CONTROL
467 ReturnComNotImplemented();
468#else
469 LogFlowThisFuncEnter();
470
471 AutoCaller autoCaller(this);
472 if (FAILED(autoCaller.rc())) return autoCaller.rc();
473
474 AssertPtr(mData.mSession);
475 int rc = mData.mSession->fileRemoveFromList(this);
476
477 /*
478 * Release autocaller before calling uninit.
479 */
480 autoCaller.release();
481
482 uninit();
483
484 LogFlowFuncLeaveRC(rc);
485 return S_OK;
486#endif /* VBOX_WITH_GUEST_CONTROL */
487}
488
489STDMETHODIMP GuestFile::QueryInfo(IFsObjInfo **aInfo)
490{
491#ifndef VBOX_WITH_GUEST_CONTROL
492 ReturnComNotImplemented();
493#else
494 AutoCaller autoCaller(this);
495 if (FAILED(autoCaller.rc())) return autoCaller.rc();
496
497 ReturnComNotImplemented();
498#endif /* VBOX_WITH_GUEST_CONTROL */
499}
500
501STDMETHODIMP GuestFile::Read(ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
502{
503#ifndef VBOX_WITH_GUEST_CONTROL
504 ReturnComNotImplemented();
505#else
506 AutoCaller autoCaller(this);
507 if (FAILED(autoCaller.rc())) return autoCaller.rc();
508
509 ReturnComNotImplemented();
510#endif /* VBOX_WITH_GUEST_CONTROL */
511}
512
513STDMETHODIMP GuestFile::ReadAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
514{
515#ifndef VBOX_WITH_GUEST_CONTROL
516 ReturnComNotImplemented();
517#else
518 AutoCaller autoCaller(this);
519 if (FAILED(autoCaller.rc())) return autoCaller.rc();
520
521 ReturnComNotImplemented();
522#endif /* VBOX_WITH_GUEST_CONTROL */
523}
524
525STDMETHODIMP GuestFile::Seek(LONG64 aOffset, FileSeekType_T aType)
526{
527#ifndef VBOX_WITH_GUEST_CONTROL
528 ReturnComNotImplemented();
529#else
530 AutoCaller autoCaller(this);
531 if (FAILED(autoCaller.rc())) return autoCaller.rc();
532
533 ReturnComNotImplemented();
534#endif /* VBOX_WITH_GUEST_CONTROL */
535}
536
537STDMETHODIMP GuestFile::SetACL(IN_BSTR aACL)
538{
539#ifndef VBOX_WITH_GUEST_CONTROL
540 ReturnComNotImplemented();
541#else
542 AutoCaller autoCaller(this);
543 if (FAILED(autoCaller.rc())) return autoCaller.rc();
544
545 ReturnComNotImplemented();
546#endif /* VBOX_WITH_GUEST_CONTROL */
547}
548
549STDMETHODIMP GuestFile::Write(ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
550{
551#ifndef VBOX_WITH_GUEST_CONTROL
552 ReturnComNotImplemented();
553#else
554 AutoCaller autoCaller(this);
555 if (FAILED(autoCaller.rc())) return autoCaller.rc();
556
557 ReturnComNotImplemented();
558#endif /* VBOX_WITH_GUEST_CONTROL */
559}
560
561STDMETHODIMP GuestFile::WriteAt(LONG64 aOffset, ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
562{
563#ifndef VBOX_WITH_GUEST_CONTROL
564 ReturnComNotImplemented();
565#else
566 AutoCaller autoCaller(this);
567 if (FAILED(autoCaller.rc())) return autoCaller.rc();
568
569 ReturnComNotImplemented();
570#endif /* VBOX_WITH_GUEST_CONTROL */
571}
572
Note: See TracBrowser for help on using the repository browser.

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