VirtualBox

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

Last change on this file since 49517 was 49504, checked in by vboxsync, 11 years ago

Main/GuestCtrl: Reference counting bugfixes, handle more directoryCreate errors.

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