VirtualBox

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

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

Main: Removed IGuestErrorInfo, added new attribute resultDetail to IVirtualBoxErrorInfo for (optionally) providing more details on the error happened.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.0 KB
Line 
1
2/* $Id: GuestFileImpl.cpp 45805 2013-04-29 12:30:50Z vboxsync $ */
3/** @file
4 * VirtualBox Main - Guest file handling.
5 */
6
7/*
8 * Copyright (C) 2012-2013 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#include "GuestFileImpl.h"
24#include "GuestSessionImpl.h"
25#include "GuestCtrlImplPrivate.h"
26#include "ConsoleImpl.h"
27#include "VirtualBoxErrorInfoImpl.h"
28
29#include "Global.h"
30#include "AutoCaller.h"
31#include "VBoxEvents.h"
32
33#include <iprt/cpp/utils.h> /* For unconst(). */
34#include <iprt/file.h>
35
36#include <VBox/com/array.h>
37#include <VBox/com/listeners.h>
38
39#ifdef LOG_GROUP
40 #undef LOG_GROUP
41#endif
42#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
43#include <VBox/log.h>
44
45
46/**
47 * Internal listener class to serve events in an
48 * active manner, e.g. without polling delays.
49 */
50class GuestFileListener
51{
52public:
53
54 GuestFileListener(void)
55 {
56 }
57
58 HRESULT init(GuestFile *pFile)
59 {
60 mFile = pFile;
61 return S_OK;
62 }
63
64 void uninit(void)
65 {
66 mFile.setNull();
67 }
68
69 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
70 {
71 switch (aType)
72 {
73 case VBoxEventType_OnGuestFileStateChanged:
74 case VBoxEventType_OnGuestFileOffsetChanged:
75 case VBoxEventType_OnGuestFileRead:
76 case VBoxEventType_OnGuestFileWrite:
77 {
78 Assert(!mFile.isNull());
79 int rc2 = mFile->signalWaitEvents(aType, aEvent);
80#ifdef DEBUG_andy
81 LogFlowFunc(("Signalling events of type=%ld, file=%p resulted in rc=%Rrc\n",
82 aType, mFile, rc2));
83#endif
84 break;
85 }
86
87 default:
88 AssertMsgFailed(("Unhandled event %ld\n", aType));
89 break;
90 }
91
92 return S_OK;
93 }
94
95private:
96
97 ComObjPtr<GuestFile> mFile;
98};
99typedef ListenerImpl<GuestFileListener, GuestFile*> GuestFileListenerImpl;
100
101VBOX_LISTENER_DECLARE(GuestFileListenerImpl)
102
103// constructor / destructor
104/////////////////////////////////////////////////////////////////////////////
105
106DEFINE_EMPTY_CTOR_DTOR(GuestFile)
107
108HRESULT GuestFile::FinalConstruct(void)
109{
110 LogFlowThisFunc(("\n"));
111 return BaseFinalConstruct();
112}
113
114void GuestFile::FinalRelease(void)
115{
116 LogFlowThisFuncEnter();
117 uninit();
118 BaseFinalRelease();
119 LogFlowThisFuncLeave();
120}
121
122// public initializer/uninitializer for internal purposes only
123/////////////////////////////////////////////////////////////////////////////
124
125/**
126 * Initializes a file object but does *not* open the file on the guest
127 * yet. This is done in the dedidcated openFile call.
128 *
129 * @return IPRT status code.
130 * @param pConsole Pointer to console object.
131 * @param pSession Pointer to session object.
132 * @param uFileID Host-based file ID (part of the context ID).
133 * @param openInfo File opening information.
134 */
135int GuestFile::init(Console *pConsole, GuestSession *pSession,
136 ULONG uFileID, const GuestFileOpenInfo &openInfo)
137{
138 LogFlowThisFunc(("pConsole=%p, pSession=%p, uFileID=%RU32, strPath=%s\n",
139 pConsole, pSession, uFileID, openInfo.mFileName.c_str()));
140
141 AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
142 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
143
144 /* Enclose the state transition NotReady->InInit->Ready. */
145 AutoInitSpan autoInitSpan(this);
146 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
147
148#ifndef VBOX_WITH_GUEST_CONTROL
149 autoInitSpan.setSucceeded();
150 return VINF_SUCCESS;
151#else
152 int vrc = bindToSession(pConsole, pSession, uFileID /* Object ID */);
153 if (RT_SUCCESS(vrc))
154 {
155 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<VirtualBoxErrorInfo> errorInfo;
922 HRESULT hr = errorInfo.createObject();
923 ComAssertComRC(hr);
924 if (RT_FAILURE(fileRc))
925 {
926 int rc2 = errorInfo->initEx(VBOX_E_IPRT_ERROR, fileRc,
927 COM_IIDOF(IGuestFile), getComponentName(),
928 guestErrorToString(fileRc));
929 AssertRC(rc2);
930 }
931
932 fireGuestFileStateChangedEvent(mEventSource, mSession,
933 this, mData.mStatus, errorInfo);
934 }
935
936 return VINF_SUCCESS;
937}
938
939int GuestFile::waitForOffsetChange(GuestWaitEvent *pEvent,
940 uint32_t uTimeoutMS, uint64_t *puOffset)
941{
942 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
943
944 VBoxEventType_T evtType;
945 ComPtr<IEvent> pIEvent;
946 int vrc = waitForEvent(pEvent, uTimeoutMS,
947 &evtType, pIEvent.asOutParam());
948 if (RT_SUCCESS(vrc))
949 {
950 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
951 {
952 if (puOffset)
953 {
954 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
955 Assert(!pFileEvent.isNull());
956
957 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
958 ComAssertComRC(hr);
959 }
960 }
961 else
962 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
963 }
964
965 return vrc;
966}
967
968int GuestFile::waitForRead(GuestWaitEvent *pEvent,
969 uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead)
970{
971 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
972
973 VBoxEventType_T evtType;
974 ComPtr<IEvent> pIEvent;
975 int vrc = waitForEvent(pEvent, uTimeoutMS,
976 &evtType, pIEvent.asOutParam());
977 if (RT_SUCCESS(vrc))
978 {
979 if (evtType == VBoxEventType_OnGuestFileRead)
980 {
981 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
982 Assert(!pFileEvent.isNull());
983
984 HRESULT hr;
985 if (pvData)
986 {
987 com::SafeArray <BYTE> data;
988 hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
989 ComAssertComRC(hr);
990 size_t cbRead = data.size();
991 if ( cbRead
992 && cbRead <= cbData)
993 {
994 memcpy(pvData, data.raw(), data.size());
995 }
996 else
997 vrc = VERR_BUFFER_OVERFLOW;
998 }
999 if (pcbRead)
1000 {
1001 hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
1002 ComAssertComRC(hr);
1003 }
1004 }
1005 else
1006 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1007 }
1008
1009 return vrc;
1010}
1011
1012int GuestFile::waitForStatusChange(GuestWaitEvent *pEvent,
1013 uint32_t uTimeoutMS, FileStatus_T *pFileStatus)
1014{
1015 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1016
1017 VBoxEventType_T evtType;
1018 ComPtr<IEvent> pIEvent;
1019 int vrc = waitForEvent(pEvent, uTimeoutMS,
1020 &evtType, pIEvent.asOutParam());
1021 if (RT_SUCCESS(vrc))
1022 {
1023 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
1024 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
1025 Assert(!pFileEvent.isNull());
1026
1027 HRESULT hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1028 ComAssertComRC(hr);
1029 }
1030
1031 return vrc;
1032}
1033
1034int GuestFile::waitForWrite(GuestWaitEvent *pEvent,
1035 uint32_t uTimeoutMS, uint32_t *pcbWritten)
1036{
1037 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1038
1039 VBoxEventType_T evtType;
1040 ComPtr<IEvent> pIEvent;
1041 int vrc = waitForEvent(pEvent, uTimeoutMS,
1042 &evtType, pIEvent.asOutParam());
1043 if (RT_SUCCESS(vrc))
1044 {
1045 if (evtType == VBoxEventType_OnGuestFileWrite)
1046 {
1047 if (pcbWritten)
1048 {
1049 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1050 Assert(!pFileEvent.isNull());
1051
1052 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1053 ComAssertComRC(hr);
1054 }
1055 }
1056 else
1057 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1058 }
1059
1060 return vrc;
1061}
1062
1063int GuestFile::writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData,
1064 uint32_t *pcbWritten)
1065{
1066 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1067 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1068
1069 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1070 uTimeoutMS, pvData, cbData));
1071 int vrc;
1072
1073 GuestWaitEvent *pEvent = NULL;
1074 std::list < VBoxEventType_T > eventTypes;
1075 try
1076 {
1077 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1078 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1079
1080 vrc = registerEvent(eventTypes, &pEvent);
1081 }
1082 catch (std::bad_alloc)
1083 {
1084 vrc = VERR_NO_MEMORY;
1085 }
1086
1087 if (RT_FAILURE(vrc))
1088 return vrc;
1089
1090 /* Prepare HGCM call. */
1091 VBOXHGCMSVCPARM paParms[8];
1092 int i = 0;
1093 paParms[i++].setUInt32(pEvent->ContextID());
1094 paParms[i++].setUInt32(mData.mID /* File handle */);
1095 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
1096 paParms[i++].setPointer(pvData, cbData);
1097
1098 uint32_t cbWritten;
1099 vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
1100 if (RT_SUCCESS(vrc))
1101 vrc = waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1102
1103 if (RT_SUCCESS(vrc))
1104 {
1105 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1106
1107 if (cbWritten)
1108 *pcbWritten = cbWritten;
1109 }
1110
1111 unregisterEvent(pEvent);
1112
1113 LogFlowFuncLeaveRC(vrc);
1114 return vrc;
1115}
1116
1117int GuestFile::writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
1118 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1119{
1120 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1121 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1122
1123 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1124 uOffset, uTimeoutMS, pvData, cbData));
1125 int vrc;
1126
1127 GuestWaitEvent *pEvent = NULL;
1128 std::list < VBoxEventType_T > eventTypes;
1129 try
1130 {
1131 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1132 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1133
1134 vrc = registerEvent(eventTypes, &pEvent);
1135 }
1136 catch (std::bad_alloc)
1137 {
1138 vrc = VERR_NO_MEMORY;
1139 }
1140
1141 if (RT_FAILURE(vrc))
1142 return vrc;
1143
1144 /* Prepare HGCM call. */
1145 VBOXHGCMSVCPARM paParms[8];
1146 int i = 0;
1147 paParms[i++].setUInt32(pEvent->ContextID());
1148 paParms[i++].setUInt32(mData.mID /* File handle */);
1149 paParms[i++].setUInt64(uOffset /* Offset where to starting writing */);
1150 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
1151 paParms[i++].setPointer(pvData, cbData);
1152
1153 uint32_t cbWritten;
1154 vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
1155 if (RT_SUCCESS(vrc))
1156 vrc = waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1157
1158 if (RT_SUCCESS(vrc))
1159 {
1160 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1161
1162 if (cbWritten)
1163 *pcbWritten = cbWritten;
1164 }
1165
1166 unregisterEvent(pEvent);
1167
1168 LogFlowFuncLeaveRC(vrc);
1169 return vrc;
1170}
1171
1172// implementation of public methods
1173/////////////////////////////////////////////////////////////////////////////
1174
1175STDMETHODIMP GuestFile::Close(void)
1176{
1177#ifndef VBOX_WITH_GUEST_CONTROL
1178 ReturnComNotImplemented();
1179#else
1180 LogFlowThisFuncEnter();
1181
1182 AutoCaller autoCaller(this);
1183 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1184
1185 /* Close file on guest. */
1186 int guestRc;
1187 int rc = closeFile(&guestRc);
1188 /* On failure don't return here, instead do all the cleanup
1189 * work first and then return an error. */
1190
1191 AssertPtr(mSession);
1192 int rc2 = mSession->fileRemoveFromList(this);
1193 if (RT_SUCCESS(rc))
1194 rc = rc2;
1195
1196 /*
1197 * Release autocaller before calling uninit.
1198 */
1199 autoCaller.release();
1200
1201 uninit();
1202
1203 LogFlowFuncLeaveRC(rc);
1204 if (RT_FAILURE(rc))
1205 {
1206 if (rc == VERR_GSTCTL_GUEST_ERROR)
1207 return GuestFile::setErrorExternal(this, guestRc);
1208
1209 return setError(VBOX_E_IPRT_ERROR,
1210 tr("Closing guest file failed with %Rrc\n"), rc);
1211 }
1212
1213 return S_OK;
1214#endif /* VBOX_WITH_GUEST_CONTROL */
1215}
1216
1217STDMETHODIMP GuestFile::QueryInfo(IFsObjInfo **aInfo)
1218{
1219#ifndef VBOX_WITH_GUEST_CONTROL
1220 ReturnComNotImplemented();
1221#else
1222 AutoCaller autoCaller(this);
1223 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1224
1225 ReturnComNotImplemented();
1226#endif /* VBOX_WITH_GUEST_CONTROL */
1227}
1228
1229STDMETHODIMP GuestFile::Read(ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
1230{
1231#ifndef VBOX_WITH_GUEST_CONTROL
1232 ReturnComNotImplemented();
1233#else
1234 if (aToRead == 0)
1235 return setError(E_INVALIDARG, tr("The size to read is zero"));
1236 CheckComArgOutSafeArrayPointerValid(aData);
1237
1238 AutoCaller autoCaller(this);
1239 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1240
1241 com::SafeArray<BYTE> data((size_t)aToRead);
1242 Assert(data.size() >= aToRead);
1243
1244 HRESULT hr = S_OK;
1245
1246 uint32_t cbRead;
1247 int vrc = readData(aToRead, aTimeoutMS,
1248 data.raw(), aToRead, &cbRead);
1249 if (RT_SUCCESS(vrc))
1250 {
1251 if (data.size() != cbRead)
1252 data.resize(cbRead);
1253 data.detachTo(ComSafeArrayOutArg(aData));
1254 }
1255 else
1256 {
1257 switch (vrc)
1258 {
1259 default:
1260 hr = setError(VBOX_E_IPRT_ERROR,
1261 tr("Reading from file \"%s\" failed: %Rrc"),
1262 mData.mOpenInfo.mFileName.c_str(), vrc);
1263 break;
1264 }
1265 }
1266
1267 LogFlowFuncLeaveRC(vrc);
1268 return hr;
1269#endif /* VBOX_WITH_GUEST_CONTROL */
1270}
1271
1272STDMETHODIMP GuestFile::ReadAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
1273{
1274#ifndef VBOX_WITH_GUEST_CONTROL
1275 ReturnComNotImplemented();
1276#else
1277 if (aToRead == 0)
1278 return setError(E_INVALIDARG, tr("The size to read is zero"));
1279 CheckComArgOutSafeArrayPointerValid(aData);
1280
1281 AutoCaller autoCaller(this);
1282 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1283
1284 com::SafeArray<BYTE> data((size_t)aToRead);
1285 Assert(data.size() >= aToRead);
1286
1287 HRESULT hr = S_OK;
1288
1289 size_t cbRead;
1290 int vrc = readDataAt(aOffset, aToRead, aTimeoutMS,
1291 data.raw(), aToRead, &cbRead);
1292 if (RT_SUCCESS(vrc))
1293 {
1294 if (data.size() != cbRead)
1295 data.resize(cbRead);
1296 data.detachTo(ComSafeArrayOutArg(aData));
1297 }
1298 else
1299 {
1300 switch (vrc)
1301 {
1302 default:
1303 hr = setError(VBOX_E_IPRT_ERROR,
1304 tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1305 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1306 break;
1307 }
1308 }
1309
1310 LogFlowFuncLeaveRC(vrc);
1311 return hr;
1312#endif /* VBOX_WITH_GUEST_CONTROL */
1313}
1314
1315STDMETHODIMP GuestFile::Seek(LONG64 aOffset, FileSeekType_T aType)
1316{
1317#ifndef VBOX_WITH_GUEST_CONTROL
1318 ReturnComNotImplemented();
1319#else
1320 LogFlowThisFuncEnter();
1321
1322 AutoCaller autoCaller(this);
1323 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1324
1325 HRESULT hr = S_OK;
1326
1327 GUEST_FILE_SEEKTYPE eSeekType;
1328 switch (aType)
1329 {
1330 case FileSeekType_Set:
1331 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1332 break;
1333
1334 case FileSeekType_Current:
1335 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1336 break;
1337
1338 default:
1339 return setError(E_INVALIDARG, tr("Invalid seek type specified"));
1340 break;
1341 }
1342
1343 int vrc = seekAt(aOffset, eSeekType,
1344 30 * 1000 /* 30s timeout */, NULL /* puOffset */);
1345 if (RT_FAILURE(vrc))
1346 {
1347 switch (vrc)
1348 {
1349 default:
1350 hr = setError(VBOX_E_IPRT_ERROR,
1351 tr("Seeking file \"%s\" (to offset %RU64) failed: %Rrc"),
1352 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1353 break;
1354 }
1355 }
1356
1357 LogFlowFuncLeaveRC(vrc);
1358 return hr;
1359#endif /* VBOX_WITH_GUEST_CONTROL */
1360}
1361
1362STDMETHODIMP GuestFile::SetACL(IN_BSTR aACL)
1363{
1364#ifndef VBOX_WITH_GUEST_CONTROL
1365 ReturnComNotImplemented();
1366#else
1367 AutoCaller autoCaller(this);
1368 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1369
1370 ReturnComNotImplemented();
1371#endif /* VBOX_WITH_GUEST_CONTROL */
1372}
1373
1374STDMETHODIMP GuestFile::Write(ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1375{
1376#ifndef VBOX_WITH_GUEST_CONTROL
1377 ReturnComNotImplemented();
1378#else
1379 LogFlowThisFuncEnter();
1380
1381 CheckComArgOutPointerValid(aWritten);
1382
1383 AutoCaller autoCaller(this);
1384 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1385
1386 HRESULT hr = S_OK;
1387
1388 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
1389 int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(),
1390 (uint32_t*)aWritten);
1391 if (RT_FAILURE(vrc))
1392 {
1393 switch (vrc)
1394 {
1395 default:
1396 hr = setError(VBOX_E_IPRT_ERROR,
1397 tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
1398 data.size(), mData.mOpenInfo.mFileName.c_str(), vrc);
1399 break;
1400 }
1401 }
1402
1403 LogFlowFuncLeaveRC(vrc);
1404 return hr;
1405#endif /* VBOX_WITH_GUEST_CONTROL */
1406}
1407
1408STDMETHODIMP GuestFile::WriteAt(LONG64 aOffset, ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1409{
1410#ifndef VBOX_WITH_GUEST_CONTROL
1411 ReturnComNotImplemented();
1412#else
1413 LogFlowThisFuncEnter();
1414
1415 CheckComArgOutPointerValid(aWritten);
1416
1417 AutoCaller autoCaller(this);
1418 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1419
1420 HRESULT hr = S_OK;
1421
1422 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
1423 int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(),
1424 (uint32_t*)aWritten);
1425 if (RT_FAILURE(vrc))
1426 {
1427 switch (vrc)
1428 {
1429 default:
1430 hr = setError(VBOX_E_IPRT_ERROR,
1431 tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
1432 data.size(), mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1433 break;
1434 }
1435 }
1436
1437 LogFlowFuncLeaveRC(vrc);
1438 return hr;
1439#endif /* VBOX_WITH_GUEST_CONTROL */
1440}
1441
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