VirtualBox

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

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

GuestCtrl: More event handling code for IGuestFile and IGuestSession.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.0 KB
Line 
1
2/* $Id: GuestFileImpl.cpp 45434 2013-04-09 13:51:55Z 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.215389.xyz. 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 TRUE /* 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 else
850 vrc = VERR_COM_UNEXPECTED;
851
852 } while (!fSignalled);
853
854 if ( RT_SUCCESS(vrc)
855 && !fSignalled)
856 {
857 vrc = VERR_TIMEOUT;
858 }
859
860 hr = mEventSource->UnregisterListener(pListener);
861 ComAssertComRC(hr);
862 }
863 else
864 vrc = VERR_COM_UNEXPECTED;
865
866 LogFlowFuncLeaveRC(vrc);
867 return vrc;
868}
869
870int GuestFile::waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset)
871{
872 VBoxEventType_T evtType;
873 ComPtr<IEvent> pEvent;
874 com::SafeArray<VBoxEventType_T> eventTypes;
875 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
876 int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
877 &evtType, pEvent.asOutParam());
878 if ( vrc == VINF_SUCCESS /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
879 && puOffset)
880 {
881 Assert(evtType == VBoxEventType_OnGuestFileOffsetChanged);
882 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pEvent;
883 Assert(!pFileEvent.isNull());
884
885 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
886 ComAssertComRC(hr);
887 }
888
889 return vrc;
890}
891
892int GuestFile::waitForRead(uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead)
893{
894 VBoxEventType_T evtType;
895 ComPtr<IEvent> pEvent;
896 com::SafeArray<VBoxEventType_T> eventTypes;
897 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
898 int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
899 &evtType, pEvent.asOutParam());
900 if (vrc == VINF_SUCCESS) /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
901 {
902 Assert(evtType == VBoxEventType_OnGuestFileRead);
903 ComPtr<IGuestFileReadEvent> pFileEvent = pEvent;
904 Assert(!pFileEvent.isNull());
905
906 HRESULT hr;
907 if (pvData)
908 {
909 com::SafeArray <BYTE> data;
910 hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
911 ComAssertComRC(hr);
912 size_t cbRead = data.size();
913 if ( cbRead
914 && cbRead <= cbData)
915 {
916 memcpy(pvData, data.raw(), data.size());
917 }
918 else
919 vrc = VERR_BUFFER_OVERFLOW;
920 }
921 if (pcbRead)
922 {
923 hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
924 ComAssertComRC(hr);
925 }
926 }
927
928 return vrc;
929}
930
931int GuestFile::waitForStatusChange(uint32_t uTimeoutMS, FileStatus_T *pFileStatus)
932{
933 VBoxEventType_T evtType;
934 ComPtr<IEvent> pEvent;
935 com::SafeArray<VBoxEventType_T> eventTypes;
936 /* No own event types needed. VBoxEventType_OnGuestFileStateChanged already will
937 * part of the array when processed in waitForEvents. */
938 int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
939 &evtType, pEvent.asOutParam());
940 if ( vrc == VINF_SUCCESS /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
941 && pFileStatus)
942 {
943 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
944 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pEvent;
945 Assert(!pFileEvent.isNull());
946
947 HRESULT hr = pFileEvent->COMGETTER(Status)(pFileStatus);
948 ComAssertComRC(hr);
949 }
950
951 return vrc;
952}
953
954int GuestFile::waitForWrite(uint32_t uTimeoutMS, uint32_t *pcbWritten)
955{
956 VBoxEventType_T evtType;
957 ComPtr<IEvent> pEvent;
958 com::SafeArray<VBoxEventType_T> eventTypes;
959 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
960 int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
961 &evtType, pEvent.asOutParam());
962 if ( vrc == VINF_SUCCESS /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
963 && pcbWritten)
964 {
965 Assert(evtType == VBoxEventType_OnGuestFileWrite);
966 ComPtr<IGuestFileWriteEvent> pFileEvent = pEvent;
967 Assert(!pFileEvent.isNull());
968
969 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
970 ComAssertComRC(hr);
971 }
972
973 return vrc;
974}
975
976int GuestFile::writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData,
977 uint32_t *pcbWritten)
978{
979 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
980 AssertReturn(cbData, VERR_INVALID_PARAMETER);
981
982 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
983 uTimeoutMS, pvData, cbData));
984
985 uint32_t uContextID;
986 int vrc = generateContextID(mSession->getId(), mObjectID,
987 &uContextID);
988 if (RT_SUCCESS(vrc))
989 {
990 /* Prepare HGCM call. */
991 VBOXHGCMSVCPARM paParms[8];
992 int i = 0;
993 paParms[i++].setUInt32(uContextID);
994 paParms[i++].setUInt32(mData.mID /* File handle */);
995 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
996 paParms[i++].setPointer(pvData, cbData);
997
998 uint32_t cbWritten;
999 vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
1000 if (RT_SUCCESS(vrc))
1001 vrc = waitForWrite(uTimeoutMS, &cbWritten);
1002
1003 if (RT_SUCCESS(vrc))
1004 {
1005 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1006
1007 if (cbWritten)
1008 *pcbWritten = cbWritten;
1009 }
1010 }
1011
1012 LogFlowFuncLeaveRC(vrc);
1013 return vrc;
1014}
1015
1016int GuestFile::writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
1017 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1018{
1019 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1020 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1021
1022 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1023 uOffset, uTimeoutMS, pvData, cbData));
1024
1025 uint32_t uContextID;
1026 int vrc = generateContextID(mSession->getId(), mObjectID,
1027 &uContextID);
1028 if (RT_SUCCESS(vrc))
1029 {
1030 /* Prepare HGCM call. */
1031 VBOXHGCMSVCPARM paParms[8];
1032 int i = 0;
1033 paParms[i++].setUInt32(mData.mID /* File handle */);
1034 paParms[i++].setUInt64(uOffset /* Offset where to starting writing */);
1035 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
1036 paParms[i++].setPointer(pvData, cbData);
1037
1038 uint32_t cbWritten;
1039 vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
1040 if (RT_SUCCESS(vrc))
1041 vrc = waitForWrite(uTimeoutMS, &cbWritten);
1042
1043 if (RT_SUCCESS(vrc))
1044 {
1045 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1046
1047 if (cbWritten)
1048 *pcbWritten = cbWritten;
1049 }
1050 }
1051
1052 LogFlowFuncLeaveRC(vrc);
1053 return vrc;
1054}
1055
1056// implementation of public methods
1057/////////////////////////////////////////////////////////////////////////////
1058
1059STDMETHODIMP GuestFile::Close(void)
1060{
1061#ifndef VBOX_WITH_GUEST_CONTROL
1062 ReturnComNotImplemented();
1063#else
1064 LogFlowThisFuncEnter();
1065
1066 AutoCaller autoCaller(this);
1067 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1068
1069 /* Close file on guest. */
1070 int guestRc;
1071 int rc = closeFile(&guestRc);
1072 /* On failure don't return here, instead do all the cleanup
1073 * work first and then return an error. */
1074
1075 AssertPtr(mSession);
1076 int rc2 = mSession->fileRemoveFromList(this);
1077 if (RT_SUCCESS(rc))
1078 rc = rc2;
1079
1080 /*
1081 * Release autocaller before calling uninit.
1082 */
1083 autoCaller.release();
1084
1085 uninit();
1086
1087 LogFlowFuncLeaveRC(rc);
1088 if (RT_FAILURE(rc))
1089 {
1090 if (rc == VERR_GSTCTL_GUEST_ERROR)
1091 return GuestFile::setErrorExternal(this, guestRc);
1092
1093 return setError(VBOX_E_IPRT_ERROR,
1094 tr("Closing guest file failed with %Rrc\n"), rc);
1095 }
1096
1097 return S_OK;
1098#endif /* VBOX_WITH_GUEST_CONTROL */
1099}
1100
1101STDMETHODIMP GuestFile::QueryInfo(IFsObjInfo **aInfo)
1102{
1103#ifndef VBOX_WITH_GUEST_CONTROL
1104 ReturnComNotImplemented();
1105#else
1106 AutoCaller autoCaller(this);
1107 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1108
1109 ReturnComNotImplemented();
1110#endif /* VBOX_WITH_GUEST_CONTROL */
1111}
1112
1113STDMETHODIMP GuestFile::Read(ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
1114{
1115#ifndef VBOX_WITH_GUEST_CONTROL
1116 ReturnComNotImplemented();
1117#else
1118 if (aToRead == 0)
1119 return setError(E_INVALIDARG, tr("The size to read is zero"));
1120 CheckComArgOutSafeArrayPointerValid(aData);
1121
1122 AutoCaller autoCaller(this);
1123 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1124
1125 com::SafeArray<BYTE> data((size_t)aToRead);
1126 Assert(data.size() >= aToRead);
1127
1128 HRESULT hr = S_OK;
1129
1130 uint32_t cbRead;
1131 int vrc = readData(aToRead, aTimeoutMS,
1132 data.raw(), aToRead, &cbRead);
1133 if (RT_SUCCESS(vrc))
1134 {
1135 if (data.size() != cbRead)
1136 data.resize(cbRead);
1137 data.detachTo(ComSafeArrayOutArg(aData));
1138 }
1139 else
1140 {
1141 switch (vrc)
1142 {
1143 default:
1144 hr = setError(VBOX_E_IPRT_ERROR,
1145 tr("Reading from file \"%s\" failed: %Rrc"),
1146 mData.mOpenInfo.mFileName.c_str(), vrc);
1147 break;
1148 }
1149 }
1150
1151 LogFlowFuncLeaveRC(vrc);
1152 return hr;
1153#endif /* VBOX_WITH_GUEST_CONTROL */
1154}
1155
1156STDMETHODIMP GuestFile::ReadAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
1157{
1158#ifndef VBOX_WITH_GUEST_CONTROL
1159 ReturnComNotImplemented();
1160#else
1161 if (aToRead == 0)
1162 return setError(E_INVALIDARG, tr("The size to read is zero"));
1163 CheckComArgOutSafeArrayPointerValid(aData);
1164
1165 AutoCaller autoCaller(this);
1166 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1167
1168 com::SafeArray<BYTE> data((size_t)aToRead);
1169 Assert(data.size() >= aToRead);
1170
1171 HRESULT hr = S_OK;
1172
1173 size_t cbRead;
1174 int vrc = readDataAt(aOffset, aToRead, aTimeoutMS,
1175 data.raw(), aToRead, &cbRead);
1176 if (RT_SUCCESS(vrc))
1177 {
1178 if (data.size() != cbRead)
1179 data.resize(cbRead);
1180 data.detachTo(ComSafeArrayOutArg(aData));
1181 }
1182 else
1183 {
1184 switch (vrc)
1185 {
1186 default:
1187 hr = setError(VBOX_E_IPRT_ERROR,
1188 tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1189 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1190 break;
1191 }
1192 }
1193
1194 LogFlowFuncLeaveRC(vrc);
1195 return hr;
1196#endif /* VBOX_WITH_GUEST_CONTROL */
1197}
1198
1199STDMETHODIMP GuestFile::Seek(LONG64 aOffset, FileSeekType_T aType)
1200{
1201#ifndef VBOX_WITH_GUEST_CONTROL
1202 ReturnComNotImplemented();
1203#else
1204 LogFlowThisFuncEnter();
1205
1206 AutoCaller autoCaller(this);
1207 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1208
1209 HRESULT hr = S_OK;
1210
1211 GUEST_FILE_SEEKTYPE eSeekType;
1212 switch (aType)
1213 {
1214 case FileSeekType_Set:
1215 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1216 break;
1217
1218 case FileSeekType_Current:
1219 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1220 break;
1221
1222 default:
1223 return setError(E_INVALIDARG, tr("Invalid seek type specified"));
1224 break;
1225 }
1226
1227 int vrc = seekAt(aOffset, eSeekType,
1228 30 * 1000 /* 30s timeout */, NULL /* puOffset */);
1229 if (RT_FAILURE(vrc))
1230 {
1231 switch (vrc)
1232 {
1233 default:
1234 hr = setError(VBOX_E_IPRT_ERROR,
1235 tr("Seeking file \"%s\" (to offset %RU64) failed: %Rrc"),
1236 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1237 break;
1238 }
1239 }
1240
1241 LogFlowFuncLeaveRC(vrc);
1242 return hr;
1243#endif /* VBOX_WITH_GUEST_CONTROL */
1244}
1245
1246STDMETHODIMP GuestFile::SetACL(IN_BSTR aACL)
1247{
1248#ifndef VBOX_WITH_GUEST_CONTROL
1249 ReturnComNotImplemented();
1250#else
1251 AutoCaller autoCaller(this);
1252 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1253
1254 ReturnComNotImplemented();
1255#endif /* VBOX_WITH_GUEST_CONTROL */
1256}
1257
1258STDMETHODIMP GuestFile::Write(ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1259{
1260#ifndef VBOX_WITH_GUEST_CONTROL
1261 ReturnComNotImplemented();
1262#else
1263 LogFlowThisFuncEnter();
1264
1265 CheckComArgOutPointerValid(aWritten);
1266
1267 AutoCaller autoCaller(this);
1268 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1269
1270 HRESULT hr = S_OK;
1271
1272 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
1273 int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(),
1274 (uint32_t*)aWritten);
1275 if (RT_FAILURE(vrc))
1276 {
1277 switch (vrc)
1278 {
1279 default:
1280 hr = setError(VBOX_E_IPRT_ERROR,
1281 tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
1282 data.size(), mData.mOpenInfo.mFileName.c_str(), vrc);
1283 break;
1284 }
1285 }
1286
1287 LogFlowFuncLeaveRC(vrc);
1288 return hr;
1289#endif /* VBOX_WITH_GUEST_CONTROL */
1290}
1291
1292STDMETHODIMP GuestFile::WriteAt(LONG64 aOffset, ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1293{
1294#ifndef VBOX_WITH_GUEST_CONTROL
1295 ReturnComNotImplemented();
1296#else
1297 LogFlowThisFuncEnter();
1298
1299 CheckComArgOutPointerValid(aWritten);
1300
1301 AutoCaller autoCaller(this);
1302 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1303
1304 HRESULT hr = S_OK;
1305
1306 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
1307 int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(),
1308 (uint32_t*)aWritten);
1309 if (RT_FAILURE(vrc))
1310 {
1311 switch (vrc)
1312 {
1313 default:
1314 hr = setError(VBOX_E_IPRT_ERROR,
1315 tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
1316 data.size(), mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1317 break;
1318 }
1319 }
1320
1321 LogFlowFuncLeaveRC(vrc);
1322 return hr;
1323#endif /* VBOX_WITH_GUEST_CONTROL */
1324}
1325
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette