VirtualBox

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

Last change on this file since 55747 was 55668, checked in by vboxsync, 10 years ago

Modified IGuestSession::fileOpenEx: removed the 'offset' parameter and added generic flags parameter so we can easily add features later when we need them (see RTFILE_O_XXX for inspiration). Changed FileSeekOrigin_Set to FileSeekOrigin_Begin.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.9 KB
Line 
1/* $Id: GuestFileImpl.cpp 55668 2015-05-05 15:45:27Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Guest file handling.
4 */
5
6/*
7 * Copyright (C) 2012-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#ifndef VBOX_WITH_GUEST_CONTROL
23# error "VBOX_WITH_GUEST_CONTROL must defined in this file"
24#endif
25#include "GuestFileImpl.h"
26#include "GuestSessionImpl.h"
27#include "GuestCtrlImplPrivate.h"
28#include "ConsoleImpl.h"
29#include "VirtualBoxErrorInfoImpl.h"
30
31#include "Global.h"
32#include "AutoCaller.h"
33#include "VBoxEvents.h"
34
35#include <iprt/cpp/utils.h> /* For unconst(). */
36#include <iprt/file.h>
37
38#include <VBox/com/array.h>
39#include <VBox/com/listeners.h>
40
41#ifdef LOG_GROUP
42 #undef LOG_GROUP
43#endif
44#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
45#include <VBox/log.h>
46
47
48/**
49 * Internal listener class to serve events in an
50 * active manner, e.g. without polling delays.
51 */
52class GuestFileListener
53{
54public:
55
56 GuestFileListener(void)
57 {
58 }
59
60 HRESULT init(GuestFile *pFile)
61 {
62 AssertPtrReturn(pFile, E_POINTER);
63 mFile = pFile;
64 return S_OK;
65 }
66
67 void uninit(void)
68 {
69 mFile = NULL;
70 }
71
72 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
73 {
74 switch (aType)
75 {
76 case VBoxEventType_OnGuestFileStateChanged:
77 case VBoxEventType_OnGuestFileOffsetChanged:
78 case VBoxEventType_OnGuestFileRead:
79 case VBoxEventType_OnGuestFileWrite:
80 {
81 AssertPtrReturn(mFile, E_POINTER);
82 int rc2 = mFile->signalWaitEvent(aType, aEvent);
83#ifdef DEBUG_andy
84 LogFlowFunc(("Signalling events of type=%RU32, file=%p resulted in rc=%Rrc\n",
85 aType, mFile, rc2));
86#endif
87 break;
88 }
89
90 default:
91 AssertMsgFailed(("Unhandled event %RU32\n", aType));
92 break;
93 }
94
95 return S_OK;
96 }
97
98private:
99
100 GuestFile *mFile;
101};
102typedef ListenerImpl<GuestFileListener, GuestFile*> GuestFileListenerImpl;
103
104VBOX_LISTENER_DECLARE(GuestFileListenerImpl)
105
106// constructor / destructor
107/////////////////////////////////////////////////////////////////////////////
108
109DEFINE_EMPTY_CTOR_DTOR(GuestFile)
110
111HRESULT GuestFile::FinalConstruct(void)
112{
113 LogFlowThisFuncEnter();
114 return BaseFinalConstruct();
115}
116
117void GuestFile::FinalRelease(void)
118{
119 LogFlowThisFuncEnter();
120 uninit();
121 BaseFinalRelease();
122 LogFlowThisFuncLeave();
123}
124
125// public initializer/uninitializer for internal purposes only
126/////////////////////////////////////////////////////////////////////////////
127
128/**
129 * Initializes a file object but does *not* open the file on the guest
130 * yet. This is done in the dedidcated openFile call.
131 *
132 * @return IPRT status code.
133 * @param pConsole Pointer to console object.
134 * @param pSession Pointer to session object.
135 * @param uFileID Host-based file ID (part of the context ID).
136 * @param openInfo File opening information.
137 */
138int GuestFile::init(Console *pConsole, GuestSession *pSession,
139 ULONG uFileID, const GuestFileOpenInfo &openInfo)
140{
141 LogFlowThisFunc(("pConsole=%p, pSession=%p, uFileID=%RU32, strPath=%s\n",
142 pConsole, pSession, uFileID, openInfo.mFileName.c_str()));
143
144 AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
145 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
146
147 /* Enclose the state transition NotReady->InInit->Ready. */
148 AutoInitSpan autoInitSpan(this);
149 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
150
151 int vrc = bindToSession(pConsole, pSession, uFileID /* Object ID */);
152 if (RT_SUCCESS(vrc))
153 {
154 mSession = pSession;
155
156 mData.mID = uFileID;
157 mData.mInitialSize = 0;
158 mData.mStatus = FileStatus_Undefined;
159 mData.mOpenInfo = openInfo;
160
161 unconst(mEventSource).createObject();
162 HRESULT hr = mEventSource->init();
163 if (FAILED(hr))
164 vrc = VERR_COM_UNEXPECTED;
165 }
166
167 if (RT_SUCCESS(vrc))
168 {
169 try
170 {
171 GuestFileListener *pListener = new GuestFileListener();
172 ComObjPtr<GuestFileListenerImpl> thisListener;
173 HRESULT hr = thisListener.createObject();
174 if (SUCCEEDED(hr))
175 hr = thisListener->init(pListener, this);
176
177 if (SUCCEEDED(hr))
178 {
179 com::SafeArray <VBoxEventType_T> eventTypes;
180 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
181 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
182 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
183 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
184 hr = mEventSource->RegisterListener(thisListener,
185 ComSafeArrayAsInParam(eventTypes),
186 TRUE /* Active listener */);
187 if (SUCCEEDED(hr))
188 {
189 vrc = baseInit();
190 if (RT_SUCCESS(vrc))
191 {
192 mLocalListener = thisListener;
193 }
194 }
195 else
196 vrc = VERR_COM_UNEXPECTED;
197 }
198 else
199 vrc = VERR_COM_UNEXPECTED;
200 }
201 catch(std::bad_alloc &)
202 {
203 vrc = VERR_NO_MEMORY;
204 }
205 }
206
207 if (RT_SUCCESS(vrc))
208 {
209 /* Confirm a successful initialization when it's the case. */
210 autoInitSpan.setSucceeded();
211 }
212 else
213 autoInitSpan.setFailed();
214
215 LogFlowFuncLeaveRC(vrc);
216 return vrc;
217}
218
219/**
220 * Uninitializes the instance.
221 * Called from FinalRelease().
222 */
223void GuestFile::uninit(void)
224{
225 /* Enclose the state transition Ready->InUninit->NotReady. */
226 AutoUninitSpan autoUninitSpan(this);
227 if (autoUninitSpan.uninitDone())
228 return;
229
230 LogFlowThisFuncEnter();
231
232 baseUninit();
233 LogFlowThisFuncLeave();
234}
235
236// implementation of public getters/setters for attributes
237/////////////////////////////////////////////////////////////////////////////
238
239HRESULT GuestFile::getCreationMode(ULONG *aCreationMode)
240{
241 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
242
243 *aCreationMode = mData.mOpenInfo.mCreationMode;
244
245 return S_OK;
246}
247
248HRESULT GuestFile::getOpenAction(FileOpenAction_T *aOpenAction)
249{
250 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
251
252 *aOpenAction = mData.mOpenInfo.mOpenAction;
253
254 return S_OK;
255}
256
257HRESULT GuestFile::getEventSource(ComPtr<IEventSource> &aEventSource)
258{
259 /* No need to lock - lifetime constant. */
260 mEventSource.queryInterfaceTo(aEventSource.asOutParam());
261
262 return S_OK;
263}
264
265HRESULT GuestFile::getFileName(com::Utf8Str &aFileName)
266{
267 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
268
269 aFileName = mData.mOpenInfo.mFileName;
270
271 return S_OK;
272}
273
274HRESULT GuestFile::getId(ULONG *aId)
275{
276 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
277
278 *aId = mData.mID;
279
280 return S_OK;
281}
282
283HRESULT GuestFile::getInitialSize(LONG64 *aInitialSize)
284{
285 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
286
287 *aInitialSize = mData.mInitialSize;
288
289 return S_OK;
290}
291
292HRESULT GuestFile::getOffset(LONG64 *aOffset)
293{
294 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
295
296 *aOffset = mData.mOffCurrent;
297
298 return S_OK;
299}
300
301HRESULT GuestFile::getAccessMode(FileAccessMode_T *aAccessMode)
302{
303 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
304
305 *aAccessMode = mData.mOpenInfo.mAccessMode;
306
307 return S_OK;
308}
309
310HRESULT GuestFile::getStatus(FileStatus_T *aStatus)
311{
312 LogFlowThisFuncEnter();
313
314 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
315
316 *aStatus = mData.mStatus;
317
318 return S_OK;
319}
320
321// private methods
322/////////////////////////////////////////////////////////////////////////////
323
324int GuestFile::i_callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
325{
326 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
327 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
328
329 LogFlowThisFunc(("strName=%s, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
330 mData.mOpenInfo.mFileName.c_str(), pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
331
332 int vrc;
333 switch (pCbCtx->uFunction)
334 {
335 case GUEST_DISCONNECTED:
336 vrc = i_onGuestDisconnected(pCbCtx, pSvcCb);
337 break;
338
339 case GUEST_FILE_NOTIFY:
340 vrc = i_onFileNotify(pCbCtx, pSvcCb);
341 break;
342
343 default:
344 /* Silently ignore not implemented functions. */
345 vrc = VERR_NOT_SUPPORTED;
346 break;
347 }
348
349#ifdef DEBUG
350 LogFlowFuncLeaveRC(vrc);
351#endif
352 return vrc;
353}
354
355int GuestFile::i_closeFile(int *pGuestRc)
356{
357 LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFileName.c_str()));
358
359 int vrc;
360
361 GuestWaitEvent *pEvent = NULL;
362 GuestEventTypes eventTypes;
363 try
364 {
365 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
366
367 vrc = registerWaitEvent(eventTypes, &pEvent);
368 }
369 catch (std::bad_alloc)
370 {
371 vrc = VERR_NO_MEMORY;
372 }
373
374 if (RT_FAILURE(vrc))
375 return vrc;
376
377 /* Prepare HGCM call. */
378 VBOXHGCMSVCPARM paParms[4];
379 int i = 0;
380 paParms[i++].setUInt32(pEvent->ContextID());
381 paParms[i++].setUInt32(mData.mID /* Guest file ID */);
382
383 vrc = sendCommand(HOST_FILE_CLOSE, i, paParms);
384 if (RT_SUCCESS(vrc))
385 vrc = i_waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */,
386 NULL /* FileStatus */, pGuestRc);
387 unregisterWaitEvent(pEvent);
388
389 LogFlowFuncLeaveRC(vrc);
390 return vrc;
391}
392
393/* static */
394Utf8Str GuestFile::i_guestErrorToString(int guestRc)
395{
396 Utf8Str strError;
397
398 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
399 switch (guestRc)
400 {
401 case VERR_ALREADY_EXISTS:
402 strError += Utf8StrFmt(tr("File already exists"));
403 break;
404
405 case VERR_FILE_NOT_FOUND:
406 strError += Utf8StrFmt(tr("File not found"));
407 break;
408
409 case VERR_NET_HOST_NOT_FOUND:
410 strError += Utf8StrFmt(tr("Host name not found"));
411 break;
412
413 case VERR_SHARING_VIOLATION:
414 strError += Utf8StrFmt(tr("Sharing violation"));
415 break;
416
417 default:
418 strError += Utf8StrFmt("%Rrc", guestRc);
419 break;
420 }
421
422 return strError;
423}
424
425int GuestFile::i_onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
426{
427 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
428 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
429
430 LogFlowThisFuncEnter();
431
432 if (pSvcCbData->mParms < 3)
433 return VERR_INVALID_PARAMETER;
434
435 int vrc = VINF_SUCCESS;
436
437 int idx = 1; /* Current parameter index. */
438 CALLBACKDATA_FILE_NOTIFY dataCb;
439 /* pSvcCb->mpaParms[0] always contains the context ID. */
440 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.uType);
441 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.rc);
442
443 FileStatus_T fileStatus = FileStatus_Undefined;
444 int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */
445
446 LogFlowFunc(("uType=%RU32, guestRc=%Rrc\n",
447 dataCb.uType, guestRc));
448
449 if (RT_FAILURE(guestRc))
450 {
451 int rc2 = i_setFileStatus(FileStatus_Error, guestRc);
452 AssertRC(rc2);
453
454 rc2 = signalWaitEventInternal(pCbCtx,
455 guestRc, NULL /* pPayload */);
456 AssertRC(rc2);
457
458 return VINF_SUCCESS; /* Report to the guest. */
459 }
460
461 switch (dataCb.uType)
462 {
463 case GUEST_FILE_NOTIFYTYPE_ERROR:
464 {
465 int rc2 = i_setFileStatus(FileStatus_Error, guestRc);
466 AssertRC(rc2);
467
468 break;
469 }
470
471 case GUEST_FILE_NOTIFYTYPE_OPEN:
472 {
473 if (pSvcCbData->mParms == 4)
474 {
475 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.open.uHandle);
476
477 AssertMsg(mData.mID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID),
478 ("File ID %RU32 does not match context ID %RU32\n", mData.mID,
479 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));
480
481 /* Set the process status. */
482 int rc2 = i_setFileStatus(FileStatus_Open, guestRc);
483 AssertRC(rc2);
484 }
485 else
486 vrc = VERR_NOT_SUPPORTED;
487
488 break;
489 }
490
491 case GUEST_FILE_NOTIFYTYPE_CLOSE:
492 {
493 int rc2 = i_setFileStatus(FileStatus_Closed, guestRc);
494 AssertRC(rc2);
495
496 break;
497 }
498
499 case GUEST_FILE_NOTIFYTYPE_READ:
500 {
501 if (pSvcCbData->mParms == 4)
502 {
503 pSvcCbData->mpaParms[idx++].getPointer(&dataCb.u.read.pvData,
504 &dataCb.u.read.cbData);
505 uint32_t cbRead = dataCb.u.read.cbData;
506
507 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
508
509 mData.mOffCurrent += cbRead;
510
511 alock.release();
512
513 com::SafeArray<BYTE> data((size_t)cbRead);
514 data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead);
515
516 fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent,
517 cbRead, ComSafeArrayAsInParam(data));
518 }
519 else
520 vrc = VERR_NOT_SUPPORTED;
521 break;
522 }
523
524 case GUEST_FILE_NOTIFYTYPE_WRITE:
525 {
526 if (pSvcCbData->mParms == 4)
527 {
528 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.write.cbWritten);
529
530 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
531
532 mData.mOffCurrent += dataCb.u.write.cbWritten;
533 uint64_t uOffCurrent = mData.mOffCurrent;
534
535 alock.release();
536
537 fireGuestFileWriteEvent(mEventSource, mSession, this, uOffCurrent,
538 dataCb.u.write.cbWritten);
539 }
540 else
541 vrc = VERR_NOT_SUPPORTED;
542 break;
543 }
544
545 case GUEST_FILE_NOTIFYTYPE_SEEK:
546 {
547 if (pSvcCbData->mParms == 4)
548 {
549 pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.seek.uOffActual);
550
551 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
552
553 mData.mOffCurrent = dataCb.u.seek.uOffActual;
554
555 alock.release();
556
557 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
558 dataCb.u.seek.uOffActual, 0 /* Processed */);
559 }
560 else
561 vrc = VERR_NOT_SUPPORTED;
562 break;
563 }
564
565 case GUEST_FILE_NOTIFYTYPE_TELL:
566 {
567 if (pSvcCbData->mParms == 4)
568 {
569 pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.tell.uOffActual);
570
571 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
572
573 mData.mOffCurrent = dataCb.u.tell.uOffActual;
574
575 alock.release();
576
577 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
578 dataCb.u.tell.uOffActual, 0 /* Processed */);
579 }
580 else
581 vrc = VERR_NOT_SUPPORTED;
582 break;
583 }
584
585 default:
586 vrc = VERR_NOT_SUPPORTED;
587 break;
588 }
589
590 if (RT_SUCCESS(vrc))
591 {
592 GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb));
593 int rc2 = signalWaitEventInternal(pCbCtx, guestRc, &payload);
594 AssertRC(rc2);
595 }
596
597 LogFlowThisFunc(("uType=%RU32, guestRc=%Rrc\n",
598 dataCb.uType, dataCb.rc));
599
600 LogFlowFuncLeaveRC(vrc);
601 return vrc;
602}
603
604int GuestFile::i_onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
605{
606 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
607 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
608
609 int vrc = i_setFileStatus(FileStatus_Down, VINF_SUCCESS);
610
611 LogFlowFuncLeaveRC(vrc);
612 return vrc;
613}
614
615/**
616 * Called by IGuestSession right before this file gets removed
617 * from the public file list.
618 */
619int GuestFile::i_onRemove(void)
620{
621 LogFlowThisFuncEnter();
622
623 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
624
625 int vrc = VINF_SUCCESS;
626
627 /*
628 * Note: The event source stuff holds references to this object,
629 * so make sure that this is cleaned up *before* calling uninit().
630 */
631 if (!mEventSource.isNull())
632 {
633 mEventSource->UnregisterListener(mLocalListener);
634
635 mLocalListener.setNull();
636 unconst(mEventSource).setNull();
637 }
638
639 LogFlowFuncLeaveRC(vrc);
640 return vrc;
641}
642
643int GuestFile::i_openFile(uint32_t uTimeoutMS, int *pGuestRc)
644{
645 LogFlowThisFuncEnter();
646
647 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
648
649 LogFlowThisFunc(("strFile=%s, enmAccessMode=%d (%s) enmOpenAction=%d (%s) uCreationMode=%RU32, mfOpenEx=%RU32\n",
650 mData.mOpenInfo.mFileName.c_str(), mData.mOpenInfo.mAccessMode, mData.mOpenInfo.mpszAccessMode,
651 mData.mOpenInfo.mOpenAction, mData.mOpenInfo.mpszOpenAction, mData.mOpenInfo.mCreationMode,
652 mData.mOpenInfo.mfOpenEx));
653 int vrc;
654
655 GuestWaitEvent *pEvent = NULL;
656 GuestEventTypes eventTypes;
657 try
658 {
659 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
660
661 vrc = registerWaitEvent(eventTypes, &pEvent);
662 }
663 catch (std::bad_alloc)
664 {
665 vrc = VERR_NO_MEMORY;
666 }
667
668 if (RT_FAILURE(vrc))
669 return vrc;
670
671 /* Prepare HGCM call. */
672 VBOXHGCMSVCPARM paParms[8];
673 int i = 0;
674 paParms[i++].setUInt32(pEvent->ContextID());
675 paParms[i++].setPointer((void*)mData.mOpenInfo.mFileName.c_str(),
676 (ULONG)mData.mOpenInfo.mFileName.length() + 1);
677 paParms[i++].setString(mData.mOpenInfo.mpszAccessMode);
678 paParms[i++].setString(mData.mOpenInfo.mpszOpenAction);
679 paParms[i++].setString(""); /** @todo sharing mode. */
680 paParms[i++].setUInt32(mData.mOpenInfo.mCreationMode);
681 paParms[i++].setUInt64(0 /* initial offset */);
682 /** @todo Next protocol version: add flags, replace strings, remove initial offset. */
683
684 alock.release(); /* Drop write lock before sending. */
685
686 vrc = sendCommand(HOST_FILE_OPEN, i, paParms);
687 if (RT_SUCCESS(vrc))
688 vrc = i_waitForStatusChange(pEvent, uTimeoutMS,
689 NULL /* FileStatus */, pGuestRc);
690
691 unregisterWaitEvent(pEvent);
692
693 LogFlowFuncLeaveRC(vrc);
694 return vrc;
695}
696
697int GuestFile::i_readData(uint32_t uSize, uint32_t uTimeoutMS,
698 void* pvData, uint32_t cbData, uint32_t* pcbRead)
699{
700 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
701 AssertReturn(cbData, VERR_INVALID_PARAMETER);
702
703 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
704 uSize, uTimeoutMS, pvData, cbData));
705
706 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
707
708 int vrc;
709
710 GuestWaitEvent *pEvent = NULL;
711 GuestEventTypes eventTypes;
712 try
713 {
714 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
715 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
716
717 vrc = registerWaitEvent(eventTypes, &pEvent);
718 }
719 catch (std::bad_alloc)
720 {
721 vrc = VERR_NO_MEMORY;
722 }
723
724 if (RT_FAILURE(vrc))
725 return vrc;
726
727 /* Prepare HGCM call. */
728 VBOXHGCMSVCPARM paParms[4];
729 int i = 0;
730 paParms[i++].setUInt32(pEvent->ContextID());
731 paParms[i++].setUInt32(mData.mID /* File handle */);
732 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
733
734 alock.release(); /* Drop write lock before sending. */
735
736 uint32_t cbRead;
737 vrc = sendCommand(HOST_FILE_READ, i, paParms);
738 if (RT_SUCCESS(vrc))
739 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
740
741 if (RT_SUCCESS(vrc))
742 {
743 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
744
745 if (pcbRead)
746 *pcbRead = cbRead;
747 }
748
749 unregisterWaitEvent(pEvent);
750
751 LogFlowFuncLeaveRC(vrc);
752 return vrc;
753}
754
755int GuestFile::i_readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
756 void* pvData, size_t cbData, size_t* pcbRead)
757{
758 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
759 uOffset, uSize, uTimeoutMS, pvData, cbData));
760
761 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
762
763 int vrc;
764
765 GuestWaitEvent *pEvent = NULL;
766 GuestEventTypes eventTypes;
767 try
768 {
769 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
770 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
771
772 vrc = registerWaitEvent(eventTypes, &pEvent);
773 }
774 catch (std::bad_alloc)
775 {
776 vrc = VERR_NO_MEMORY;
777 }
778
779 if (RT_FAILURE(vrc))
780 return vrc;
781
782 /* Prepare HGCM call. */
783 VBOXHGCMSVCPARM paParms[4];
784 int i = 0;
785 paParms[i++].setUInt32(pEvent->ContextID());
786 paParms[i++].setUInt32(mData.mID /* File handle */);
787 paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
788 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
789
790 alock.release(); /* Drop write lock before sending. */
791
792 uint32_t cbRead;
793 vrc = sendCommand(HOST_FILE_READ_AT, i, paParms);
794 if (RT_SUCCESS(vrc))
795 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
796
797 if (RT_SUCCESS(vrc))
798 {
799 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
800
801 if (pcbRead)
802 *pcbRead = cbRead;
803 }
804
805 unregisterWaitEvent(pEvent);
806
807 LogFlowFuncLeaveRC(vrc);
808 return vrc;
809}
810
811int GuestFile::i_seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType,
812 uint32_t uTimeoutMS, uint64_t *puOffset)
813{
814 LogFlowThisFunc(("iOffset=%RI64, uTimeoutMS=%RU32\n",
815 iOffset, uTimeoutMS));
816
817 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
818
819 int vrc;
820
821 GuestWaitEvent *pEvent = NULL;
822 GuestEventTypes eventTypes;
823 try
824 {
825 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
826 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
827
828 vrc = registerWaitEvent(eventTypes, &pEvent);
829 }
830 catch (std::bad_alloc)
831 {
832 vrc = VERR_NO_MEMORY;
833 }
834
835 if (RT_FAILURE(vrc))
836 return vrc;
837
838 /* Prepare HGCM call. */
839 VBOXHGCMSVCPARM paParms[4];
840 int i = 0;
841 paParms[i++].setUInt32(pEvent->ContextID());
842 paParms[i++].setUInt32(mData.mID /* File handle */);
843 paParms[i++].setUInt32(eSeekType /* Seek method */);
844 /** @todo uint64_t vs. int64_t! */
845 paParms[i++].setUInt64((uint64_t)iOffset /* Offset (in bytes) to start reading */);
846
847 alock.release(); /* Drop write lock before sending. */
848
849 vrc = sendCommand(HOST_FILE_SEEK, i, paParms);
850 if (RT_SUCCESS(vrc))
851 vrc = i_waitForOffsetChange(pEvent, uTimeoutMS, puOffset);
852
853 unregisterWaitEvent(pEvent);
854
855 LogFlowFuncLeaveRC(vrc);
856 return vrc;
857}
858
859/* static */
860HRESULT GuestFile::i_setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
861{
862 AssertPtr(pInterface);
863 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
864
865 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestFile::i_guestErrorToString(guestRc).c_str());
866}
867
868int GuestFile::i_setFileStatus(FileStatus_T fileStatus, int fileRc)
869{
870 LogFlowThisFuncEnter();
871
872 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
873
874 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, fileRc=%Rrc\n",
875 mData.mStatus, fileStatus, fileRc));
876
877#ifdef VBOX_STRICT
878 if (fileStatus == FileStatus_Error)
879 {
880 AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc));
881 }
882 else
883 AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc));
884#endif
885
886 if (mData.mStatus != fileStatus)
887 {
888 mData.mStatus = fileStatus;
889 mData.mLastError = fileRc;
890
891 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
892 HRESULT hr = errorInfo.createObject();
893 ComAssertComRC(hr);
894 if (RT_FAILURE(fileRc))
895 {
896 hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, fileRc,
897 COM_IIDOF(IGuestFile), getComponentName(),
898 i_guestErrorToString(fileRc));
899 ComAssertComRC(hr);
900 }
901
902 alock.release(); /* Release lock before firing off event. */
903
904 fireGuestFileStateChangedEvent(mEventSource, mSession,
905 this, fileStatus, errorInfo);
906 }
907
908 return VINF_SUCCESS;
909}
910
911int GuestFile::i_waitForOffsetChange(GuestWaitEvent *pEvent,
912 uint32_t uTimeoutMS, uint64_t *puOffset)
913{
914 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
915
916 VBoxEventType_T evtType;
917 ComPtr<IEvent> pIEvent;
918 int vrc = waitForEvent(pEvent, uTimeoutMS,
919 &evtType, pIEvent.asOutParam());
920 if (RT_SUCCESS(vrc))
921 {
922 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
923 {
924 if (puOffset)
925 {
926 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
927 Assert(!pFileEvent.isNull());
928
929 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
930 ComAssertComRC(hr);
931 }
932 }
933 else
934 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
935 }
936
937 return vrc;
938}
939
940int GuestFile::i_waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
941 void *pvData, size_t cbData, uint32_t *pcbRead)
942{
943 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
944
945 VBoxEventType_T evtType;
946 ComPtr<IEvent> pIEvent;
947 int vrc = waitForEvent(pEvent, uTimeoutMS,
948 &evtType, pIEvent.asOutParam());
949 if (RT_SUCCESS(vrc))
950 {
951 if (evtType == VBoxEventType_OnGuestFileRead)
952 {
953 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
954 Assert(!pFileEvent.isNull());
955
956 HRESULT hr;
957 if (pvData)
958 {
959 com::SafeArray <BYTE> data;
960 hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
961 ComAssertComRC(hr);
962 size_t cbRead = data.size();
963 if ( cbRead
964 && cbRead <= cbData)
965 {
966 memcpy(pvData, data.raw(), data.size());
967 }
968 else
969 vrc = VERR_BUFFER_OVERFLOW;
970 }
971 if (pcbRead)
972 {
973 hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
974 ComAssertComRC(hr);
975 }
976 }
977 else
978 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
979 }
980
981 return vrc;
982}
983
984int GuestFile::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
985 FileStatus_T *pFileStatus, int *pGuestRc)
986{
987 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
988 /* pFileStatus is optional. */
989
990 VBoxEventType_T evtType;
991 ComPtr<IEvent> pIEvent;
992 int vrc = waitForEvent(pEvent, uTimeoutMS,
993 &evtType, pIEvent.asOutParam());
994 if (RT_SUCCESS(vrc))
995 {
996 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
997 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
998 Assert(!pFileEvent.isNull());
999
1000 HRESULT hr;
1001 if (pFileStatus)
1002 {
1003 hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1004 ComAssertComRC(hr);
1005 }
1006
1007 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1008 hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam());
1009 ComAssertComRC(hr);
1010
1011 LONG lGuestRc;
1012 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1013 ComAssertComRC(hr);
1014
1015 LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n",
1016 lGuestRc, lGuestRc));
1017
1018 if (RT_FAILURE((int)lGuestRc))
1019 vrc = VERR_GSTCTL_GUEST_ERROR;
1020
1021 if (pGuestRc)
1022 *pGuestRc = (int)lGuestRc;
1023 }
1024
1025 return vrc;
1026}
1027
1028int GuestFile::i_waitForWrite(GuestWaitEvent *pEvent,
1029 uint32_t uTimeoutMS, uint32_t *pcbWritten)
1030{
1031 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1032
1033 VBoxEventType_T evtType;
1034 ComPtr<IEvent> pIEvent;
1035 int vrc = waitForEvent(pEvent, uTimeoutMS,
1036 &evtType, pIEvent.asOutParam());
1037 if (RT_SUCCESS(vrc))
1038 {
1039 if (evtType == VBoxEventType_OnGuestFileWrite)
1040 {
1041 if (pcbWritten)
1042 {
1043 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1044 Assert(!pFileEvent.isNull());
1045
1046 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1047 ComAssertComRC(hr);
1048 }
1049 }
1050 else
1051 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1052 }
1053
1054 return vrc;
1055}
1056
1057int GuestFile::i_writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData,
1058 uint32_t *pcbWritten)
1059{
1060 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1061 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1062
1063 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1064 uTimeoutMS, pvData, cbData));
1065
1066 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1067
1068 int vrc;
1069
1070 GuestWaitEvent *pEvent = NULL;
1071 GuestEventTypes eventTypes;
1072 try
1073 {
1074 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1075 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1076
1077 vrc = registerWaitEvent(eventTypes, &pEvent);
1078 }
1079 catch (std::bad_alloc)
1080 {
1081 vrc = VERR_NO_MEMORY;
1082 }
1083
1084 if (RT_FAILURE(vrc))
1085 return vrc;
1086
1087 /* Prepare HGCM call. */
1088 VBOXHGCMSVCPARM paParms[8];
1089 int i = 0;
1090 paParms[i++].setUInt32(pEvent->ContextID());
1091 paParms[i++].setUInt32(mData.mID /* File handle */);
1092 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
1093 paParms[i++].setPointer(pvData, cbData);
1094
1095 alock.release(); /* Drop write lock before sending. */
1096
1097 uint32_t cbWritten;
1098 vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
1099 if (RT_SUCCESS(vrc))
1100 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1101
1102 if (RT_SUCCESS(vrc))
1103 {
1104 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1105
1106 if (cbWritten)
1107 *pcbWritten = cbWritten;
1108 }
1109
1110 unregisterWaitEvent(pEvent);
1111
1112 LogFlowFuncLeaveRC(vrc);
1113 return vrc;
1114}
1115
1116int GuestFile::i_writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
1117 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1118{
1119 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1120 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1121
1122 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1123 uOffset, uTimeoutMS, pvData, cbData));
1124
1125 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1126
1127 int vrc;
1128
1129 GuestWaitEvent *pEvent = NULL;
1130 GuestEventTypes eventTypes;
1131 try
1132 {
1133 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1134 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1135
1136 vrc = registerWaitEvent(eventTypes, &pEvent);
1137 }
1138 catch (std::bad_alloc)
1139 {
1140 vrc = VERR_NO_MEMORY;
1141 }
1142
1143 if (RT_FAILURE(vrc))
1144 return vrc;
1145
1146 /* Prepare HGCM call. */
1147 VBOXHGCMSVCPARM paParms[8];
1148 int i = 0;
1149 paParms[i++].setUInt32(pEvent->ContextID());
1150 paParms[i++].setUInt32(mData.mID /* File handle */);
1151 paParms[i++].setUInt64(uOffset /* Offset where to starting writing */);
1152 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
1153 paParms[i++].setPointer(pvData, cbData);
1154
1155 alock.release(); /* Drop write lock before sending. */
1156
1157 uint32_t cbWritten;
1158 vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
1159 if (RT_SUCCESS(vrc))
1160 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1161
1162 if (RT_SUCCESS(vrc))
1163 {
1164 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1165
1166 if (cbWritten)
1167 *pcbWritten = cbWritten;
1168 }
1169
1170 unregisterWaitEvent(pEvent);
1171
1172 LogFlowFuncLeaveRC(vrc);
1173 return vrc;
1174}
1175
1176// Wrapped IGuestFile methods
1177/////////////////////////////////////////////////////////////////////////////
1178HRESULT GuestFile::close()
1179{
1180 LogFlowThisFuncEnter();
1181
1182 /* Close file on guest. */
1183 int guestRc;
1184 int rc = i_closeFile(&guestRc);
1185 /* On failure don't return here, instead do all the cleanup
1186 * work first and then return an error. */
1187
1188 AssertPtr(mSession);
1189 int rc2 = mSession->i_fileRemoveFromList(this);
1190 if (RT_SUCCESS(rc))
1191 rc = rc2;
1192
1193 if (RT_FAILURE(rc))
1194 {
1195 if (rc == VERR_GSTCTL_GUEST_ERROR)
1196 return GuestFile::i_setErrorExternal(this, guestRc);
1197
1198 return setError(VBOX_E_IPRT_ERROR,
1199 tr("Closing guest file failed with %Rrc\n"), rc);
1200 }
1201
1202 LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
1203 return S_OK;
1204}
1205
1206HRESULT GuestFile::queryInfo(ComPtr<IFsObjInfo> &aObjInfo)
1207{
1208 ReturnComNotImplemented();
1209}
1210
1211HRESULT GuestFile::querySize(LONG64 *aSize)
1212{
1213 ReturnComNotImplemented();
1214}
1215
1216HRESULT GuestFile::read(ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1217{
1218 if (aToRead == 0)
1219 return setError(E_INVALIDARG, tr("The size to read is zero"));
1220
1221 aData.resize(aToRead);
1222
1223 HRESULT hr = S_OK;
1224
1225 uint32_t cbRead;
1226 int vrc = i_readData(aToRead, aTimeoutMS,
1227 &aData.front(), aToRead, &cbRead);
1228
1229 if (RT_SUCCESS(vrc))
1230 {
1231 if (aData.size() != cbRead)
1232 aData.resize(cbRead);
1233 }
1234 else
1235 {
1236 aData.resize(0);
1237
1238 switch (vrc)
1239 {
1240 default:
1241 hr = setError(VBOX_E_IPRT_ERROR,
1242 tr("Reading from file \"%s\" failed: %Rrc"),
1243 mData.mOpenInfo.mFileName.c_str(), vrc);
1244 break;
1245 }
1246 }
1247
1248 LogFlowFuncLeaveRC(vrc);
1249 return hr;
1250}
1251HRESULT GuestFile::readAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1252
1253{
1254 if (aToRead == 0)
1255 return setError(E_INVALIDARG, tr("The size to read is zero"));
1256
1257 aData.resize(aToRead);
1258
1259 HRESULT hr = S_OK;
1260
1261 size_t cbRead;
1262 int vrc = i_readDataAt(aOffset, aToRead, aTimeoutMS,
1263 &aData.front(), aToRead, &cbRead);
1264 if (RT_SUCCESS(vrc))
1265 {
1266 if (aData.size() != cbRead)
1267 aData.resize(cbRead);
1268 }
1269 else
1270 {
1271 aData.resize(0);
1272
1273 switch (vrc)
1274 {
1275 default:
1276 hr = setError(VBOX_E_IPRT_ERROR,
1277 tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1278 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1279 break;
1280 }
1281 }
1282
1283 LogFlowFuncLeaveRC(vrc);
1284 return hr;
1285}
1286
1287HRESULT GuestFile::seek(LONG64 aOffset, FileSeekOrigin_T aWhence, LONG64 *aNewOffset)
1288{
1289 LogFlowThisFuncEnter();
1290
1291 HRESULT hr = S_OK;
1292
1293 GUEST_FILE_SEEKTYPE eSeekType;
1294 switch (aWhence)
1295 {
1296 case FileSeekOrigin_Begin:
1297 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1298 break;
1299
1300 case FileSeekOrigin_Current:
1301 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1302 break;
1303
1304 case FileSeekOrigin_End:
1305 eSeekType = GUEST_FILE_SEEKTYPE_END;
1306 break;
1307
1308 default:
1309 return setError(E_INVALIDARG, tr("Invalid seek type specified"));
1310 break; /* Never reached. */
1311 }
1312
1313 uint64_t uNewOffset;
1314 int vrc = i_seekAt(aOffset, eSeekType,
1315 30 * 1000 /* 30s timeout */, &uNewOffset);
1316 if (RT_SUCCESS(vrc))
1317 *aNewOffset = RT_MIN(uNewOffset, (uint64_t)INT64_MAX);
1318 else
1319 {
1320 switch (vrc)
1321 {
1322 default:
1323 hr = setError(VBOX_E_IPRT_ERROR,
1324 tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"),
1325 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1326 break;
1327 }
1328 }
1329
1330 LogFlowFuncLeaveRC(vrc);
1331 return hr;
1332}
1333
1334HRESULT GuestFile::setACL(const com::Utf8Str &aAcl, ULONG aMode)
1335{
1336 ReturnComNotImplemented();
1337}
1338
1339HRESULT GuestFile::setSize(LONG64 aSize)
1340{
1341 ReturnComNotImplemented();
1342}
1343
1344HRESULT GuestFile::write(const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1345{
1346 LogFlowThisFuncEnter();
1347
1348 HRESULT hr = S_OK;
1349
1350 uint32_t cbData = (uint32_t)aData.size();
1351 void *pvData = cbData > 0? (void *)&aData.front(): NULL;
1352 int vrc = i_writeData(aTimeoutMS, pvData, cbData,
1353 (uint32_t*)aWritten);
1354 if (RT_FAILURE(vrc))
1355 {
1356 switch (vrc)
1357 {
1358 default:
1359 hr = setError(VBOX_E_IPRT_ERROR,
1360 tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
1361 aData.size(), mData.mOpenInfo.mFileName.c_str(), vrc);
1362 break;
1363 }
1364 }
1365
1366 LogFlowFuncLeaveRC(vrc);
1367 return hr;
1368}
1369
1370HRESULT GuestFile::writeAt(LONG64 aOffset, const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1371
1372{
1373 LogFlowThisFuncEnter();
1374
1375 HRESULT hr = S_OK;
1376
1377 uint32_t cbData = (uint32_t)aData.size();
1378 void *pvData = cbData > 0? (void *)&aData.front(): NULL;
1379 int vrc = i_writeData(aTimeoutMS, pvData, cbData,
1380 (uint32_t*)aWritten);
1381 if (RT_FAILURE(vrc))
1382 {
1383 switch (vrc)
1384 {
1385 default:
1386 hr = setError(VBOX_E_IPRT_ERROR,
1387 tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
1388 aData.size(), mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1389 break;
1390 }
1391 }
1392
1393 LogFlowFuncLeaveRC(vrc);
1394 return hr;
1395}
1396
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