VirtualBox

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

Last change on this file since 49930 was 49610, checked in by vboxsync, 11 years ago

Main/GuestCtrl: Don't keep ComObjPtr of parents in internal listeners.

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