VirtualBox

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

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

GuestCtrl: Added abstract IGuestProcessIOEvent event, removed duplicate code, making the testdriver execution tests pass.

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