VirtualBox

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

Last change on this file since 49223 was 49006, checked in by vboxsync, 11 years ago

Main/GuestFileImpl.cpp: More locking.

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