VirtualBox

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

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

Main/GuestCtrl: Bugfixes:

  • Hold lock while registering wait event in GuestProcess::waitFor()
  • Fixes for GuestProcess::waitFlagsToResultEx()
  • Use public wait events for internal GuestFile methods
  • Remove wait event from all other event groups when signaled
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.6 KB
Line 
1
2/* $Id: GuestFileImpl.cpp 49440 2013-11-11 15:44:53Z 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#include "VirtualBoxErrorInfoImpl.h"
28
29#include "Global.h"
30#include "AutoCaller.h"
31#include "VBoxEvents.h"
32
33#include <iprt/cpp/utils.h> /* For unconst(). */
34#include <iprt/file.h>
35
36#include <VBox/com/array.h>
37#include <VBox/com/listeners.h>
38
39#ifdef LOG_GROUP
40 #undef LOG_GROUP
41#endif
42#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
43#include <VBox/log.h>
44
45
46/**
47 * Internal listener class to serve events in an
48 * active manner, e.g. without polling delays.
49 */
50class GuestFileListener
51{
52public:
53
54 GuestFileListener(void)
55 {
56 }
57
58 HRESULT init(GuestFile *pFile)
59 {
60 mFile = pFile;
61 return S_OK;
62 }
63
64 void uninit(void)
65 {
66 mFile.setNull();
67 }
68
69 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
70 {
71 switch (aType)
72 {
73 case VBoxEventType_OnGuestFileStateChanged:
74 case VBoxEventType_OnGuestFileOffsetChanged:
75 case VBoxEventType_OnGuestFileRead:
76 case VBoxEventType_OnGuestFileWrite:
77 {
78 Assert(!mFile.isNull());
79 int rc2 = mFile->signalWaitEvent(aType, aEvent);
80#ifdef DEBUG_andy
81 LogFlowFunc(("Signalling events of type=%ld, file=%p resulted in rc=%Rrc\n",
82 aType, mFile, rc2));
83#endif
84 break;
85 }
86
87 default:
88 AssertMsgFailed(("Unhandled event %ld\n", aType));
89 break;
90 }
91
92 return S_OK;
93 }
94
95private:
96
97 ComObjPtr<GuestFile> mFile;
98};
99typedef ListenerImpl<GuestFileListener, GuestFile*> GuestFileListenerImpl;
100
101VBOX_LISTENER_DECLARE(GuestFileListenerImpl)
102
103// constructor / destructor
104/////////////////////////////////////////////////////////////////////////////
105
106DEFINE_EMPTY_CTOR_DTOR(GuestFile)
107
108HRESULT GuestFile::FinalConstruct(void)
109{
110 LogFlowThisFuncEnter();
111 return BaseFinalConstruct();
112}
113
114void GuestFile::FinalRelease(void)
115{
116 LogFlowThisFuncEnter();
117 uninit();
118 BaseFinalRelease();
119 LogFlowThisFuncLeave();
120}
121
122// public initializer/uninitializer for internal purposes only
123/////////////////////////////////////////////////////////////////////////////
124
125/**
126 * Initializes a file object but does *not* open the file on the guest
127 * yet. This is done in the dedidcated openFile call.
128 *
129 * @return IPRT status code.
130 * @param pConsole Pointer to console object.
131 * @param pSession Pointer to session object.
132 * @param uFileID Host-based file ID (part of the context ID).
133 * @param openInfo File opening information.
134 */
135int GuestFile::init(Console *pConsole, GuestSession *pSession,
136 ULONG uFileID, const GuestFileOpenInfo &openInfo)
137{
138 LogFlowThisFunc(("pConsole=%p, pSession=%p, uFileID=%RU32, strPath=%s\n",
139 pConsole, pSession, uFileID, openInfo.mFileName.c_str()));
140
141 AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
142 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
143
144 /* Enclose the state transition NotReady->InInit->Ready. */
145 AutoInitSpan autoInitSpan(this);
146 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
147
148#ifndef VBOX_WITH_GUEST_CONTROL
149 autoInitSpan.setSucceeded();
150 return VINF_SUCCESS;
151#else
152 int vrc = bindToSession(pConsole, pSession, uFileID /* Object ID */);
153 if (RT_SUCCESS(vrc))
154 {
155 mSession = pSession;
156
157 mData.mID = uFileID;
158 mData.mInitialSize = 0;
159 mData.mStatus = FileStatus_Undefined;
160 mData.mOpenInfo = openInfo;
161
162 unconst(mEventSource).createObject();
163 HRESULT hr = mEventSource->init(static_cast<IGuestFile*>(this));
164 if (FAILED(hr))
165 vrc = VERR_COM_UNEXPECTED;
166 }
167
168 if (RT_SUCCESS(vrc))
169 {
170 try
171 {
172 GuestFileListener *pListener = new GuestFileListener();
173 ComObjPtr<GuestFileListenerImpl> thisListener;
174 HRESULT hr = thisListener.createObject();
175 if (SUCCEEDED(hr))
176 hr = thisListener->init(pListener, this);
177
178 if (SUCCEEDED(hr))
179 {
180 com::SafeArray <VBoxEventType_T> eventTypes;
181 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
182 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
183 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
184 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
185 hr = mEventSource->RegisterListener(thisListener,
186 ComSafeArrayAsInParam(eventTypes),
187 TRUE /* Active listener */);
188 if (SUCCEEDED(hr))
189 {
190 vrc = baseInit();
191 if (RT_SUCCESS(vrc))
192 {
193 mLocalListener = thisListener;
194 }
195 }
196 else
197 vrc = VERR_COM_UNEXPECTED;
198 }
199 else
200 vrc = VERR_COM_UNEXPECTED;
201 }
202 catch(std::bad_alloc &)
203 {
204 vrc = VERR_NO_MEMORY;
205 }
206 }
207
208 if (RT_SUCCESS(vrc))
209 {
210 /* Confirm a successful initialization when it's the case. */
211 autoInitSpan.setSucceeded();
212 }
213 else
214 autoInitSpan.setFailed();
215
216 LogFlowFuncLeaveRC(vrc);
217 return vrc;
218#endif /* VBOX_WITH_GUEST_CONTROL */
219}
220
221/**
222 * Uninitializes the instance.
223 * Called from FinalRelease().
224 */
225void GuestFile::uninit(void)
226{
227 LogFlowThisFuncEnter();
228
229 /* Enclose the state transition Ready->InUninit->NotReady. */
230 AutoUninitSpan autoUninitSpan(this);
231 if (autoUninitSpan.uninitDone())
232 return;
233
234#ifdef VBOX_WITH_GUEST_CONTROL
235 baseUninit();
236
237 if (!mEventSource.isNull())
238 {
239 mEventSource->UnregisterListener(mLocalListener);
240
241 mLocalListener.setNull();
242 unconst(mEventSource).setNull();
243 }
244#endif
245
246 LogFlowThisFuncLeave();
247}
248
249// implementation of public getters/setters for attributes
250/////////////////////////////////////////////////////////////////////////////
251
252STDMETHODIMP GuestFile::COMGETTER(CreationMode)(ULONG *aCreationMode)
253{
254#ifndef VBOX_WITH_GUEST_CONTROL
255 ReturnComNotImplemented();
256#else
257 AutoCaller autoCaller(this);
258 if (FAILED(autoCaller.rc())) return autoCaller.rc();
259
260 CheckComArgOutPointerValid(aCreationMode);
261
262 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
263
264 *aCreationMode = mData.mOpenInfo.mCreationMode;
265
266 return S_OK;
267#endif /* VBOX_WITH_GUEST_CONTROL */
268}
269
270STDMETHODIMP GuestFile::COMGETTER(Disposition)(BSTR *aDisposition)
271{
272#ifndef VBOX_WITH_GUEST_CONTROL
273 ReturnComNotImplemented();
274#else
275 AutoCaller autoCaller(this);
276 if (FAILED(autoCaller.rc())) return autoCaller.rc();
277
278 CheckComArgOutPointerValid(aDisposition);
279
280 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
281
282 mData.mOpenInfo.mDisposition.cloneTo(aDisposition);
283
284 return S_OK;
285#endif /* VBOX_WITH_GUEST_CONTROL */
286}
287
288STDMETHODIMP GuestFile::COMGETTER(EventSource)(IEventSource ** aEventSource)
289{
290#ifndef VBOX_WITH_GUEST_CONTROL
291 ReturnComNotImplemented();
292#else
293 CheckComArgOutPointerValid(aEventSource);
294
295 AutoCaller autoCaller(this);
296 if (FAILED(autoCaller.rc())) return autoCaller.rc();
297
298 /* No need to lock - lifetime constant. */
299 mEventSource.queryInterfaceTo(aEventSource);
300
301 return S_OK;
302#endif /* VBOX_WITH_GUEST_CONTROL */
303}
304
305STDMETHODIMP GuestFile::COMGETTER(FileName)(BSTR *aFileName)
306{
307#ifndef VBOX_WITH_GUEST_CONTROL
308 ReturnComNotImplemented();
309#else
310 AutoCaller autoCaller(this);
311 if (FAILED(autoCaller.rc())) return autoCaller.rc();
312
313 CheckComArgOutPointerValid(aFileName);
314
315 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
316
317 mData.mOpenInfo.mFileName.cloneTo(aFileName);
318
319 return S_OK;
320#endif /* VBOX_WITH_GUEST_CONTROL */
321}
322
323STDMETHODIMP GuestFile::COMGETTER(Id)(ULONG *aID)
324{
325#ifndef VBOX_WITH_GUEST_CONTROL
326 ReturnComNotImplemented();
327#else
328 AutoCaller autoCaller(this);
329 if (FAILED(autoCaller.rc())) return autoCaller.rc();
330
331 CheckComArgOutPointerValid(aID);
332
333 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
334
335 *aID = mData.mID;
336
337 return S_OK;
338#endif /* VBOX_WITH_GUEST_CONTROL */
339}
340
341STDMETHODIMP GuestFile::COMGETTER(InitialSize)(LONG64 *aInitialSize)
342{
343#ifndef VBOX_WITH_GUEST_CONTROL
344 ReturnComNotImplemented();
345#else
346 AutoCaller autoCaller(this);
347 if (FAILED(autoCaller.rc())) return autoCaller.rc();
348
349 CheckComArgOutPointerValid(aInitialSize);
350
351 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
352
353 *aInitialSize = mData.mInitialSize;
354
355 return S_OK;
356#endif /* VBOX_WITH_GUEST_CONTROL */
357}
358
359STDMETHODIMP GuestFile::COMGETTER(Offset)(LONG64 *aOffset)
360{
361#ifndef VBOX_WITH_GUEST_CONTROL
362 ReturnComNotImplemented();
363#else
364 AutoCaller autoCaller(this);
365 if (FAILED(autoCaller.rc())) return autoCaller.rc();
366
367 CheckComArgOutPointerValid(aOffset);
368
369 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
370
371 *aOffset = mData.mOffCurrent;
372
373 return S_OK;
374#endif /* VBOX_WITH_GUEST_CONTROL */
375}
376
377STDMETHODIMP GuestFile::COMGETTER(OpenMode)(BSTR *aOpenMode)
378{
379#ifndef VBOX_WITH_GUEST_CONTROL
380 ReturnComNotImplemented();
381#else
382 AutoCaller autoCaller(this);
383 if (FAILED(autoCaller.rc())) return autoCaller.rc();
384
385 CheckComArgOutPointerValid(aOpenMode);
386
387 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
388
389 mData.mOpenInfo.mOpenMode.cloneTo(aOpenMode);
390
391 return S_OK;
392#endif /* VBOX_WITH_GUEST_CONTROL */
393}
394
395STDMETHODIMP GuestFile::COMGETTER(Status)(FileStatus_T *aStatus)
396{
397#ifndef VBOX_WITH_GUEST_CONTROL
398 ReturnComNotImplemented();
399#else
400 LogFlowThisFuncEnter();
401
402 AutoCaller autoCaller(this);
403 if (FAILED(autoCaller.rc())) return autoCaller.rc();
404
405 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
406
407 *aStatus = mData.mStatus;
408
409 return S_OK;
410#endif /* VBOX_WITH_GUEST_CONTROL */
411}
412
413// private methods
414/////////////////////////////////////////////////////////////////////////////
415
416int GuestFile::callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
417{
418 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
419 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
420
421 LogFlowThisFunc(("strName=%s, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
422 mData.mOpenInfo.mFileName.c_str(), pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
423
424 int vrc;
425 switch (pCbCtx->uFunction)
426 {
427 case GUEST_DISCONNECTED:
428 vrc = onGuestDisconnected(pCbCtx, pSvcCb);
429 break;
430
431 case GUEST_FILE_NOTIFY:
432 vrc = onFileNotify(pCbCtx, pSvcCb);
433 break;
434
435 default:
436 /* Silently ignore not implemented functions. */
437 vrc = VERR_NOT_SUPPORTED;
438 break;
439 }
440
441#ifdef DEBUG
442 LogFlowFuncLeaveRC(vrc);
443#endif
444 return vrc;
445}
446
447int GuestFile::closeFile(int *pGuestRc)
448{
449 LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFileName.c_str()));
450
451 int vrc;
452
453 GuestWaitEvent *pEvent = NULL;
454 GuestEventTypes eventTypes;
455 try
456 {
457 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
458
459 vrc = registerWaitEvent(eventTypes, &pEvent);
460 }
461 catch (std::bad_alloc)
462 {
463 vrc = VERR_NO_MEMORY;
464 }
465
466 if (RT_FAILURE(vrc))
467 return vrc;
468
469 /* Prepare HGCM call. */
470 VBOXHGCMSVCPARM paParms[4];
471 int i = 0;
472 paParms[i++].setUInt32(pEvent->ContextID());
473 paParms[i++].setUInt32(mData.mID /* Guest file ID */);
474
475 vrc = sendCommand(HOST_FILE_CLOSE, i, paParms);
476 if (RT_SUCCESS(vrc))
477 vrc = waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */,
478 NULL /* FileStatus */, pGuestRc);
479 unregisterWaitEvent(pEvent);
480
481 LogFlowFuncLeaveRC(vrc);
482 return vrc;
483}
484
485/* static */
486Utf8Str GuestFile::guestErrorToString(int guestRc)
487{
488 Utf8Str strError;
489
490 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
491 switch (guestRc)
492 {
493 case VERR_ALREADY_EXISTS:
494 strError += Utf8StrFmt(tr("File already exists"));
495 break;
496
497 case VERR_FILE_NOT_FOUND:
498 strError += Utf8StrFmt(tr("File not found"));
499 break;
500
501 case VERR_NET_HOST_NOT_FOUND:
502 strError += Utf8StrFmt(tr("Host name not found"));
503 break;
504
505 case VERR_SHARING_VIOLATION:
506 strError += Utf8StrFmt(tr("Sharing violation"));
507 break;
508
509 default:
510 strError += Utf8StrFmt("%Rrc", guestRc);
511 break;
512 }
513
514 return strError;
515}
516
517int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
518{
519 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
520 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
521
522 LogFlowThisFuncEnter();
523
524 if (pSvcCbData->mParms < 3)
525 return VERR_INVALID_PARAMETER;
526
527 int vrc = VINF_SUCCESS;
528
529 int idx = 1; /* Current parameter index. */
530 CALLBACKDATA_FILE_NOTIFY dataCb;
531 /* pSvcCb->mpaParms[0] always contains the context ID. */
532 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.uType);
533 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.rc);
534
535 FileStatus_T fileStatus = FileStatus_Undefined;
536 int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */
537
538 LogFlowFunc(("uType=%RU32, guestRc=%Rrc\n",
539 dataCb.uType, guestRc));
540
541 if (RT_FAILURE(guestRc))
542 {
543 int rc2 = setFileStatus(FileStatus_Error, guestRc);
544 AssertRC(rc2);
545
546 rc2 = signalWaitEventInternal(pCbCtx,
547 guestRc, NULL /* pPayload */);
548 AssertRC(rc2);
549
550 return VINF_SUCCESS; /* Report to the guest. */
551 }
552
553 switch (dataCb.uType)
554 {
555 case GUEST_FILE_NOTIFYTYPE_ERROR:
556 {
557 int rc2 = setFileStatus(FileStatus_Error, guestRc);
558 AssertRC(rc2);
559
560 break;
561 }
562
563 case GUEST_FILE_NOTIFYTYPE_OPEN:
564 {
565 if (pSvcCbData->mParms == 4)
566 {
567 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.open.uHandle);
568
569 {
570 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
571 AssertMsg(mData.mID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID),
572 ("File ID %RU32 does not match context ID %RU32\n", mData.mID,
573 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));
574
575 /* Set the initial offset. On the guest the whole opening operation
576 * would fail if an initial seek isn't possible. */
577 mData.mOffCurrent = mData.mOpenInfo.mInitialOffset;
578 }
579
580 /* Set the process status. */
581 int rc2 = setFileStatus(FileStatus_Open, guestRc);
582 AssertRC(rc2);
583 }
584 else
585 vrc = VERR_NOT_SUPPORTED;
586
587 break;
588 }
589
590 case GUEST_FILE_NOTIFYTYPE_CLOSE:
591 {
592 int rc2 = setFileStatus(FileStatus_Closed, guestRc);
593 AssertRC(rc2);
594
595 break;
596 }
597
598 case GUEST_FILE_NOTIFYTYPE_READ:
599 {
600 if (pSvcCbData->mParms == 4)
601 {
602 pSvcCbData->mpaParms[idx++].getPointer(&dataCb.u.read.pvData,
603 &dataCb.u.read.cbData);
604 uint32_t cbRead = dataCb.u.read.cbData;
605
606 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
607
608 mData.mOffCurrent += cbRead;
609
610 alock.release();
611
612 com::SafeArray<BYTE> data((size_t)cbRead);
613 data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead);
614
615 fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent,
616 cbRead, ComSafeArrayAsInParam(data));
617 }
618 else
619 vrc = VERR_NOT_SUPPORTED;
620 break;
621 }
622
623 case GUEST_FILE_NOTIFYTYPE_WRITE:
624 {
625 if (pSvcCbData->mParms == 4)
626 {
627 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.write.cbWritten);
628
629 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
630
631 mData.mOffCurrent += dataCb.u.write.cbWritten;
632 uint64_t uOffCurrent = mData.mOffCurrent;
633
634 alock.release();
635
636 fireGuestFileWriteEvent(mEventSource, mSession, this, uOffCurrent,
637 dataCb.u.write.cbWritten);
638 }
639 else
640 vrc = VERR_NOT_SUPPORTED;
641 break;
642 }
643
644 case GUEST_FILE_NOTIFYTYPE_SEEK:
645 {
646 if (pSvcCbData->mParms == 4)
647 {
648 pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.seek.uOffActual);
649
650 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
651
652 mData.mOffCurrent = dataCb.u.seek.uOffActual;
653
654 alock.release();
655
656 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
657 dataCb.u.seek.uOffActual, 0 /* Processed */);
658 }
659 else
660 vrc = VERR_NOT_SUPPORTED;
661 break;
662 }
663
664 case GUEST_FILE_NOTIFYTYPE_TELL:
665 {
666 if (pSvcCbData->mParms == 4)
667 {
668 pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.tell.uOffActual);
669
670 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
671
672 mData.mOffCurrent = dataCb.u.tell.uOffActual;
673
674 alock.release();
675
676 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
677 dataCb.u.tell.uOffActual, 0 /* Processed */);
678 }
679 else
680 vrc = VERR_NOT_SUPPORTED;
681 break;
682 }
683
684 default:
685 vrc = VERR_NOT_SUPPORTED;
686 break;
687 }
688
689 if (RT_SUCCESS(vrc))
690 {
691 GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb));
692 int rc2 = signalWaitEventInternal(pCbCtx, guestRc, &payload);
693 AssertRC(rc2);
694 }
695
696 LogFlowThisFunc(("uType=%RU32, guestRc=%Rrc\n",
697 dataCb.uType, dataCb.rc));
698
699 LogFlowFuncLeaveRC(vrc);
700 return vrc;
701}
702
703int GuestFile::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
704{
705 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
706 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
707
708 int vrc = setFileStatus(FileStatus_Down, VINF_SUCCESS);
709
710 LogFlowFuncLeaveRC(vrc);
711 return vrc;
712}
713
714int GuestFile::openFile(uint32_t uTimeoutMS, int *pGuestRc)
715{
716 LogFlowThisFuncEnter();
717
718 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
719
720 LogFlowThisFunc(("strFile=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%RU32, uOffset=%RU64\n",
721 mData.mOpenInfo.mFileName.c_str(), mData.mOpenInfo.mOpenMode.c_str(),
722 mData.mOpenInfo.mDisposition.c_str(), mData.mOpenInfo.mCreationMode, mData.mOpenInfo.mInitialOffset));
723 int vrc;
724
725 GuestWaitEvent *pEvent = NULL;
726 GuestEventTypes eventTypes;
727 try
728 {
729 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
730
731 vrc = registerWaitEvent(eventTypes, &pEvent);
732 }
733 catch (std::bad_alloc)
734 {
735 vrc = VERR_NO_MEMORY;
736 }
737
738 if (RT_FAILURE(vrc))
739 return vrc;
740
741 /* Prepare HGCM call. */
742 VBOXHGCMSVCPARM paParms[8];
743 int i = 0;
744 paParms[i++].setUInt32(pEvent->ContextID());
745 paParms[i++].setPointer((void*)mData.mOpenInfo.mFileName.c_str(),
746 (ULONG)mData.mOpenInfo.mFileName.length() + 1);
747 paParms[i++].setPointer((void*)mData.mOpenInfo.mOpenMode.c_str(),
748 (ULONG)mData.mOpenInfo.mOpenMode.length() + 1);
749 paParms[i++].setPointer((void*)mData.mOpenInfo.mDisposition.c_str(),
750 (ULONG)mData.mOpenInfo.mDisposition.length() + 1);
751 paParms[i++].setPointer((void*)mData.mOpenInfo.mSharingMode.c_str(),
752 (ULONG)mData.mOpenInfo.mSharingMode.length() + 1);
753 paParms[i++].setUInt32(mData.mOpenInfo.mCreationMode);
754 paParms[i++].setUInt64(mData.mOpenInfo.mInitialOffset);
755
756 alock.release(); /* Drop write lock before sending. */
757
758 vrc = sendCommand(HOST_FILE_OPEN, i, paParms);
759 if (RT_SUCCESS(vrc))
760 vrc = waitForStatusChange(pEvent, uTimeoutMS,
761 NULL /* FileStatus */, pGuestRc);
762
763 unregisterWaitEvent(pEvent);
764
765 LogFlowFuncLeaveRC(vrc);
766 return vrc;
767}
768
769int GuestFile::readData(uint32_t uSize, uint32_t uTimeoutMS,
770 void* pvData, uint32_t cbData, uint32_t* pcbRead)
771{
772 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
773 AssertReturn(cbData, VERR_INVALID_PARAMETER);
774
775 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
776 uSize, uTimeoutMS, pvData, cbData));
777
778 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
779
780 int vrc;
781
782 GuestWaitEvent *pEvent = NULL;
783 GuestEventTypes eventTypes;
784 try
785 {
786 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
787 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
788
789 vrc = registerWaitEvent(eventTypes, &pEvent);
790 }
791 catch (std::bad_alloc)
792 {
793 vrc = VERR_NO_MEMORY;
794 }
795
796 if (RT_FAILURE(vrc))
797 return vrc;
798
799 /* Prepare HGCM call. */
800 VBOXHGCMSVCPARM paParms[4];
801 int i = 0;
802 paParms[i++].setUInt32(pEvent->ContextID());
803 paParms[i++].setUInt32(mData.mID /* File handle */);
804 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
805
806 alock.release(); /* Drop write lock before sending. */
807
808 uint32_t cbRead;
809 vrc = sendCommand(HOST_FILE_READ, i, paParms);
810 if (RT_SUCCESS(vrc))
811 vrc = waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
812
813 if (RT_SUCCESS(vrc))
814 {
815 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
816
817 if (pcbRead)
818 *pcbRead = cbRead;
819 }
820
821 unregisterWaitEvent(pEvent);
822
823 LogFlowFuncLeaveRC(vrc);
824 return vrc;
825}
826
827int GuestFile::readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
828 void* pvData, size_t cbData, size_t* pcbRead)
829{
830 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
831 uOffset, uSize, uTimeoutMS, pvData, cbData));
832
833 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
834
835 int vrc;
836
837 GuestWaitEvent *pEvent = NULL;
838 GuestEventTypes eventTypes;
839 try
840 {
841 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
842 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
843
844 vrc = registerWaitEvent(eventTypes, &pEvent);
845 }
846 catch (std::bad_alloc)
847 {
848 vrc = VERR_NO_MEMORY;
849 }
850
851 if (RT_FAILURE(vrc))
852 return vrc;
853
854 /* Prepare HGCM call. */
855 VBOXHGCMSVCPARM paParms[4];
856 int i = 0;
857 paParms[i++].setUInt32(pEvent->ContextID());
858 paParms[i++].setUInt32(mData.mID /* File handle */);
859 paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
860 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
861
862 alock.release(); /* Drop write lock before sending. */
863
864 uint32_t cbRead;
865 vrc = sendCommand(HOST_FILE_READ_AT, i, paParms);
866 if (RT_SUCCESS(vrc))
867 vrc = waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
868
869 if (RT_SUCCESS(vrc))
870 {
871 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
872
873 if (pcbRead)
874 *pcbRead = cbRead;
875 }
876
877 unregisterWaitEvent(pEvent);
878
879 LogFlowFuncLeaveRC(vrc);
880 return vrc;
881}
882
883int GuestFile::seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType,
884 uint32_t uTimeoutMS, uint64_t *puOffset)
885{
886 LogFlowThisFunc(("iOffset=%RI64, uTimeoutMS=%RU32\n",
887 iOffset, uTimeoutMS));
888
889 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
890
891 int vrc;
892
893 GuestWaitEvent *pEvent = NULL;
894 GuestEventTypes eventTypes;
895 try
896 {
897 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
898 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
899
900 vrc = registerWaitEvent(eventTypes, &pEvent);
901 }
902 catch (std::bad_alloc)
903 {
904 vrc = VERR_NO_MEMORY;
905 }
906
907 if (RT_FAILURE(vrc))
908 return vrc;
909
910 /* Prepare HGCM call. */
911 VBOXHGCMSVCPARM paParms[4];
912 int i = 0;
913 paParms[i++].setUInt32(pEvent->ContextID());
914 paParms[i++].setUInt32(mData.mID /* File handle */);
915 paParms[i++].setUInt32(eSeekType /* Seek method */);
916 /** @todo uint64_t vs. int64_t! */
917 paParms[i++].setUInt64((uint64_t)iOffset /* Offset (in bytes) to start reading */);
918
919 alock.release(); /* Drop write lock before sending. */
920
921 vrc = sendCommand(HOST_FILE_SEEK, i, paParms);
922 if (RT_SUCCESS(vrc))
923 vrc = waitForOffsetChange(pEvent, uTimeoutMS, puOffset);
924
925 unregisterWaitEvent(pEvent);
926
927 LogFlowFuncLeaveRC(vrc);
928 return vrc;
929}
930
931/* static */
932HRESULT GuestFile::setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
933{
934 AssertPtr(pInterface);
935 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
936
937 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestFile::guestErrorToString(guestRc).c_str());
938}
939
940int GuestFile::setFileStatus(FileStatus_T fileStatus, int fileRc)
941{
942 LogFlowThisFuncEnter();
943
944 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
945
946 LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, fileRc=%Rrc\n",
947 mData.mStatus, fileStatus, fileRc));
948
949#ifdef VBOX_STRICT
950 if (fileStatus == FileStatus_Error)
951 {
952 AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc));
953 }
954 else
955 AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc));
956#endif
957
958 if (mData.mStatus != fileStatus)
959 {
960 mData.mStatus = fileStatus;
961 mData.mLastError = fileRc;
962
963 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
964 HRESULT hr = errorInfo.createObject();
965 ComAssertComRC(hr);
966 if (RT_FAILURE(fileRc))
967 {
968 hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, fileRc,
969 COM_IIDOF(IGuestFile), getComponentName(),
970 guestErrorToString(fileRc));
971 ComAssertComRC(hr);
972 }
973
974 alock.release(); /* Release lock before firing off event. */
975
976 fireGuestFileStateChangedEvent(mEventSource, mSession,
977 this, fileStatus, errorInfo);
978 }
979
980 return VINF_SUCCESS;
981}
982
983int GuestFile::waitForOffsetChange(GuestWaitEvent *pEvent,
984 uint32_t uTimeoutMS, uint64_t *puOffset)
985{
986 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
987
988 VBoxEventType_T evtType;
989 ComPtr<IEvent> pIEvent;
990 int vrc = waitForEvent(pEvent, uTimeoutMS,
991 &evtType, pIEvent.asOutParam());
992 if (RT_SUCCESS(vrc))
993 {
994 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
995 {
996 if (puOffset)
997 {
998 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
999 Assert(!pFileEvent.isNull());
1000
1001 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
1002 ComAssertComRC(hr);
1003 }
1004 }
1005 else
1006 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1007 }
1008
1009 return vrc;
1010}
1011
1012int GuestFile::waitForRead(GuestWaitEvent *pEvent,
1013 uint32_t uTimeoutMS,
1014 void *pvData, size_t cbData, uint32_t *pcbRead)
1015{
1016 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1017
1018 VBoxEventType_T evtType;
1019 ComPtr<IEvent> pIEvent;
1020 int vrc = waitForEvent(pEvent, uTimeoutMS,
1021 &evtType, pIEvent.asOutParam());
1022 if (RT_SUCCESS(vrc))
1023 {
1024 if (evtType == VBoxEventType_OnGuestFileRead)
1025 {
1026 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
1027 Assert(!pFileEvent.isNull());
1028
1029 HRESULT hr;
1030 if (pvData)
1031 {
1032 com::SafeArray <BYTE> data;
1033 hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1034 ComAssertComRC(hr);
1035 size_t cbRead = data.size();
1036 if ( cbRead
1037 && cbRead <= cbData)
1038 {
1039 memcpy(pvData, data.raw(), data.size());
1040 }
1041 else
1042 vrc = VERR_BUFFER_OVERFLOW;
1043 }
1044 if (pcbRead)
1045 {
1046 hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
1047 ComAssertComRC(hr);
1048 }
1049 }
1050 else
1051 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1052 }
1053
1054 return vrc;
1055}
1056
1057int GuestFile::waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1058 FileStatus_T *pFileStatus, int *pGuestRc)
1059{
1060 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1061 /* pFileStatus is optional. */
1062
1063 VBoxEventType_T evtType;
1064 ComPtr<IEvent> pIEvent;
1065 int vrc = waitForEvent(pEvent, uTimeoutMS,
1066 &evtType, pIEvent.asOutParam());
1067 if (RT_SUCCESS(vrc))
1068 {
1069 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
1070 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
1071 Assert(!pFileEvent.isNull());
1072
1073 HRESULT hr;
1074 if (pFileStatus)
1075 {
1076 hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1077 ComAssertComRC(hr);
1078 }
1079
1080 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1081 hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam());
1082 ComAssertComRC(hr);
1083
1084 LONG lGuestRc;
1085 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1086 ComAssertComRC(hr);
1087
1088 LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n",
1089 lGuestRc, lGuestRc));
1090
1091 if (RT_FAILURE((int)lGuestRc))
1092 vrc = VERR_GSTCTL_GUEST_ERROR;
1093
1094 if (pGuestRc)
1095 *pGuestRc = (int)lGuestRc;
1096 }
1097
1098 return vrc;
1099}
1100
1101int GuestFile::waitForWrite(GuestWaitEvent *pEvent,
1102 uint32_t uTimeoutMS, uint32_t *pcbWritten)
1103{
1104 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1105
1106 VBoxEventType_T evtType;
1107 ComPtr<IEvent> pIEvent;
1108 int vrc = waitForEvent(pEvent, uTimeoutMS,
1109 &evtType, pIEvent.asOutParam());
1110 if (RT_SUCCESS(vrc))
1111 {
1112 if (evtType == VBoxEventType_OnGuestFileWrite)
1113 {
1114 if (pcbWritten)
1115 {
1116 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1117 Assert(!pFileEvent.isNull());
1118
1119 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1120 ComAssertComRC(hr);
1121 }
1122 }
1123 else
1124 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1125 }
1126
1127 return vrc;
1128}
1129
1130int GuestFile::writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData,
1131 uint32_t *pcbWritten)
1132{
1133 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1134 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1135
1136 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1137 uTimeoutMS, pvData, cbData));
1138
1139 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1140
1141 int vrc;
1142
1143 GuestWaitEvent *pEvent = NULL;
1144 GuestEventTypes eventTypes;
1145 try
1146 {
1147 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1148 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1149
1150 vrc = registerWaitEvent(eventTypes, &pEvent);
1151 }
1152 catch (std::bad_alloc)
1153 {
1154 vrc = VERR_NO_MEMORY;
1155 }
1156
1157 if (RT_FAILURE(vrc))
1158 return vrc;
1159
1160 /* Prepare HGCM call. */
1161 VBOXHGCMSVCPARM paParms[8];
1162 int i = 0;
1163 paParms[i++].setUInt32(pEvent->ContextID());
1164 paParms[i++].setUInt32(mData.mID /* File handle */);
1165 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
1166 paParms[i++].setPointer(pvData, cbData);
1167
1168 alock.release(); /* Drop write lock before sending. */
1169
1170 uint32_t cbWritten;
1171 vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
1172 if (RT_SUCCESS(vrc))
1173 vrc = waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1174
1175 if (RT_SUCCESS(vrc))
1176 {
1177 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1178
1179 if (cbWritten)
1180 *pcbWritten = cbWritten;
1181 }
1182
1183 unregisterWaitEvent(pEvent);
1184
1185 LogFlowFuncLeaveRC(vrc);
1186 return vrc;
1187}
1188
1189int GuestFile::writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
1190 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1191{
1192 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1193 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1194
1195 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1196 uOffset, uTimeoutMS, pvData, cbData));
1197
1198 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1199
1200 int vrc;
1201
1202 GuestWaitEvent *pEvent = NULL;
1203 GuestEventTypes eventTypes;
1204 try
1205 {
1206 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1207 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1208
1209 vrc = registerWaitEvent(eventTypes, &pEvent);
1210 }
1211 catch (std::bad_alloc)
1212 {
1213 vrc = VERR_NO_MEMORY;
1214 }
1215
1216 if (RT_FAILURE(vrc))
1217 return vrc;
1218
1219 /* Prepare HGCM call. */
1220 VBOXHGCMSVCPARM paParms[8];
1221 int i = 0;
1222 paParms[i++].setUInt32(pEvent->ContextID());
1223 paParms[i++].setUInt32(mData.mID /* File handle */);
1224 paParms[i++].setUInt64(uOffset /* Offset where to starting writing */);
1225 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
1226 paParms[i++].setPointer(pvData, cbData);
1227
1228 alock.release(); /* Drop write lock before sending. */
1229
1230 uint32_t cbWritten;
1231 vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
1232 if (RT_SUCCESS(vrc))
1233 vrc = waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1234
1235 if (RT_SUCCESS(vrc))
1236 {
1237 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1238
1239 if (cbWritten)
1240 *pcbWritten = cbWritten;
1241 }
1242
1243 unregisterWaitEvent(pEvent);
1244
1245 LogFlowFuncLeaveRC(vrc);
1246 return vrc;
1247}
1248
1249// implementation of public methods
1250/////////////////////////////////////////////////////////////////////////////
1251
1252STDMETHODIMP GuestFile::Close(void)
1253{
1254#ifndef VBOX_WITH_GUEST_CONTROL
1255 ReturnComNotImplemented();
1256#else
1257 LogFlowThisFuncEnter();
1258
1259 AutoCaller autoCaller(this);
1260 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1261
1262 /* Close file on guest. */
1263 int guestRc;
1264 int rc = closeFile(&guestRc);
1265 /* On failure don't return here, instead do all the cleanup
1266 * work first and then return an error. */
1267
1268 AssertPtr(mSession);
1269 int rc2 = mSession->fileRemoveFromList(this);
1270 if (RT_SUCCESS(rc))
1271 rc = rc2;
1272
1273 if (RT_FAILURE(rc))
1274 {
1275 if (rc == VERR_GSTCTL_GUEST_ERROR)
1276 return GuestFile::setErrorExternal(this, guestRc);
1277
1278 return setError(VBOX_E_IPRT_ERROR,
1279 tr("Closing guest file failed with %Rrc\n"), rc);
1280 }
1281
1282 LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
1283 return S_OK;
1284#endif /* VBOX_WITH_GUEST_CONTROL */
1285}
1286
1287STDMETHODIMP GuestFile::QueryInfo(IFsObjInfo **aInfo)
1288{
1289#ifndef VBOX_WITH_GUEST_CONTROL
1290 ReturnComNotImplemented();
1291#else
1292 AutoCaller autoCaller(this);
1293 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1294
1295 ReturnComNotImplemented();
1296#endif /* VBOX_WITH_GUEST_CONTROL */
1297}
1298
1299STDMETHODIMP GuestFile::Read(ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
1300{
1301#ifndef VBOX_WITH_GUEST_CONTROL
1302 ReturnComNotImplemented();
1303#else
1304 if (aToRead == 0)
1305 return setError(E_INVALIDARG, tr("The size to read is zero"));
1306 CheckComArgOutSafeArrayPointerValid(aData);
1307
1308 AutoCaller autoCaller(this);
1309 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1310
1311 com::SafeArray<BYTE> data((size_t)aToRead);
1312 Assert(data.size() >= aToRead);
1313
1314 HRESULT hr = S_OK;
1315
1316 uint32_t cbRead;
1317 int vrc = readData(aToRead, aTimeoutMS,
1318 data.raw(), aToRead, &cbRead);
1319 if (RT_SUCCESS(vrc))
1320 {
1321 if (data.size() != cbRead)
1322 data.resize(cbRead);
1323 data.detachTo(ComSafeArrayOutArg(aData));
1324 }
1325 else
1326 {
1327 switch (vrc)
1328 {
1329 default:
1330 hr = setError(VBOX_E_IPRT_ERROR,
1331 tr("Reading from file \"%s\" failed: %Rrc"),
1332 mData.mOpenInfo.mFileName.c_str(), vrc);
1333 break;
1334 }
1335 }
1336
1337 LogFlowFuncLeaveRC(vrc);
1338 return hr;
1339#endif /* VBOX_WITH_GUEST_CONTROL */
1340}
1341
1342STDMETHODIMP GuestFile::ReadAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
1343{
1344#ifndef VBOX_WITH_GUEST_CONTROL
1345 ReturnComNotImplemented();
1346#else
1347 if (aToRead == 0)
1348 return setError(E_INVALIDARG, tr("The size to read is zero"));
1349 CheckComArgOutSafeArrayPointerValid(aData);
1350
1351 AutoCaller autoCaller(this);
1352 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1353
1354 com::SafeArray<BYTE> data((size_t)aToRead);
1355 Assert(data.size() >= aToRead);
1356
1357 HRESULT hr = S_OK;
1358
1359 size_t cbRead;
1360 int vrc = readDataAt(aOffset, aToRead, aTimeoutMS,
1361 data.raw(), aToRead, &cbRead);
1362 if (RT_SUCCESS(vrc))
1363 {
1364 if (data.size() != cbRead)
1365 data.resize(cbRead);
1366 data.detachTo(ComSafeArrayOutArg(aData));
1367 }
1368 else
1369 {
1370 switch (vrc)
1371 {
1372 default:
1373 hr = setError(VBOX_E_IPRT_ERROR,
1374 tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1375 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1376 break;
1377 }
1378 }
1379
1380 LogFlowFuncLeaveRC(vrc);
1381 return hr;
1382#endif /* VBOX_WITH_GUEST_CONTROL */
1383}
1384
1385STDMETHODIMP GuestFile::Seek(LONG64 aOffset, FileSeekType_T aType)
1386{
1387#ifndef VBOX_WITH_GUEST_CONTROL
1388 ReturnComNotImplemented();
1389#else
1390 LogFlowThisFuncEnter();
1391
1392 AutoCaller autoCaller(this);
1393 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1394
1395 HRESULT hr = S_OK;
1396
1397 GUEST_FILE_SEEKTYPE eSeekType;
1398 switch (aType)
1399 {
1400 case FileSeekType_Set:
1401 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1402 break;
1403
1404 case FileSeekType_Current:
1405 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1406 break;
1407
1408 default:
1409 return setError(E_INVALIDARG, tr("Invalid seek type specified"));
1410 break; /* Never reached. */
1411 }
1412
1413 int vrc = seekAt(aOffset, eSeekType,
1414 30 * 1000 /* 30s timeout */, NULL /* puOffset */);
1415 if (RT_FAILURE(vrc))
1416 {
1417 switch (vrc)
1418 {
1419 default:
1420 hr = setError(VBOX_E_IPRT_ERROR,
1421 tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"),
1422 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1423 break;
1424 }
1425 }
1426
1427 LogFlowFuncLeaveRC(vrc);
1428 return hr;
1429#endif /* VBOX_WITH_GUEST_CONTROL */
1430}
1431
1432STDMETHODIMP GuestFile::SetACL(IN_BSTR aACL)
1433{
1434#ifndef VBOX_WITH_GUEST_CONTROL
1435 ReturnComNotImplemented();
1436#else
1437 AutoCaller autoCaller(this);
1438 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1439
1440 ReturnComNotImplemented();
1441#endif /* VBOX_WITH_GUEST_CONTROL */
1442}
1443
1444STDMETHODIMP GuestFile::Write(ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1445{
1446#ifndef VBOX_WITH_GUEST_CONTROL
1447 ReturnComNotImplemented();
1448#else
1449 LogFlowThisFuncEnter();
1450
1451 CheckComArgSafeArrayNotNull(aData);
1452 CheckComArgOutPointerValid(aWritten);
1453
1454 AutoCaller autoCaller(this);
1455 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1456
1457 HRESULT hr = S_OK;
1458
1459 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
1460 int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(),
1461 (uint32_t*)aWritten);
1462 if (RT_FAILURE(vrc))
1463 {
1464 switch (vrc)
1465 {
1466 default:
1467 hr = setError(VBOX_E_IPRT_ERROR,
1468 tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
1469 data.size(), mData.mOpenInfo.mFileName.c_str(), vrc);
1470 break;
1471 }
1472 }
1473
1474 LogFlowFuncLeaveRC(vrc);
1475 return hr;
1476#endif /* VBOX_WITH_GUEST_CONTROL */
1477}
1478
1479STDMETHODIMP GuestFile::WriteAt(LONG64 aOffset, ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1480{
1481#ifndef VBOX_WITH_GUEST_CONTROL
1482 ReturnComNotImplemented();
1483#else
1484 LogFlowThisFuncEnter();
1485
1486 CheckComArgSafeArrayNotNull(aData);
1487 CheckComArgOutPointerValid(aWritten);
1488
1489 AutoCaller autoCaller(this);
1490 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1491
1492 HRESULT hr = S_OK;
1493
1494 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
1495 int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(),
1496 (uint32_t*)aWritten);
1497 if (RT_FAILURE(vrc))
1498 {
1499 switch (vrc)
1500 {
1501 default:
1502 hr = setError(VBOX_E_IPRT_ERROR,
1503 tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
1504 data.size(), mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1505 break;
1506 }
1507 }
1508
1509 LogFlowFuncLeaveRC(vrc);
1510 return hr;
1511#endif /* VBOX_WITH_GUEST_CONTROL */
1512}
1513
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