VirtualBox

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

Last change on this file since 55650 was 55645, checked in by vboxsync, 10 years ago

Removed 106 #ifdef/#ifndef VBOX_WITH_GUEST_CONTROL statements that was never really necessary.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.2 KB
Line 
1/* $Id: GuestFileImpl.cpp 55645 2015-05-04 13:39:18Z 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.215389.xyz. 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 {
478 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
479 AssertMsg(mData.mID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID),
480 ("File ID %RU32 does not match context ID %RU32\n", mData.mID,
481 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));
482
483 /* Set the initial offset. On the guest the whole opening operation
484 * would fail if an initial seek isn't possible. */
485 mData.mOffCurrent = mData.mOpenInfo.mInitialOffset;
486 }
487
488 /* Set the process status. */
489 int rc2 = i_setFileStatus(FileStatus_Open, guestRc);
490 AssertRC(rc2);
491 }
492 else
493 vrc = VERR_NOT_SUPPORTED;
494
495 break;
496 }
497
498 case GUEST_FILE_NOTIFYTYPE_CLOSE:
499 {
500 int rc2 = i_setFileStatus(FileStatus_Closed, guestRc);
501 AssertRC(rc2);
502
503 break;
504 }
505
506 case GUEST_FILE_NOTIFYTYPE_READ:
507 {
508 if (pSvcCbData->mParms == 4)
509 {
510 pSvcCbData->mpaParms[idx++].getPointer(&dataCb.u.read.pvData,
511 &dataCb.u.read.cbData);
512 uint32_t cbRead = dataCb.u.read.cbData;
513
514 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
515
516 mData.mOffCurrent += cbRead;
517
518 alock.release();
519
520 com::SafeArray<BYTE> data((size_t)cbRead);
521 data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead);
522
523 fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent,
524 cbRead, ComSafeArrayAsInParam(data));
525 }
526 else
527 vrc = VERR_NOT_SUPPORTED;
528 break;
529 }
530
531 case GUEST_FILE_NOTIFYTYPE_WRITE:
532 {
533 if (pSvcCbData->mParms == 4)
534 {
535 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.write.cbWritten);
536
537 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
538
539 mData.mOffCurrent += dataCb.u.write.cbWritten;
540 uint64_t uOffCurrent = mData.mOffCurrent;
541
542 alock.release();
543
544 fireGuestFileWriteEvent(mEventSource, mSession, this, uOffCurrent,
545 dataCb.u.write.cbWritten);
546 }
547 else
548 vrc = VERR_NOT_SUPPORTED;
549 break;
550 }
551
552 case GUEST_FILE_NOTIFYTYPE_SEEK:
553 {
554 if (pSvcCbData->mParms == 4)
555 {
556 pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.seek.uOffActual);
557
558 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
559
560 mData.mOffCurrent = dataCb.u.seek.uOffActual;
561
562 alock.release();
563
564 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
565 dataCb.u.seek.uOffActual, 0 /* Processed */);
566 }
567 else
568 vrc = VERR_NOT_SUPPORTED;
569 break;
570 }
571
572 case GUEST_FILE_NOTIFYTYPE_TELL:
573 {
574 if (pSvcCbData->mParms == 4)
575 {
576 pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.tell.uOffActual);
577
578 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
579
580 mData.mOffCurrent = dataCb.u.tell.uOffActual;
581
582 alock.release();
583
584 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
585 dataCb.u.tell.uOffActual, 0 /* Processed */);
586 }
587 else
588 vrc = VERR_NOT_SUPPORTED;
589 break;
590 }
591
592 default:
593 vrc = VERR_NOT_SUPPORTED;
594 break;
595 }
596
597 if (RT_SUCCESS(vrc))
598 {
599 GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb));
600 int rc2 = signalWaitEventInternal(pCbCtx, guestRc, &payload);
601 AssertRC(rc2);
602 }
603
604 LogFlowThisFunc(("uType=%RU32, guestRc=%Rrc\n",
605 dataCb.uType, dataCb.rc));
606
607 LogFlowFuncLeaveRC(vrc);
608 return vrc;
609}
610
611int GuestFile::i_onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
612{
613 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
614 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
615
616 int vrc = i_setFileStatus(FileStatus_Down, VINF_SUCCESS);
617
618 LogFlowFuncLeaveRC(vrc);
619 return vrc;
620}
621
622/**
623 * Called by IGuestSession right before this file gets removed
624 * from the public file list.
625 */
626int GuestFile::i_onRemove(void)
627{
628 LogFlowThisFuncEnter();
629
630 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
631
632 int vrc = VINF_SUCCESS;
633
634 /*
635 * Note: The event source stuff holds references to this object,
636 * so make sure that this is cleaned up *before* calling uninit().
637 */
638 if (!mEventSource.isNull())
639 {
640 mEventSource->UnregisterListener(mLocalListener);
641
642 mLocalListener.setNull();
643 unconst(mEventSource).setNull();
644 }
645
646 LogFlowFuncLeaveRC(vrc);
647 return vrc;
648}
649
650int GuestFile::i_openFile(uint32_t uTimeoutMS, int *pGuestRc)
651{
652 LogFlowThisFuncEnter();
653
654 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
655
656 LogFlowThisFunc(("strFile=%s, enmAccessMode=%d (%s) enmOpenAction=%d (%s) uCreationMode=%RU32, uOffset=%RU64\n",
657 mData.mOpenInfo.mFileName.c_str(), mData.mOpenInfo.mAccessMode, mData.mOpenInfo.mpszAccessMode,
658 mData.mOpenInfo.mOpenAction, mData.mOpenInfo.mpszOpenAction, mData.mOpenInfo.mCreationMode,
659 mData.mOpenInfo.mInitialOffset));
660 int vrc;
661
662 GuestWaitEvent *pEvent = NULL;
663 GuestEventTypes eventTypes;
664 try
665 {
666 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
667
668 vrc = registerWaitEvent(eventTypes, &pEvent);
669 }
670 catch (std::bad_alloc)
671 {
672 vrc = VERR_NO_MEMORY;
673 }
674
675 if (RT_FAILURE(vrc))
676 return vrc;
677
678 /* Prepare HGCM call. */
679 VBOXHGCMSVCPARM paParms[8];
680 int i = 0;
681 paParms[i++].setUInt32(pEvent->ContextID());
682 paParms[i++].setPointer((void*)mData.mOpenInfo.mFileName.c_str(),
683 (ULONG)mData.mOpenInfo.mFileName.length() + 1);
684 paParms[i++].setString(mData.mOpenInfo.mpszAccessMode);
685 paParms[i++].setString(mData.mOpenInfo.mpszOpenAction);
686 paParms[i++].setString(""); /** @todo sharing mode. */
687 paParms[i++].setUInt32(mData.mOpenInfo.mCreationMode);
688 paParms[i++].setUInt64(mData.mOpenInfo.mInitialOffset);
689
690 alock.release(); /* Drop write lock before sending. */
691
692 vrc = sendCommand(HOST_FILE_OPEN, i, paParms);
693 if (RT_SUCCESS(vrc))
694 vrc = i_waitForStatusChange(pEvent, uTimeoutMS,
695 NULL /* FileStatus */, pGuestRc);
696
697 unregisterWaitEvent(pEvent);
698
699 LogFlowFuncLeaveRC(vrc);
700 return vrc;
701}
702
703int GuestFile::i_readData(uint32_t uSize, uint32_t uTimeoutMS,
704 void* pvData, uint32_t cbData, uint32_t* pcbRead)
705{
706 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
707 AssertReturn(cbData, VERR_INVALID_PARAMETER);
708
709 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
710 uSize, uTimeoutMS, pvData, cbData));
711
712 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
713
714 int vrc;
715
716 GuestWaitEvent *pEvent = NULL;
717 GuestEventTypes eventTypes;
718 try
719 {
720 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
721 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
722
723 vrc = registerWaitEvent(eventTypes, &pEvent);
724 }
725 catch (std::bad_alloc)
726 {
727 vrc = VERR_NO_MEMORY;
728 }
729
730 if (RT_FAILURE(vrc))
731 return vrc;
732
733 /* Prepare HGCM call. */
734 VBOXHGCMSVCPARM paParms[4];
735 int i = 0;
736 paParms[i++].setUInt32(pEvent->ContextID());
737 paParms[i++].setUInt32(mData.mID /* File handle */);
738 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
739
740 alock.release(); /* Drop write lock before sending. */
741
742 uint32_t cbRead;
743 vrc = sendCommand(HOST_FILE_READ, i, paParms);
744 if (RT_SUCCESS(vrc))
745 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
746
747 if (RT_SUCCESS(vrc))
748 {
749 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
750
751 if (pcbRead)
752 *pcbRead = cbRead;
753 }
754
755 unregisterWaitEvent(pEvent);
756
757 LogFlowFuncLeaveRC(vrc);
758 return vrc;
759}
760
761int GuestFile::i_readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
762 void* pvData, size_t cbData, size_t* pcbRead)
763{
764 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
765 uOffset, uSize, uTimeoutMS, pvData, cbData));
766
767 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
768
769 int vrc;
770
771 GuestWaitEvent *pEvent = NULL;
772 GuestEventTypes eventTypes;
773 try
774 {
775 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
776 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
777
778 vrc = registerWaitEvent(eventTypes, &pEvent);
779 }
780 catch (std::bad_alloc)
781 {
782 vrc = VERR_NO_MEMORY;
783 }
784
785 if (RT_FAILURE(vrc))
786 return vrc;
787
788 /* Prepare HGCM call. */
789 VBOXHGCMSVCPARM paParms[4];
790 int i = 0;
791 paParms[i++].setUInt32(pEvent->ContextID());
792 paParms[i++].setUInt32(mData.mID /* File handle */);
793 paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
794 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
795
796 alock.release(); /* Drop write lock before sending. */
797
798 uint32_t cbRead;
799 vrc = sendCommand(HOST_FILE_READ_AT, i, paParms);
800 if (RT_SUCCESS(vrc))
801 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
802
803 if (RT_SUCCESS(vrc))
804 {
805 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
806
807 if (pcbRead)
808 *pcbRead = cbRead;
809 }
810
811 unregisterWaitEvent(pEvent);
812
813 LogFlowFuncLeaveRC(vrc);
814 return vrc;
815}
816
817int GuestFile::i_seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType,
818 uint32_t uTimeoutMS, uint64_t *puOffset)
819{
820 LogFlowThisFunc(("iOffset=%RI64, uTimeoutMS=%RU32\n",
821 iOffset, uTimeoutMS));
822
823 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
824
825 int vrc;
826
827 GuestWaitEvent *pEvent = NULL;
828 GuestEventTypes eventTypes;
829 try
830 {
831 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
832 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
833
834 vrc = registerWaitEvent(eventTypes, &pEvent);
835 }
836 catch (std::bad_alloc)
837 {
838 vrc = VERR_NO_MEMORY;
839 }
840
841 if (RT_FAILURE(vrc))
842 return vrc;
843
844 /* Prepare HGCM call. */
845 VBOXHGCMSVCPARM paParms[4];
846 int i = 0;
847 paParms[i++].setUInt32(pEvent->ContextID());
848 paParms[i++].setUInt32(mData.mID /* File handle */);
849 paParms[i++].setUInt32(eSeekType /* Seek method */);
850 /** @todo uint64_t vs. int64_t! */
851 paParms[i++].setUInt64((uint64_t)iOffset /* Offset (in bytes) to start reading */);
852
853 alock.release(); /* Drop write lock before sending. */
854
855 vrc = sendCommand(HOST_FILE_SEEK, i, paParms);
856 if (RT_SUCCESS(vrc))
857 vrc = i_waitForOffsetChange(pEvent, uTimeoutMS, puOffset);
858
859 unregisterWaitEvent(pEvent);
860
861 LogFlowFuncLeaveRC(vrc);
862 return vrc;
863}
864
865/* static */
866HRESULT GuestFile::i_setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
867{
868 AssertPtr(pInterface);
869 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
870
871 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestFile::i_guestErrorToString(guestRc).c_str());
872}
873
874int GuestFile::i_setFileStatus(FileStatus_T fileStatus, int fileRc)
875{
876 LogFlowThisFuncEnter();
877
878 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
879
880 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, fileRc=%Rrc\n",
881 mData.mStatus, fileStatus, fileRc));
882
883#ifdef VBOX_STRICT
884 if (fileStatus == FileStatus_Error)
885 {
886 AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc));
887 }
888 else
889 AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc));
890#endif
891
892 if (mData.mStatus != fileStatus)
893 {
894 mData.mStatus = fileStatus;
895 mData.mLastError = fileRc;
896
897 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
898 HRESULT hr = errorInfo.createObject();
899 ComAssertComRC(hr);
900 if (RT_FAILURE(fileRc))
901 {
902 hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, fileRc,
903 COM_IIDOF(IGuestFile), getComponentName(),
904 i_guestErrorToString(fileRc));
905 ComAssertComRC(hr);
906 }
907
908 alock.release(); /* Release lock before firing off event. */
909
910 fireGuestFileStateChangedEvent(mEventSource, mSession,
911 this, fileStatus, errorInfo);
912 }
913
914 return VINF_SUCCESS;
915}
916
917int GuestFile::i_waitForOffsetChange(GuestWaitEvent *pEvent,
918 uint32_t uTimeoutMS, uint64_t *puOffset)
919{
920 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
921
922 VBoxEventType_T evtType;
923 ComPtr<IEvent> pIEvent;
924 int vrc = waitForEvent(pEvent, uTimeoutMS,
925 &evtType, pIEvent.asOutParam());
926 if (RT_SUCCESS(vrc))
927 {
928 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
929 {
930 if (puOffset)
931 {
932 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
933 Assert(!pFileEvent.isNull());
934
935 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
936 ComAssertComRC(hr);
937 }
938 }
939 else
940 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
941 }
942
943 return vrc;
944}
945
946int GuestFile::i_waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
947 void *pvData, size_t cbData, uint32_t *pcbRead)
948{
949 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
950
951 VBoxEventType_T evtType;
952 ComPtr<IEvent> pIEvent;
953 int vrc = waitForEvent(pEvent, uTimeoutMS,
954 &evtType, pIEvent.asOutParam());
955 if (RT_SUCCESS(vrc))
956 {
957 if (evtType == VBoxEventType_OnGuestFileRead)
958 {
959 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
960 Assert(!pFileEvent.isNull());
961
962 HRESULT hr;
963 if (pvData)
964 {
965 com::SafeArray <BYTE> data;
966 hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
967 ComAssertComRC(hr);
968 size_t cbRead = data.size();
969 if ( cbRead
970 && cbRead <= cbData)
971 {
972 memcpy(pvData, data.raw(), data.size());
973 }
974 else
975 vrc = VERR_BUFFER_OVERFLOW;
976 }
977 if (pcbRead)
978 {
979 hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
980 ComAssertComRC(hr);
981 }
982 }
983 else
984 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
985 }
986
987 return vrc;
988}
989
990int GuestFile::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
991 FileStatus_T *pFileStatus, int *pGuestRc)
992{
993 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
994 /* pFileStatus is optional. */
995
996 VBoxEventType_T evtType;
997 ComPtr<IEvent> pIEvent;
998 int vrc = waitForEvent(pEvent, uTimeoutMS,
999 &evtType, pIEvent.asOutParam());
1000 if (RT_SUCCESS(vrc))
1001 {
1002 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
1003 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
1004 Assert(!pFileEvent.isNull());
1005
1006 HRESULT hr;
1007 if (pFileStatus)
1008 {
1009 hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1010 ComAssertComRC(hr);
1011 }
1012
1013 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1014 hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam());
1015 ComAssertComRC(hr);
1016
1017 LONG lGuestRc;
1018 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1019 ComAssertComRC(hr);
1020
1021 LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n",
1022 lGuestRc, lGuestRc));
1023
1024 if (RT_FAILURE((int)lGuestRc))
1025 vrc = VERR_GSTCTL_GUEST_ERROR;
1026
1027 if (pGuestRc)
1028 *pGuestRc = (int)lGuestRc;
1029 }
1030
1031 return vrc;
1032}
1033
1034int GuestFile::i_waitForWrite(GuestWaitEvent *pEvent,
1035 uint32_t uTimeoutMS, uint32_t *pcbWritten)
1036{
1037 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1038
1039 VBoxEventType_T evtType;
1040 ComPtr<IEvent> pIEvent;
1041 int vrc = waitForEvent(pEvent, uTimeoutMS,
1042 &evtType, pIEvent.asOutParam());
1043 if (RT_SUCCESS(vrc))
1044 {
1045 if (evtType == VBoxEventType_OnGuestFileWrite)
1046 {
1047 if (pcbWritten)
1048 {
1049 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1050 Assert(!pFileEvent.isNull());
1051
1052 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1053 ComAssertComRC(hr);
1054 }
1055 }
1056 else
1057 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1058 }
1059
1060 return vrc;
1061}
1062
1063int GuestFile::i_writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData,
1064 uint32_t *pcbWritten)
1065{
1066 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1067 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1068
1069 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1070 uTimeoutMS, pvData, cbData));
1071
1072 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1073
1074 int vrc;
1075
1076 GuestWaitEvent *pEvent = NULL;
1077 GuestEventTypes eventTypes;
1078 try
1079 {
1080 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1081 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1082
1083 vrc = registerWaitEvent(eventTypes, &pEvent);
1084 }
1085 catch (std::bad_alloc)
1086 {
1087 vrc = VERR_NO_MEMORY;
1088 }
1089
1090 if (RT_FAILURE(vrc))
1091 return vrc;
1092
1093 /* Prepare HGCM call. */
1094 VBOXHGCMSVCPARM paParms[8];
1095 int i = 0;
1096 paParms[i++].setUInt32(pEvent->ContextID());
1097 paParms[i++].setUInt32(mData.mID /* File handle */);
1098 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
1099 paParms[i++].setPointer(pvData, cbData);
1100
1101 alock.release(); /* Drop write lock before sending. */
1102
1103 uint32_t cbWritten;
1104 vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
1105 if (RT_SUCCESS(vrc))
1106 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1107
1108 if (RT_SUCCESS(vrc))
1109 {
1110 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1111
1112 if (cbWritten)
1113 *pcbWritten = cbWritten;
1114 }
1115
1116 unregisterWaitEvent(pEvent);
1117
1118 LogFlowFuncLeaveRC(vrc);
1119 return vrc;
1120}
1121
1122int GuestFile::i_writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
1123 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1124{
1125 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1126 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1127
1128 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1129 uOffset, uTimeoutMS, pvData, cbData));
1130
1131 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1132
1133 int vrc;
1134
1135 GuestWaitEvent *pEvent = NULL;
1136 GuestEventTypes eventTypes;
1137 try
1138 {
1139 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1140 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1141
1142 vrc = registerWaitEvent(eventTypes, &pEvent);
1143 }
1144 catch (std::bad_alloc)
1145 {
1146 vrc = VERR_NO_MEMORY;
1147 }
1148
1149 if (RT_FAILURE(vrc))
1150 return vrc;
1151
1152 /* Prepare HGCM call. */
1153 VBOXHGCMSVCPARM paParms[8];
1154 int i = 0;
1155 paParms[i++].setUInt32(pEvent->ContextID());
1156 paParms[i++].setUInt32(mData.mID /* File handle */);
1157 paParms[i++].setUInt64(uOffset /* Offset where to starting writing */);
1158 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
1159 paParms[i++].setPointer(pvData, cbData);
1160
1161 alock.release(); /* Drop write lock before sending. */
1162
1163 uint32_t cbWritten;
1164 vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
1165 if (RT_SUCCESS(vrc))
1166 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1167
1168 if (RT_SUCCESS(vrc))
1169 {
1170 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1171
1172 if (cbWritten)
1173 *pcbWritten = cbWritten;
1174 }
1175
1176 unregisterWaitEvent(pEvent);
1177
1178 LogFlowFuncLeaveRC(vrc);
1179 return vrc;
1180}
1181
1182// Wrapped IGuestFile methods
1183/////////////////////////////////////////////////////////////////////////////
1184HRESULT GuestFile::close()
1185{
1186 LogFlowThisFuncEnter();
1187
1188 /* Close file on guest. */
1189 int guestRc;
1190 int rc = i_closeFile(&guestRc);
1191 /* On failure don't return here, instead do all the cleanup
1192 * work first and then return an error. */
1193
1194 AssertPtr(mSession);
1195 int rc2 = mSession->i_fileRemoveFromList(this);
1196 if (RT_SUCCESS(rc))
1197 rc = rc2;
1198
1199 if (RT_FAILURE(rc))
1200 {
1201 if (rc == VERR_GSTCTL_GUEST_ERROR)
1202 return GuestFile::i_setErrorExternal(this, guestRc);
1203
1204 return setError(VBOX_E_IPRT_ERROR,
1205 tr("Closing guest file failed with %Rrc\n"), rc);
1206 }
1207
1208 LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
1209 return S_OK;
1210}
1211
1212HRESULT GuestFile::queryInfo(ComPtr<IFsObjInfo> &aObjInfo)
1213{
1214 ReturnComNotImplemented();
1215}
1216
1217HRESULT GuestFile::querySize(LONG64 *aSize)
1218{
1219 ReturnComNotImplemented();
1220}
1221
1222HRESULT GuestFile::read(ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1223{
1224 if (aToRead == 0)
1225 return setError(E_INVALIDARG, tr("The size to read is zero"));
1226
1227 aData.resize(aToRead);
1228
1229 HRESULT hr = S_OK;
1230
1231 uint32_t cbRead;
1232 int vrc = i_readData(aToRead, aTimeoutMS,
1233 &aData.front(), aToRead, &cbRead);
1234
1235 if (RT_SUCCESS(vrc))
1236 {
1237 if (aData.size() != cbRead)
1238 aData.resize(cbRead);
1239 }
1240 else
1241 {
1242 aData.resize(0);
1243
1244 switch (vrc)
1245 {
1246 default:
1247 hr = setError(VBOX_E_IPRT_ERROR,
1248 tr("Reading from file \"%s\" failed: %Rrc"),
1249 mData.mOpenInfo.mFileName.c_str(), vrc);
1250 break;
1251 }
1252 }
1253
1254 LogFlowFuncLeaveRC(vrc);
1255 return hr;
1256}
1257HRESULT GuestFile::readAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1258
1259{
1260 if (aToRead == 0)
1261 return setError(E_INVALIDARG, tr("The size to read is zero"));
1262
1263 aData.resize(aToRead);
1264
1265 HRESULT hr = S_OK;
1266
1267 size_t cbRead;
1268 int vrc = i_readDataAt(aOffset, aToRead, aTimeoutMS,
1269 &aData.front(), aToRead, &cbRead);
1270 if (RT_SUCCESS(vrc))
1271 {
1272 if (aData.size() != cbRead)
1273 aData.resize(cbRead);
1274 }
1275 else
1276 {
1277 aData.resize(0);
1278
1279 switch (vrc)
1280 {
1281 default:
1282 hr = setError(VBOX_E_IPRT_ERROR,
1283 tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1284 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1285 break;
1286 }
1287 }
1288
1289 LogFlowFuncLeaveRC(vrc);
1290 return hr;
1291}
1292
1293HRESULT GuestFile::seek(LONG64 aOffset, FileSeekOrigin_T aWhence, LONG64 *aNewOffset)
1294{
1295 LogFlowThisFuncEnter();
1296
1297 HRESULT hr = S_OK;
1298
1299 GUEST_FILE_SEEKTYPE eSeekType;
1300 switch (aWhence)
1301 {
1302 case FileSeekOrigin_Set:
1303 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1304 break;
1305
1306 case FileSeekOrigin_Current:
1307 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1308 break;
1309
1310 case FileSeekOrigin_End:
1311 eSeekType = GUEST_FILE_SEEKTYPE_END;
1312 break;
1313
1314 default:
1315 return setError(E_INVALIDARG, tr("Invalid seek type specified"));
1316 break; /* Never reached. */
1317 }
1318
1319 uint64_t uNewOffset;
1320 int vrc = i_seekAt(aOffset, eSeekType,
1321 30 * 1000 /* 30s timeout */, &uNewOffset);
1322 if (RT_SUCCESS(vrc))
1323 *aNewOffset = RT_MIN(uNewOffset, (uint64_t)INT64_MAX);
1324 else
1325 {
1326 switch (vrc)
1327 {
1328 default:
1329 hr = setError(VBOX_E_IPRT_ERROR,
1330 tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"),
1331 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1332 break;
1333 }
1334 }
1335
1336 LogFlowFuncLeaveRC(vrc);
1337 return hr;
1338}
1339
1340HRESULT GuestFile::setACL(const com::Utf8Str &aAcl, ULONG aMode)
1341{
1342 ReturnComNotImplemented();
1343}
1344
1345HRESULT GuestFile::setSize(LONG64 aSize)
1346{
1347 ReturnComNotImplemented();
1348}
1349
1350HRESULT GuestFile::write(const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1351{
1352 LogFlowThisFuncEnter();
1353
1354 HRESULT hr = S_OK;
1355
1356 uint32_t cbData = (uint32_t)aData.size();
1357 void *pvData = cbData > 0? (void *)&aData.front(): NULL;
1358 int vrc = i_writeData(aTimeoutMS, pvData, cbData,
1359 (uint32_t*)aWritten);
1360 if (RT_FAILURE(vrc))
1361 {
1362 switch (vrc)
1363 {
1364 default:
1365 hr = setError(VBOX_E_IPRT_ERROR,
1366 tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
1367 aData.size(), mData.mOpenInfo.mFileName.c_str(), vrc);
1368 break;
1369 }
1370 }
1371
1372 LogFlowFuncLeaveRC(vrc);
1373 return hr;
1374}
1375
1376HRESULT GuestFile::writeAt(LONG64 aOffset, const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1377
1378{
1379 LogFlowThisFuncEnter();
1380
1381 HRESULT hr = S_OK;
1382
1383 uint32_t cbData = (uint32_t)aData.size();
1384 void *pvData = cbData > 0? (void *)&aData.front(): NULL;
1385 int vrc = i_writeData(aTimeoutMS, pvData, cbData,
1386 (uint32_t*)aWritten);
1387 if (RT_FAILURE(vrc))
1388 {
1389 switch (vrc)
1390 {
1391 default:
1392 hr = setError(VBOX_E_IPRT_ERROR,
1393 tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
1394 aData.size(), mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1395 break;
1396 }
1397 }
1398
1399 LogFlowFuncLeaveRC(vrc);
1400 return hr;
1401}
1402
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