VirtualBox

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

Last change on this file since 66891 was 63244, checked in by vboxsync, 8 years ago

Main: warnings

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