VirtualBox

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

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

Main/GuestCtrl: Use active listeners instead of passive ones because of performance reasons (untested).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.9 KB
Line 
1
2/* $Id: GuestFileImpl.cpp 45780 2013-04-26 15:19:33Z vboxsync $ */
3/** @file
4 * VirtualBox Main - Guest file handling.
5 */
6
7/*
8 * Copyright (C) 2012-2013 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#include "GuestErrorInfoImpl.h"
24#include "GuestFileImpl.h"
25#include "GuestSessionImpl.h"
26#include "GuestCtrlImplPrivate.h"
27#include "ConsoleImpl.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 mData.mID = 0;
156 mData.mInitialSize = 0;
157 mData.mStatus = FileStatus_Undefined;
158
159 unconst(mEventSource).createObject();
160 HRESULT hr = mEventSource->init(static_cast<IGuestFile*>(this));
161 if (FAILED(hr))
162 vrc = VERR_COM_UNEXPECTED;
163 }
164
165 if (RT_SUCCESS(vrc))
166 {
167 try
168 {
169 GuestFileListener *pListener = new GuestFileListener();
170 ComObjPtr<GuestFileListenerImpl> thisListener;
171 HRESULT hr = thisListener.createObject();
172 if (SUCCEEDED(hr))
173 hr = thisListener->init(pListener, this);
174
175 if (SUCCEEDED(hr))
176 {
177 mListener = thisListener;
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(mListener,
185 ComSafeArrayAsInParam(eventTypes),
186 TRUE /* Active listener */);
187 if (SUCCEEDED(hr))
188 {
189 vrc = RTCritSectInit(&mWaitEventCritSect);
190 AssertRC(vrc);
191 }
192 else
193 vrc = VERR_COM_UNEXPECTED;
194 }
195 else
196 vrc = VERR_COM_UNEXPECTED;
197 }
198 catch(std::bad_alloc &)
199 {
200 vrc = VERR_NO_MEMORY;
201 }
202 }
203
204 if (RT_SUCCESS(vrc))
205 {
206 /* Confirm a successful initialization when it's the case. */
207 autoInitSpan.setSucceeded();
208 }
209 else
210 autoInitSpan.setFailed();
211
212 LogFlowFuncLeaveRC(vrc);
213 return vrc;
214#endif /* VBOX_WITH_GUEST_CONTROL */
215}
216
217/**
218 * Uninitializes the instance.
219 * Called from FinalRelease().
220 */
221void GuestFile::uninit(void)
222{
223 LogFlowThisFunc(("\n"));
224
225 /* Enclose the state transition Ready->InUninit->NotReady. */
226 AutoUninitSpan autoUninitSpan(this);
227 if (autoUninitSpan.uninitDone())
228 return;
229
230#ifdef VBOX_WITH_GUEST_CONTROL
231 unconst(mEventSource).setNull();
232 unregisterEventListener();
233#endif
234
235 LogFlowThisFuncLeave();
236}
237
238// implementation of public getters/setters for attributes
239/////////////////////////////////////////////////////////////////////////////
240
241STDMETHODIMP GuestFile::COMGETTER(CreationMode)(ULONG *aCreationMode)
242{
243#ifndef VBOX_WITH_GUEST_CONTROL
244 ReturnComNotImplemented();
245#else
246 AutoCaller autoCaller(this);
247 if (FAILED(autoCaller.rc())) return autoCaller.rc();
248
249 CheckComArgOutPointerValid(aCreationMode);
250
251 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
252
253 *aCreationMode = mData.mOpenInfo.mCreationMode;
254
255 return S_OK;
256#endif /* VBOX_WITH_GUEST_CONTROL */
257}
258
259/** @todo For 4.3: Change ULONG* to BSTR* ?*/
260STDMETHODIMP GuestFile::COMGETTER(Disposition)(ULONG *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 *aDisposition = getDispositionFromString(mData.mOpenInfo.mDisposition);
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(InitialSize)(LONG64 *aInitialSize)
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(aInitialSize);
322
323 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
324
325 *aInitialSize = mData.mInitialSize;
326
327 return S_OK;
328#endif /* VBOX_WITH_GUEST_CONTROL */
329}
330
331STDMETHODIMP GuestFile::COMGETTER(Offset)(LONG64 *aOffset)
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(aOffset);
340
341 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
342
343 *aOffset = mData.mOffCurrent;
344
345 return S_OK;
346#endif /* VBOX_WITH_GUEST_CONTROL */
347}
348
349/** @todo For 4.3: Change ULONG* to BSTR* ?*/
350STDMETHODIMP GuestFile::COMGETTER(OpenMode)(ULONG *aOpenMode)
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(aOpenMode);
359
360 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
361
362 *aOpenMode = getOpenModeFromString(mData.mOpenInfo.mOpenMode);
363
364 return S_OK;
365#endif /* VBOX_WITH_GUEST_CONTROL */
366}
367
368STDMETHODIMP GuestFile::COMGETTER(Status)(FileStatus_T *aStatus)
369{
370#ifndef VBOX_WITH_GUEST_CONTROL
371 ReturnComNotImplemented();
372#else
373 LogFlowThisFuncEnter();
374
375 AutoCaller autoCaller(this);
376 if (FAILED(autoCaller.rc())) return autoCaller.rc();
377
378 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
379
380 *aStatus = mData.mStatus;
381
382 return S_OK;
383#endif /* VBOX_WITH_GUEST_CONTROL */
384}
385
386// private methods
387/////////////////////////////////////////////////////////////////////////////
388
389int GuestFile::callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
390{
391#ifdef DEBUG
392 LogFlowThisFunc(("strName=%s, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
393 mData.mOpenInfo.mFileName.c_str(), pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
394#endif
395 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
396
397 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
398
399 int vrc;
400 switch (pCbCtx->uFunction)
401 {
402 case GUEST_DISCONNECTED:
403 vrc = onGuestDisconnected(pCbCtx, pSvcCb);
404 break;
405
406 case GUEST_FILE_NOTIFY:
407 vrc = onFileNotify(pCbCtx, pSvcCb);
408 break;
409
410 default:
411 /* Silently ignore not implemented functions. */
412 vrc = VERR_NOT_SUPPORTED;
413 break;
414 }
415
416#ifdef DEBUG
417 LogFlowFuncLeaveRC(vrc);
418#endif
419 return vrc;
420}
421
422int GuestFile::closeFile(int *pGuestRc)
423{
424 LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFileName.c_str()));
425
426 int vrc;
427
428 GuestWaitEvent *pEvent = NULL;
429 std::list < VBoxEventType_T > eventTypes;
430 try
431 {
432 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
433
434 vrc = registerEvent(eventTypes, &pEvent);
435 }
436 catch (std::bad_alloc)
437 {
438 vrc = VERR_NO_MEMORY;
439 }
440
441 if (RT_FAILURE(vrc))
442 return vrc;
443
444 /* Prepare HGCM call. */
445 VBOXHGCMSVCPARM paParms[4];
446 int i = 0;
447 paParms[i++].setUInt32(pEvent->ContextID());
448 paParms[i++].setUInt32(mData.mID /* Guest file ID */);
449
450 vrc = sendCommand(HOST_FILE_CLOSE, i, paParms);
451 if (RT_SUCCESS(vrc))
452 vrc = waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */,
453 NULL /* FileStatus */);
454 unregisterEvent(pEvent);
455
456 LogFlowFuncLeaveRC(vrc);
457 return vrc;
458}
459
460/* static */
461uint32_t GuestFile::getDispositionFromString(const Utf8Str &strDisposition)
462{
463 return 0; /** @todo Implement me! */
464}
465
466/* static */
467uint32_t GuestFile::getOpenModeFromString(const Utf8Str &strOpenMode)
468{
469 uint32_t uOpenMode = 0;
470
471 const char *pc = strOpenMode.c_str();
472 while (*pc != '\0')
473 {
474 switch (*pc++)
475 {
476 case 'r':
477 uOpenMode |= RTFILE_O_READ;
478 break;
479
480 case 'w':
481 uOpenMode |= RTFILE_O_WRITE;
482 break;
483
484 default:
485 /* Silently skip unknown values. */
486 break;
487 }
488 }
489
490 return uOpenMode;
491}
492
493/* static */
494Utf8Str GuestFile::guestErrorToString(int guestRc)
495{
496 Utf8Str strError;
497
498 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
499 switch (guestRc)
500 {
501 case VERR_INVALID_VM_HANDLE:
502 strError += Utf8StrFmt(tr("VMM device is not available (is the VM running?)"));
503 break;
504
505 case VERR_HGCM_SERVICE_NOT_FOUND:
506 strError += Utf8StrFmt(tr("The guest execution service is not available"));
507 break;
508
509 case VERR_TIMEOUT:
510 strError += Utf8StrFmt(tr("The guest did not respond within time"));
511 break;
512
513 case VERR_CANCELLED:
514 strError += Utf8StrFmt(tr("The session operation was canceled"));
515 break;
516
517 case VERR_MAX_PROCS_REACHED:
518 strError += Utf8StrFmt(tr("Maximum number of concurrent guest files has been reached"));
519 break;
520
521 case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */
522 strError += Utf8StrFmt(tr("Unable to retrieve requested information"));
523 break;
524
525 case VERR_NOT_FOUND:
526 strError += Utf8StrFmt(tr("The guest execution service is not ready (yet)"));
527 break;
528
529 default:
530 strError += Utf8StrFmt("%Rrc", guestRc);
531 break;
532 }
533
534 return strError;
535}
536
537int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
538{
539 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
540 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
541
542 if (pSvcCbData->mParms < 3)
543 return VERR_INVALID_PARAMETER;
544
545 int vrc = VINF_SUCCESS;
546
547 int idx = 0; /* Current parameter index. */
548 CALLBACKDATA_FILE_NOTIFY dataCb;
549 /* pSvcCb->mpaParms[0] always contains the context ID. */
550 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.uType);
551 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.rc);
552
553 int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */
554
555 switch (dataCb.uType)
556 {
557 case GUEST_FILE_NOTIFYTYPE_ERROR:
558 {
559 AssertMsg(mData.mStatus != FileStatus_Error, ("File status already set to error\n"));
560
561 int rc2 = setFileStatus(FileStatus_Error, guestRc);
562 AssertRC(rc2);
563 break;
564 }
565
566 case GUEST_FILE_NOTIFYTYPE_OPEN:
567 {
568 if (pSvcCbData->mParms == 4)
569 {
570 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.open.uHandle);
571
572 AssertMsg(mData.mID == 0, ("File ID already set to %RU32\n", mData.mID));
573 mData.mID = dataCb.u.open.uHandle;
574 AssertMsg(mData.mID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID),
575 ("File ID %RU32 does not match context ID %RU32\n", mData.mID,
576 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));
577
578 /* Set the process status. */
579 int rc2 = setFileStatus(FileStatus_Open, guestRc);
580 if (RT_SUCCESS(vrc))
581 vrc = rc2;
582 }
583 else
584 vrc = VERR_NOT_SUPPORTED;
585
586 break;
587 }
588
589 case GUEST_FILE_NOTIFYTYPE_CLOSE:
590 {
591 int rc2 = setFileStatus(FileStatus_Closed, guestRc);
592 AssertRC(rc2);
593
594 break;
595 }
596
597 case GUEST_FILE_NOTIFYTYPE_READ:
598 if (pSvcCbData->mParms == 4)
599 {
600 pSvcCbData->mpaParms[idx++].getPointer(&dataCb.u.read.pvData,
601 &dataCb.u.read.cbData);
602 uint32_t cbRead = dataCb.u.read.cbData;
603 if (cbRead)
604 {
605 mData.mOffCurrent += cbRead;
606
607 com::SafeArray<BYTE> data((size_t)cbRead);
608 data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead);
609 fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent,
610 cbRead, ComSafeArrayAsInParam(data));
611 }
612 }
613 else
614 vrc = VERR_NOT_SUPPORTED;
615 break;
616
617 case GUEST_FILE_NOTIFYTYPE_WRITE:
618 if (pSvcCbData->mParms == 4)
619 {
620 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.write.cbWritten);
621
622 mData.mOffCurrent += dataCb.u.write.cbWritten;
623
624 if (dataCb.u.write.cbWritten)
625 fireGuestFileWriteEvent(mEventSource, mSession, this, mData.mOffCurrent,
626 dataCb.u.write.cbWritten);
627 }
628 else
629 vrc = VERR_NOT_SUPPORTED;
630 break;
631
632 case GUEST_FILE_NOTIFYTYPE_SEEK:
633 if (pSvcCbData->mParms == 4)
634 {
635 pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.seek.uOffActual);
636
637 mData.mOffCurrent = dataCb.u.seek.uOffActual;
638
639 if (dataCb.u.seek.uOffActual)
640 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
641 mData.mOffCurrent, 0 /* Processed */);
642 }
643 else
644 vrc = VERR_NOT_SUPPORTED;
645 break;
646
647 case GUEST_FILE_NOTIFYTYPE_TELL:
648 if (pSvcCbData->mParms == 4)
649 {
650 pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.tell.uOffActual);
651
652 if (mData.mOffCurrent != dataCb.u.tell.uOffActual)
653 {
654 mData.mOffCurrent = dataCb.u.tell.uOffActual;
655
656 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
657 mData.mOffCurrent, 0 /* Processed */);
658 }
659 }
660 else
661 vrc = VERR_NOT_SUPPORTED;
662 break;
663
664 default:
665 vrc = VERR_NOT_SUPPORTED;
666 break;
667 }
668
669 LogFlowThisFunc(("strName=%s, uType=%RU32, guestRc=%Rrc\n",
670 mData.mOpenInfo.mFileName.c_str(), dataCb.uType, dataCb.rc));
671
672 if (RT_SUCCESS(vrc))
673 {
674 /* Nothing to do here yet. */
675 }
676 else if (vrc == VERR_NOT_SUPPORTED)
677 {
678 /* Also let the callback know. */
679 guestRc = VERR_NOT_SUPPORTED;
680 }
681
682 LogFlowFuncLeaveRC(vrc);
683 return vrc;
684}
685
686int GuestFile::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
687{
688 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
689 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
690
691 LogFlowThisFunc(("strFile=%s\n",
692 mData.mOpenInfo.mFileName.c_str()));
693
694 int vrc = setFileStatus(FileStatus_Down, VINF_SUCCESS);
695
696 LogFlowFuncLeaveRC(vrc);
697 return vrc;
698}
699
700int GuestFile::openFile(int *pGuestRc)
701{
702 LogFlowThisFunc(("strFile=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%RU32\n",
703 mData.mOpenInfo.mFileName.c_str(), mData.mOpenInfo.mOpenMode.c_str(),
704 mData.mOpenInfo.mDisposition.c_str(), mData.mOpenInfo.mCreationMode));
705 int vrc;
706
707 GuestWaitEvent *pEvent = NULL;
708 std::list < VBoxEventType_T > eventTypes;
709 try
710 {
711 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
712
713 vrc = registerEvent(eventTypes, &pEvent);
714 }
715 catch (std::bad_alloc)
716 {
717 vrc = VERR_NO_MEMORY;
718 }
719
720 if (RT_FAILURE(vrc))
721 return vrc;
722
723 /* Prepare HGCM call. */
724 VBOXHGCMSVCPARM paParms[8];
725 int i = 0;
726 paParms[i++].setUInt32(pEvent->ContextID());
727 paParms[i++].setPointer((void*)mData.mOpenInfo.mFileName.c_str(),
728 (ULONG)mData.mOpenInfo.mFileName.length() + 1);
729 paParms[i++].setPointer((void*)mData.mOpenInfo.mOpenMode.c_str(),
730 (ULONG)mData.mOpenInfo.mOpenMode.length() + 1);
731 paParms[i++].setPointer((void*)mData.mOpenInfo.mDisposition.c_str(),
732 (ULONG)mData.mOpenInfo.mDisposition.length() + 1);
733 paParms[i++].setUInt32(mData.mOpenInfo.mCreationMode);
734 paParms[i++].setUInt64(mData.mOpenInfo.mInitialOffset);
735
736 vrc = sendCommand(HOST_FILE_OPEN, i, paParms);
737 if (RT_SUCCESS(vrc))
738 vrc = waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */,
739 NULL /* FileStatus */);
740
741 unregisterEvent(pEvent);
742
743 LogFlowFuncLeaveRC(vrc);
744 return vrc;
745}
746
747int GuestFile::readData(uint32_t uSize, uint32_t uTimeoutMS,
748 void* pvData, uint32_t cbData, uint32_t* pcbRead)
749{
750 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
751 AssertReturn(cbData, VERR_INVALID_PARAMETER);
752
753 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
754 uSize, uTimeoutMS, pvData, cbData));
755 int vrc;
756
757 GuestWaitEvent *pEvent = NULL;
758 std::list < VBoxEventType_T > eventTypes;
759 try
760 {
761 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
762 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
763
764 vrc = registerEvent(eventTypes, &pEvent);
765 }
766 catch (std::bad_alloc)
767 {
768 vrc = VERR_NO_MEMORY;
769 }
770
771 if (RT_FAILURE(vrc))
772 return vrc;
773
774 /* Prepare HGCM call. */
775 VBOXHGCMSVCPARM paParms[4];
776 int i = 0;
777 paParms[i++].setUInt32(pEvent->ContextID());
778 paParms[i++].setUInt32(mData.mID /* File handle */);
779 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
780
781 uint32_t cbRead;
782 vrc = sendCommand(HOST_FILE_READ, i, paParms);
783 if (RT_SUCCESS(vrc))
784 vrc = waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
785
786 if (RT_SUCCESS(vrc))
787 {
788 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
789
790 if (pcbRead)
791 *pcbRead = cbRead;
792 }
793
794 unregisterEvent(pEvent);
795
796 LogFlowFuncLeaveRC(vrc);
797 return vrc;
798}
799
800int GuestFile::readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
801 void* pvData, size_t cbData, size_t* pcbRead)
802{
803 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
804 uOffset, uSize, uTimeoutMS, pvData, cbData));
805 int vrc;
806
807 GuestWaitEvent *pEvent = NULL;
808 std::list < VBoxEventType_T > eventTypes;
809 try
810 {
811 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
812 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
813
814 vrc = registerEvent(eventTypes, &pEvent);
815 }
816 catch (std::bad_alloc)
817 {
818 vrc = VERR_NO_MEMORY;
819 }
820
821 if (RT_FAILURE(vrc))
822 return vrc;
823
824 /* Prepare HGCM call. */
825 VBOXHGCMSVCPARM paParms[4];
826 int i = 0;
827 paParms[i++].setUInt32(pEvent->ContextID());
828 paParms[i++].setUInt32(mData.mID /* File handle */);
829 paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
830 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
831
832 uint32_t cbRead;
833 vrc = sendCommand(HOST_FILE_READ_AT, i, paParms);
834 if (RT_SUCCESS(vrc))
835 vrc = waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
836
837 if (RT_SUCCESS(vrc))
838 {
839 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
840
841 if (pcbRead)
842 *pcbRead = cbRead;
843 }
844
845 unregisterEvent(pEvent);
846
847 LogFlowFuncLeaveRC(vrc);
848 return vrc;
849}
850
851int GuestFile::seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType,
852 uint32_t uTimeoutMS, uint64_t *puOffset)
853{
854 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32\n",
855 uOffset, uTimeoutMS));
856 int vrc;
857
858 GuestWaitEvent *pEvent = NULL;
859 std::list < VBoxEventType_T > eventTypes;
860 try
861 {
862 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
863 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
864
865 vrc = registerEvent(eventTypes, &pEvent);
866 }
867 catch (std::bad_alloc)
868 {
869 vrc = VERR_NO_MEMORY;
870 }
871
872 if (RT_FAILURE(vrc))
873 return vrc;
874
875 /* Prepare HGCM call. */
876 VBOXHGCMSVCPARM paParms[4];
877 int i = 0;
878 paParms[i++].setUInt32(pEvent->ContextID());
879 paParms[i++].setUInt32(mData.mID /* File handle */);
880 paParms[i++].setUInt32(eSeekType /* Seek method */);
881 paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
882
883 vrc = sendCommand(HOST_FILE_SEEK, i, paParms);
884 if (RT_SUCCESS(vrc))
885 vrc = waitForOffsetChange(pEvent, uTimeoutMS, puOffset);
886
887 unregisterEvent(pEvent);
888
889 LogFlowFuncLeaveRC(vrc);
890 return vrc;
891}
892
893/* static */
894HRESULT GuestFile::setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
895{
896 AssertPtr(pInterface);
897 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
898
899 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestFile::guestErrorToString(guestRc).c_str());
900}
901
902/* Does not do locking; caller is responsible for that! */
903int GuestFile::setFileStatus(FileStatus_T fileStatus, int fileRc)
904{
905 LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, fileRc=%Rrc\n",
906 mData.mStatus, fileStatus, fileRc));
907
908#ifdef VBOX_STRICT
909 if (fileStatus == FileStatus_Error)
910 {
911 AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc));
912 }
913 else
914 AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc));
915#endif
916
917 if (mData.mStatus != fileStatus)
918 {
919 mData.mStatus = fileStatus;
920
921 ComObjPtr<GuestErrorInfo> errorInfo;
922 HRESULT hr = errorInfo.createObject();
923 ComAssertComRC(hr);
924 if (RT_FAILURE(fileRc))
925 {
926 int rc2 = errorInfo->init(fileRc, guestErrorToString(fileRc));
927 AssertRC(rc2);
928 }
929
930 fireGuestFileStateChangedEvent(mEventSource, mSession,
931 this, mData.mStatus, errorInfo);
932 }
933
934 return VINF_SUCCESS;
935}
936
937int GuestFile::waitForOffsetChange(GuestWaitEvent *pEvent,
938 uint32_t uTimeoutMS, uint64_t *puOffset)
939{
940 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
941
942 VBoxEventType_T evtType;
943 ComPtr<IEvent> pIEvent;
944 int vrc = waitForEvent(pEvent, uTimeoutMS,
945 &evtType, pIEvent.asOutParam());
946 if (RT_SUCCESS(vrc))
947 {
948 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
949 {
950 if (puOffset)
951 {
952 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
953 Assert(!pFileEvent.isNull());
954
955 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
956 ComAssertComRC(hr);
957 }
958 }
959 else
960 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
961 }
962
963 return vrc;
964}
965
966int GuestFile::waitForRead(GuestWaitEvent *pEvent,
967 uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead)
968{
969 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
970
971 VBoxEventType_T evtType;
972 ComPtr<IEvent> pIEvent;
973 int vrc = waitForEvent(pEvent, uTimeoutMS,
974 &evtType, pIEvent.asOutParam());
975 if (RT_SUCCESS(vrc))
976 {
977 if (evtType == VBoxEventType_OnGuestFileRead)
978 {
979 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
980 Assert(!pFileEvent.isNull());
981
982 HRESULT hr;
983 if (pvData)
984 {
985 com::SafeArray <BYTE> data;
986 hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
987 ComAssertComRC(hr);
988 size_t cbRead = data.size();
989 if ( cbRead
990 && cbRead <= cbData)
991 {
992 memcpy(pvData, data.raw(), data.size());
993 }
994 else
995 vrc = VERR_BUFFER_OVERFLOW;
996 }
997 if (pcbRead)
998 {
999 hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
1000 ComAssertComRC(hr);
1001 }
1002 }
1003 else
1004 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1005 }
1006
1007 return vrc;
1008}
1009
1010int GuestFile::waitForStatusChange(GuestWaitEvent *pEvent,
1011 uint32_t uTimeoutMS, FileStatus_T *pFileStatus)
1012{
1013 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1014
1015 VBoxEventType_T evtType;
1016 ComPtr<IEvent> pIEvent;
1017 int vrc = waitForEvent(pEvent, uTimeoutMS,
1018 &evtType, pIEvent.asOutParam());
1019 if (RT_SUCCESS(vrc))
1020 {
1021 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
1022 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
1023 Assert(!pFileEvent.isNull());
1024
1025 HRESULT hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1026 ComAssertComRC(hr);
1027 }
1028
1029 return vrc;
1030}
1031
1032int GuestFile::waitForWrite(GuestWaitEvent *pEvent,
1033 uint32_t uTimeoutMS, uint32_t *pcbWritten)
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_OnGuestFileWrite)
1044 {
1045 if (pcbWritten)
1046 {
1047 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1048 Assert(!pFileEvent.isNull());
1049
1050 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1051 ComAssertComRC(hr);
1052 }
1053 }
1054 else
1055 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1056 }
1057
1058 return vrc;
1059}
1060
1061int GuestFile::writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData,
1062 uint32_t *pcbWritten)
1063{
1064 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1065 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1066
1067 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1068 uTimeoutMS, pvData, cbData));
1069 int vrc;
1070
1071 GuestWaitEvent *pEvent = NULL;
1072 std::list < VBoxEventType_T > eventTypes;
1073 try
1074 {
1075 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1076 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1077
1078 vrc = registerEvent(eventTypes, &pEvent);
1079 }
1080 catch (std::bad_alloc)
1081 {
1082 vrc = VERR_NO_MEMORY;
1083 }
1084
1085 if (RT_FAILURE(vrc))
1086 return vrc;
1087
1088 /* Prepare HGCM call. */
1089 VBOXHGCMSVCPARM paParms[8];
1090 int i = 0;
1091 paParms[i++].setUInt32(pEvent->ContextID());
1092 paParms[i++].setUInt32(mData.mID /* File handle */);
1093 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
1094 paParms[i++].setPointer(pvData, cbData);
1095
1096 uint32_t cbWritten;
1097 vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
1098 if (RT_SUCCESS(vrc))
1099 vrc = waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1100
1101 if (RT_SUCCESS(vrc))
1102 {
1103 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1104
1105 if (cbWritten)
1106 *pcbWritten = cbWritten;
1107 }
1108
1109 unregisterEvent(pEvent);
1110
1111 LogFlowFuncLeaveRC(vrc);
1112 return vrc;
1113}
1114
1115int GuestFile::writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
1116 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1117{
1118 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1119 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1120
1121 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1122 uOffset, uTimeoutMS, pvData, cbData));
1123 int vrc;
1124
1125 GuestWaitEvent *pEvent = NULL;
1126 std::list < VBoxEventType_T > eventTypes;
1127 try
1128 {
1129 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1130 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1131
1132 vrc = registerEvent(eventTypes, &pEvent);
1133 }
1134 catch (std::bad_alloc)
1135 {
1136 vrc = VERR_NO_MEMORY;
1137 }
1138
1139 if (RT_FAILURE(vrc))
1140 return vrc;
1141
1142 /* Prepare HGCM call. */
1143 VBOXHGCMSVCPARM paParms[8];
1144 int i = 0;
1145 paParms[i++].setUInt32(pEvent->ContextID());
1146 paParms[i++].setUInt32(mData.mID /* File handle */);
1147 paParms[i++].setUInt64(uOffset /* Offset where to starting writing */);
1148 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
1149 paParms[i++].setPointer(pvData, cbData);
1150
1151 uint32_t cbWritten;
1152 vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
1153 if (RT_SUCCESS(vrc))
1154 vrc = waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1155
1156 if (RT_SUCCESS(vrc))
1157 {
1158 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1159
1160 if (cbWritten)
1161 *pcbWritten = cbWritten;
1162 }
1163
1164 unregisterEvent(pEvent);
1165
1166 LogFlowFuncLeaveRC(vrc);
1167 return vrc;
1168}
1169
1170// implementation of public methods
1171/////////////////////////////////////////////////////////////////////////////
1172
1173STDMETHODIMP GuestFile::Close(void)
1174{
1175#ifndef VBOX_WITH_GUEST_CONTROL
1176 ReturnComNotImplemented();
1177#else
1178 LogFlowThisFuncEnter();
1179
1180 AutoCaller autoCaller(this);
1181 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1182
1183 /* Close file on guest. */
1184 int guestRc;
1185 int rc = closeFile(&guestRc);
1186 /* On failure don't return here, instead do all the cleanup
1187 * work first and then return an error. */
1188
1189 AssertPtr(mSession);
1190 int rc2 = mSession->fileRemoveFromList(this);
1191 if (RT_SUCCESS(rc))
1192 rc = rc2;
1193
1194 /*
1195 * Release autocaller before calling uninit.
1196 */
1197 autoCaller.release();
1198
1199 uninit();
1200
1201 LogFlowFuncLeaveRC(rc);
1202 if (RT_FAILURE(rc))
1203 {
1204 if (rc == VERR_GSTCTL_GUEST_ERROR)
1205 return GuestFile::setErrorExternal(this, guestRc);
1206
1207 return setError(VBOX_E_IPRT_ERROR,
1208 tr("Closing guest file failed with %Rrc\n"), rc);
1209 }
1210
1211 return S_OK;
1212#endif /* VBOX_WITH_GUEST_CONTROL */
1213}
1214
1215STDMETHODIMP GuestFile::QueryInfo(IFsObjInfo **aInfo)
1216{
1217#ifndef VBOX_WITH_GUEST_CONTROL
1218 ReturnComNotImplemented();
1219#else
1220 AutoCaller autoCaller(this);
1221 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1222
1223 ReturnComNotImplemented();
1224#endif /* VBOX_WITH_GUEST_CONTROL */
1225}
1226
1227STDMETHODIMP GuestFile::Read(ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
1228{
1229#ifndef VBOX_WITH_GUEST_CONTROL
1230 ReturnComNotImplemented();
1231#else
1232 if (aToRead == 0)
1233 return setError(E_INVALIDARG, tr("The size to read is zero"));
1234 CheckComArgOutSafeArrayPointerValid(aData);
1235
1236 AutoCaller autoCaller(this);
1237 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1238
1239 com::SafeArray<BYTE> data((size_t)aToRead);
1240 Assert(data.size() >= aToRead);
1241
1242 HRESULT hr = S_OK;
1243
1244 uint32_t cbRead;
1245 int vrc = readData(aToRead, aTimeoutMS,
1246 data.raw(), aToRead, &cbRead);
1247 if (RT_SUCCESS(vrc))
1248 {
1249 if (data.size() != cbRead)
1250 data.resize(cbRead);
1251 data.detachTo(ComSafeArrayOutArg(aData));
1252 }
1253 else
1254 {
1255 switch (vrc)
1256 {
1257 default:
1258 hr = setError(VBOX_E_IPRT_ERROR,
1259 tr("Reading from file \"%s\" failed: %Rrc"),
1260 mData.mOpenInfo.mFileName.c_str(), vrc);
1261 break;
1262 }
1263 }
1264
1265 LogFlowFuncLeaveRC(vrc);
1266 return hr;
1267#endif /* VBOX_WITH_GUEST_CONTROL */
1268}
1269
1270STDMETHODIMP GuestFile::ReadAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
1271{
1272#ifndef VBOX_WITH_GUEST_CONTROL
1273 ReturnComNotImplemented();
1274#else
1275 if (aToRead == 0)
1276 return setError(E_INVALIDARG, tr("The size to read is zero"));
1277 CheckComArgOutSafeArrayPointerValid(aData);
1278
1279 AutoCaller autoCaller(this);
1280 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1281
1282 com::SafeArray<BYTE> data((size_t)aToRead);
1283 Assert(data.size() >= aToRead);
1284
1285 HRESULT hr = S_OK;
1286
1287 size_t cbRead;
1288 int vrc = readDataAt(aOffset, aToRead, aTimeoutMS,
1289 data.raw(), aToRead, &cbRead);
1290 if (RT_SUCCESS(vrc))
1291 {
1292 if (data.size() != cbRead)
1293 data.resize(cbRead);
1294 data.detachTo(ComSafeArrayOutArg(aData));
1295 }
1296 else
1297 {
1298 switch (vrc)
1299 {
1300 default:
1301 hr = setError(VBOX_E_IPRT_ERROR,
1302 tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1303 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1304 break;
1305 }
1306 }
1307
1308 LogFlowFuncLeaveRC(vrc);
1309 return hr;
1310#endif /* VBOX_WITH_GUEST_CONTROL */
1311}
1312
1313STDMETHODIMP GuestFile::Seek(LONG64 aOffset, FileSeekType_T aType)
1314{
1315#ifndef VBOX_WITH_GUEST_CONTROL
1316 ReturnComNotImplemented();
1317#else
1318 LogFlowThisFuncEnter();
1319
1320 AutoCaller autoCaller(this);
1321 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1322
1323 HRESULT hr = S_OK;
1324
1325 GUEST_FILE_SEEKTYPE eSeekType;
1326 switch (aType)
1327 {
1328 case FileSeekType_Set:
1329 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1330 break;
1331
1332 case FileSeekType_Current:
1333 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1334 break;
1335
1336 default:
1337 return setError(E_INVALIDARG, tr("Invalid seek type specified"));
1338 break;
1339 }
1340
1341 int vrc = seekAt(aOffset, eSeekType,
1342 30 * 1000 /* 30s timeout */, NULL /* puOffset */);
1343 if (RT_FAILURE(vrc))
1344 {
1345 switch (vrc)
1346 {
1347 default:
1348 hr = setError(VBOX_E_IPRT_ERROR,
1349 tr("Seeking file \"%s\" (to offset %RU64) failed: %Rrc"),
1350 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1351 break;
1352 }
1353 }
1354
1355 LogFlowFuncLeaveRC(vrc);
1356 return hr;
1357#endif /* VBOX_WITH_GUEST_CONTROL */
1358}
1359
1360STDMETHODIMP GuestFile::SetACL(IN_BSTR aACL)
1361{
1362#ifndef VBOX_WITH_GUEST_CONTROL
1363 ReturnComNotImplemented();
1364#else
1365 AutoCaller autoCaller(this);
1366 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1367
1368 ReturnComNotImplemented();
1369#endif /* VBOX_WITH_GUEST_CONTROL */
1370}
1371
1372STDMETHODIMP GuestFile::Write(ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1373{
1374#ifndef VBOX_WITH_GUEST_CONTROL
1375 ReturnComNotImplemented();
1376#else
1377 LogFlowThisFuncEnter();
1378
1379 CheckComArgOutPointerValid(aWritten);
1380
1381 AutoCaller autoCaller(this);
1382 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1383
1384 HRESULT hr = S_OK;
1385
1386 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
1387 int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(),
1388 (uint32_t*)aWritten);
1389 if (RT_FAILURE(vrc))
1390 {
1391 switch (vrc)
1392 {
1393 default:
1394 hr = setError(VBOX_E_IPRT_ERROR,
1395 tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
1396 data.size(), mData.mOpenInfo.mFileName.c_str(), vrc);
1397 break;
1398 }
1399 }
1400
1401 LogFlowFuncLeaveRC(vrc);
1402 return hr;
1403#endif /* VBOX_WITH_GUEST_CONTROL */
1404}
1405
1406STDMETHODIMP GuestFile::WriteAt(LONG64 aOffset, ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1407{
1408#ifndef VBOX_WITH_GUEST_CONTROL
1409 ReturnComNotImplemented();
1410#else
1411 LogFlowThisFuncEnter();
1412
1413 CheckComArgOutPointerValid(aWritten);
1414
1415 AutoCaller autoCaller(this);
1416 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1417
1418 HRESULT hr = S_OK;
1419
1420 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
1421 int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(),
1422 (uint32_t*)aWritten);
1423 if (RT_FAILURE(vrc))
1424 {
1425 switch (vrc)
1426 {
1427 default:
1428 hr = setError(VBOX_E_IPRT_ERROR,
1429 tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
1430 data.size(), mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1431 break;
1432 }
1433 }
1434
1435 LogFlowFuncLeaveRC(vrc);
1436 return hr;
1437#endif /* VBOX_WITH_GUEST_CONTROL */
1438}
1439
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