VirtualBox

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

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

Guest Control: Adjustments for supporting < 4.3 Guest Additions in conjunction with the new guest session, extended testcase (now passing using latest 4.2 Guest Additions with latest trunk).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use