VirtualBox

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

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

GuestCtrl: Update for IGuestFile; some renaming.

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