VirtualBox

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

Last change on this file since 79278 was 79278, checked in by vboxsync, 5 years ago

Main/GuestFileImpl.cpp: Cap the read and readAt requests at 1 MiB so as to not waste memory on aData buffer space that won't be used, given the that guest side won't return more than a MiB. bugref:9320

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.0 KB
Line 
1/* $Id: GuestFileImpl.cpp 79278 2019-06-21 13:52:35Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Guest file handling.
4 */
5
6/*
7 * Copyright (C) 2012-2019 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#define LOG_GROUP LOG_GROUP_MAIN_GUESTFILE
23#include "LoggingNew.h"
24
25#ifndef VBOX_WITH_GUEST_CONTROL
26# error "VBOX_WITH_GUEST_CONTROL must defined in this file"
27#endif
28#include "GuestFileImpl.h"
29#include "GuestSessionImpl.h"
30#include "GuestCtrlImplPrivate.h"
31#include "ConsoleImpl.h"
32#include "VirtualBoxErrorInfoImpl.h"
33
34#include "Global.h"
35#include "AutoCaller.h"
36#include "VBoxEvents.h"
37
38#include <iprt/cpp/utils.h> /* For unconst(). */
39#include <iprt/file.h>
40
41#include <VBox/com/array.h>
42#include <VBox/com/listeners.h>
43
44
45/**
46 * Internal listener class to serve events in an
47 * active manner, e.g. without polling delays.
48 */
49class GuestFileListener
50{
51public:
52
53 GuestFileListener(void)
54 {
55 }
56
57 virtual ~GuestFileListener()
58 {
59 }
60
61 HRESULT init(GuestFile *pFile)
62 {
63 AssertPtrReturn(pFile, E_POINTER);
64 mFile = pFile;
65 return S_OK;
66 }
67
68 void uninit(void)
69 {
70 mFile = NULL;
71 }
72
73 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
74 {
75 switch (aType)
76 {
77 case VBoxEventType_OnGuestFileStateChanged:
78 case VBoxEventType_OnGuestFileOffsetChanged:
79 case VBoxEventType_OnGuestFileRead:
80 case VBoxEventType_OnGuestFileWrite:
81 {
82 AssertPtrReturn(mFile, E_POINTER);
83 int rc2 = mFile->signalWaitEvent(aType, aEvent);
84 RT_NOREF(rc2);
85#ifdef DEBUG_andy
86 LogFlowFunc(("Signalling events of type=%RU32, file=%p resulted in rc=%Rrc\n",
87 aType, mFile, rc2));
88#endif
89 break;
90 }
91
92 default:
93 AssertMsgFailed(("Unhandled event %RU32\n", aType));
94 break;
95 }
96
97 return S_OK;
98 }
99
100private:
101
102 GuestFile *mFile;
103};
104typedef ListenerImpl<GuestFileListener, GuestFile*> GuestFileListenerImpl;
105
106VBOX_LISTENER_DECLARE(GuestFileListenerImpl)
107
108// constructor / destructor
109/////////////////////////////////////////////////////////////////////////////
110
111DEFINE_EMPTY_CTOR_DTOR(GuestFile)
112
113HRESULT GuestFile::FinalConstruct(void)
114{
115 LogFlowThisFuncEnter();
116 return BaseFinalConstruct();
117}
118
119void GuestFile::FinalRelease(void)
120{
121 LogFlowThisFuncEnter();
122 uninit();
123 BaseFinalRelease();
124 LogFlowThisFuncLeave();
125}
126
127// public initializer/uninitializer for internal purposes only
128/////////////////////////////////////////////////////////////////////////////
129
130/**
131 * Initializes a file object but does *not* open the file on the guest
132 * yet. This is done in the dedidcated openFile call.
133 *
134 * @return IPRT status code.
135 * @param pConsole Pointer to console object.
136 * @param pSession Pointer to session object.
137 * @param aObjectID The object's ID.
138 * @param openInfo File opening information.
139 */
140int GuestFile::init(Console *pConsole, GuestSession *pSession,
141 ULONG aObjectID, const GuestFileOpenInfo &openInfo)
142{
143 LogFlowThisFunc(("pConsole=%p, pSession=%p, aObjectID=%RU32, strPath=%s\n",
144 pConsole, pSession, aObjectID, openInfo.mFilename.c_str()));
145
146 AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
147 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
148
149 /* Enclose the state transition NotReady->InInit->Ready. */
150 AutoInitSpan autoInitSpan(this);
151 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
152
153 int vrc = bindToSession(pConsole, pSession, aObjectID);
154 if (RT_SUCCESS(vrc))
155 {
156 mSession = pSession;
157
158 mData.mOpenInfo = openInfo;
159 mData.mInitialSize = 0;
160 mData.mStatus = FileStatus_Undefined;
161 mData.mLastError = VINF_SUCCESS;
162 mData.mOffCurrent = 0;
163
164 unconst(mEventSource).createObject();
165 HRESULT hr = mEventSource->init();
166 if (FAILED(hr))
167 vrc = VERR_COM_UNEXPECTED;
168 }
169
170 if (RT_SUCCESS(vrc))
171 {
172 try
173 {
174 GuestFileListener *pListener = new GuestFileListener();
175 ComObjPtr<GuestFileListenerImpl> thisListener;
176 HRESULT hr = thisListener.createObject();
177 if (SUCCEEDED(hr))
178 hr = thisListener->init(pListener, this);
179
180 if (SUCCEEDED(hr))
181 {
182 com::SafeArray <VBoxEventType_T> eventTypes;
183 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
184 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
185 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
186 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
187 hr = mEventSource->RegisterListener(thisListener,
188 ComSafeArrayAsInParam(eventTypes),
189 TRUE /* Active listener */);
190 if (SUCCEEDED(hr))
191 {
192 vrc = baseInit();
193 if (RT_SUCCESS(vrc))
194 {
195 mLocalListener = thisListener;
196 }
197 }
198 else
199 vrc = VERR_COM_UNEXPECTED;
200 }
201 else
202 vrc = VERR_COM_UNEXPECTED;
203 }
204 catch(std::bad_alloc &)
205 {
206 vrc = VERR_NO_MEMORY;
207 }
208 }
209
210 if (RT_SUCCESS(vrc))
211 {
212 /* Confirm a successful initialization when it's the case. */
213 autoInitSpan.setSucceeded();
214 }
215 else
216 autoInitSpan.setFailed();
217
218 LogFlowFuncLeaveRC(vrc);
219 return vrc;
220}
221
222/**
223 * Uninitializes the instance.
224 * Called from FinalRelease().
225 */
226void GuestFile::uninit(void)
227{
228 /* Enclose the state transition Ready->InUninit->NotReady. */
229 AutoUninitSpan autoUninitSpan(this);
230 if (autoUninitSpan.uninitDone())
231 return;
232
233 LogFlowThisFuncEnter();
234
235 baseUninit();
236 LogFlowThisFuncLeave();
237}
238
239// implementation of public getters/setters for attributes
240/////////////////////////////////////////////////////////////////////////////
241
242HRESULT GuestFile::getCreationMode(ULONG *aCreationMode)
243{
244 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
245
246 *aCreationMode = mData.mOpenInfo.mCreationMode;
247
248 return S_OK;
249}
250
251HRESULT GuestFile::getOpenAction(FileOpenAction_T *aOpenAction)
252{
253 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
254
255 *aOpenAction = mData.mOpenInfo.mOpenAction;
256
257 return S_OK;
258}
259
260HRESULT GuestFile::getEventSource(ComPtr<IEventSource> &aEventSource)
261{
262 /* No need to lock - lifetime constant. */
263 mEventSource.queryInterfaceTo(aEventSource.asOutParam());
264
265 return S_OK;
266}
267
268HRESULT GuestFile::getFilename(com::Utf8Str &aFilename)
269{
270 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
271
272 aFilename = mData.mOpenInfo.mFilename;
273
274 return S_OK;
275}
276
277HRESULT GuestFile::getId(ULONG *aId)
278{
279 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
280
281 *aId = mObjectID;
282
283 return S_OK;
284}
285
286HRESULT GuestFile::getInitialSize(LONG64 *aInitialSize)
287{
288 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
289
290 *aInitialSize = mData.mInitialSize;
291
292 return S_OK;
293}
294
295HRESULT GuestFile::getOffset(LONG64 *aOffset)
296{
297 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
298
299/** @todo r=bird: Why do you have both a offset and a tell() function?
300 * After a ReadAt or WriteAt with a non-current offset, the tell() result will
301 * differ from this value, because mOffCurrent is only ever incremented with
302 * data read or written. */
303 *aOffset = mData.mOffCurrent;
304
305 return S_OK;
306}
307
308HRESULT GuestFile::getAccessMode(FileAccessMode_T *aAccessMode)
309{
310 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
311
312 *aAccessMode = mData.mOpenInfo.mAccessMode;
313
314 return S_OK;
315}
316
317HRESULT GuestFile::getStatus(FileStatus_T *aStatus)
318{
319 LogFlowThisFuncEnter();
320
321 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
322
323 *aStatus = mData.mStatus;
324
325 return S_OK;
326}
327
328// private methods
329/////////////////////////////////////////////////////////////////////////////
330
331int GuestFile::i_callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
332{
333 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
334 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
335
336 LogFlowThisFunc(("strName=%s, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
337 mData.mOpenInfo.mFilename.c_str(), pCbCtx->uContextID, pCbCtx->uMessage, pSvcCb));
338
339 int vrc;
340 switch (pCbCtx->uMessage)
341 {
342 case GUEST_MSG_DISCONNECTED:
343 vrc = i_onGuestDisconnected(pCbCtx, pSvcCb);
344 break;
345
346 case GUEST_MSG_FILE_NOTIFY:
347 vrc = i_onFileNotify(pCbCtx, pSvcCb);
348 break;
349
350 default:
351 /* Silently ignore not implemented functions. */
352 vrc = VERR_NOT_SUPPORTED;
353 break;
354 }
355
356#ifdef DEBUG
357 LogFlowFuncLeaveRC(vrc);
358#endif
359 return vrc;
360}
361
362int GuestFile::i_closeFile(int *prcGuest)
363{
364 LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFilename.c_str()));
365
366 int vrc;
367
368 GuestWaitEvent *pEvent = NULL;
369 GuestEventTypes eventTypes;
370 try
371 {
372 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
373
374 vrc = registerWaitEvent(eventTypes, &pEvent);
375 }
376 catch (std::bad_alloc &)
377 {
378 vrc = VERR_NO_MEMORY;
379 }
380
381 if (RT_FAILURE(vrc))
382 return vrc;
383
384 /* Prepare HGCM call. */
385 VBOXHGCMSVCPARM paParms[4];
386 int i = 0;
387 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
388 HGCMSvcSetU32(&paParms[i++], mObjectID /* Guest file ID */);
389
390 vrc = sendMessage(HOST_MSG_FILE_CLOSE, i, paParms);
391 if (RT_SUCCESS(vrc))
392 vrc = i_waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */,
393 NULL /* FileStatus */, prcGuest);
394 unregisterWaitEvent(pEvent);
395
396 LogFlowFuncLeaveRC(vrc);
397 return vrc;
398}
399
400/* static */ const char *GuestFile::i_guestVrcToString(int rcGuest)
401{
402 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
403 switch (rcGuest)
404 {
405 case VERR_ACCESS_DENIED: return tr("Access denied");
406 case VERR_ALREADY_EXISTS: return tr("File already exists");
407 case VERR_FILE_NOT_FOUND: return tr("File not found");
408 case VERR_NET_HOST_NOT_FOUND: return tr("Host name not found");
409 case VERR_SHARING_VIOLATION: return tr("Sharing violation");
410 default: return RTErrGetDefine(rcGuest);
411 }
412}
413
414/**
415 * @todo r=bird: This is an absolutely cryptic way of reporting errors. You may convert
416 * this to a const char * returning function for explaining rcGuest and
417 * use that as part of a _proper_ error message. This alone extremely
418 * user unfriendly. E.g. which file is not found? One of the source files,
419 * a destination file, what are you referring to?!?
420 *
421 * I've addressed one of these that annoyed me, you can do the rest of them.
422 */
423/* static */ Utf8Str GuestFile::i_guestErrorToString(int rcGuest)
424{
425 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
426 return i_guestVrcToString(rcGuest);
427}
428
429int GuestFile::i_onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
430{
431 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
432 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
433
434 LogFlowThisFuncEnter();
435
436 if (pSvcCbData->mParms < 3)
437 return VERR_INVALID_PARAMETER;
438
439 int idx = 1; /* Current parameter index. */
440 CALLBACKDATA_FILE_NOTIFY dataCb;
441 /* pSvcCb->mpaParms[0] always contains the context ID. */
442 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.uType);
443 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.rc);
444
445 int rcGuest = (int)dataCb.rc; /* uint32_t vs. int. */
446
447 LogFlowThisFunc(("uType=%RU32, rcGuest=%Rrc\n", dataCb.uType, rcGuest));
448
449 if (RT_FAILURE(rcGuest))
450 {
451 int rc2 = i_setFileStatus(FileStatus_Error, rcGuest);
452 AssertRC(rc2);
453
454 /* Ignore rc, as the event to signal might not be there (anymore). */
455 signalWaitEventInternal(pCbCtx, rcGuest, NULL /* pPayload */);
456 return VINF_SUCCESS; /* Report to the guest. */
457 }
458
459 AssertMsg(mObjectID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID),
460 ("File ID %RU32 does not match object ID %RU32\n", mObjectID,
461 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));
462
463 int rc = VERR_NOT_SUPPORTED; /* Play safe by default. */
464
465 switch (dataCb.uType)
466 {
467 case GUEST_FILE_NOTIFYTYPE_ERROR:
468 {
469 rc = i_setFileStatus(FileStatus_Error, rcGuest);
470 break;
471 }
472
473 case GUEST_FILE_NOTIFYTYPE_OPEN:
474 {
475 if (pSvcCbData->mParms == 4)
476 {
477 rc = HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.u.open.uHandle);
478 if (RT_FAILURE(rc))
479 break;
480
481 /* Set the process status. */
482 rc = i_setFileStatus(FileStatus_Open, rcGuest);
483 }
484 break;
485 }
486
487 case GUEST_FILE_NOTIFYTYPE_CLOSE:
488 {
489 rc = i_setFileStatus(FileStatus_Closed, rcGuest);
490 break;
491 }
492
493 case GUEST_FILE_NOTIFYTYPE_READ:
494 {
495 if (pSvcCbData->mParms == 4)
496 {
497 rc = HGCMSvcGetPv(&pSvcCbData->mpaParms[idx++], &dataCb.u.read.pvData,
498 &dataCb.u.read.cbData);
499 if (RT_FAILURE(rc))
500 break;
501
502 const uint32_t cbRead = dataCb.u.read.cbData;
503
504 Log3ThisFunc(("cbRead=%RU32\n", cbRead));
505
506 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
507
508 mData.mOffCurrent += cbRead;
509
510 alock.release();
511
512 com::SafeArray<BYTE> data((size_t)cbRead);
513 data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead);
514
515 fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent,
516 cbRead, ComSafeArrayAsInParam(data));
517 }
518 break;
519 }
520
521 case GUEST_FILE_NOTIFYTYPE_WRITE:
522 {
523 if (pSvcCbData->mParms == 4)
524 {
525 rc = HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.u.write.cbWritten);
526 if (RT_FAILURE(rc))
527 break;
528
529 const uint32_t cbWritten = dataCb.u.write.cbWritten;
530
531 Log3ThisFunc(("cbWritten=%RU32\n", cbWritten));
532
533 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
534
535 mData.mOffCurrent += cbWritten;
536
537 alock.release();
538
539 fireGuestFileWriteEvent(mEventSource, mSession, this, mData.mOffCurrent, cbWritten);
540 }
541 break;
542 }
543
544 case GUEST_FILE_NOTIFYTYPE_SEEK:
545 {
546 if (pSvcCbData->mParms == 4)
547 {
548 rc = HGCMSvcGetU64(&pSvcCbData->mpaParms[idx++], &dataCb.u.seek.uOffActual);
549 if (RT_FAILURE(rc))
550 break;
551
552 Log3ThisFunc(("uOffActual=%RU64\n", dataCb.u.seek.uOffActual));
553
554 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
555
556 mData.mOffCurrent = dataCb.u.seek.uOffActual;
557
558 alock.release();
559
560 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, mData.mOffCurrent, 0 /* Processed */);
561 }
562 break;
563 }
564
565 case GUEST_FILE_NOTIFYTYPE_TELL:
566 {
567 if (pSvcCbData->mParms == 4)
568 {
569 rc = HGCMSvcGetU64(&pSvcCbData->mpaParms[idx++], &dataCb.u.tell.uOffActual);
570 if (RT_FAILURE(rc))
571 break;
572
573 Log3ThisFunc(("uOffActual=%RU64\n", 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, mData.mOffCurrent, 0 /* Processed */);
582 }
583 break;
584 }
585
586 default:
587 break;
588 }
589
590 if (RT_SUCCESS(rc))
591 {
592 GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb));
593
594 /* Ignore rc, as the event to signal might not be there (anymore). */
595 signalWaitEventInternal(pCbCtx, rcGuest, &payload);
596 }
597
598 LogFlowThisFunc(("uType=%RU32, rcGuest=%Rrc, rc=%Rrc\n", dataCb.uType, rcGuest, rc));
599 return rc;
600}
601
602int GuestFile::i_onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
603{
604 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
605 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
606
607 int vrc = i_setFileStatus(FileStatus_Down, VINF_SUCCESS);
608
609 LogFlowFuncLeaveRC(vrc);
610 return vrc;
611}
612
613/**
614 * @copydoc GuestObject::i_onUnregister
615 */
616int GuestFile::i_onUnregister(void)
617{
618 LogFlowThisFuncEnter();
619
620 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
621
622 int vrc = VINF_SUCCESS;
623
624 /*
625 * Note: The event source stuff holds references to this object,
626 * so make sure that this is cleaned up *before* calling uninit().
627 */
628 if (!mEventSource.isNull())
629 {
630 mEventSource->UnregisterListener(mLocalListener);
631
632 mLocalListener.setNull();
633 unconst(mEventSource).setNull();
634 }
635
636 LogFlowFuncLeaveRC(vrc);
637 return vrc;
638}
639
640/**
641 * @copydoc GuestObject::i_onSessionStatusChange
642 */
643int GuestFile::i_onSessionStatusChange(GuestSessionStatus_T enmSessionStatus)
644{
645 LogFlowThisFuncEnter();
646
647 int vrc = VINF_SUCCESS;
648
649 /* If the session now is in a terminated state, set the file status
650 * to "down", as there is not much else we can do now. */
651 if (GuestSession::i_isTerminated(enmSessionStatus))
652 vrc = i_setFileStatus(FileStatus_Down, 0 /* fileRc, ignored */);
653
654 LogFlowFuncLeaveRC(vrc);
655 return vrc;
656}
657
658int GuestFile::i_openFile(uint32_t uTimeoutMS, int *prcGuest)
659{
660 AssertReturn(mData.mOpenInfo.mFilename.isNotEmpty(), VERR_INVALID_PARAMETER);
661
662 LogFlowThisFuncEnter();
663
664 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
665
666 LogFlowThisFunc(("strFile=%s, enmAccessMode=0x%x, enmOpenAction=0x%x, uCreationMode=%RU32, mfOpenEx=%RU32\n",
667 mData.mOpenInfo.mFilename.c_str(), mData.mOpenInfo.mAccessMode, mData.mOpenInfo.mOpenAction,
668 mData.mOpenInfo.mCreationMode, mData.mOpenInfo.mfOpenEx));
669
670 /* Validate and translate open action. */
671 const char *pszOpenAction = NULL;
672 switch (mData.mOpenInfo.mOpenAction)
673 {
674 case FileOpenAction_OpenExisting: pszOpenAction = "oe"; break;
675 case FileOpenAction_OpenOrCreate: pszOpenAction = "oc"; break;
676 case FileOpenAction_CreateNew: pszOpenAction = "ce"; break;
677 case FileOpenAction_CreateOrReplace: pszOpenAction = "ca"; break;
678 case FileOpenAction_OpenExistingTruncated: pszOpenAction = "ot"; break;
679 case FileOpenAction_AppendOrCreate:
680 pszOpenAction = "oa"; /** @todo get rid of this one and implement AppendOnly/AppendRead. */
681 break;
682 default:
683 return VERR_INVALID_PARAMETER;
684 }
685
686 /* Validate and translate access mode. */
687 const char *pszAccessMode = NULL;
688 switch (mData.mOpenInfo.mAccessMode)
689 {
690 case FileAccessMode_ReadOnly: pszAccessMode = "r"; break;
691 case FileAccessMode_WriteOnly: pszAccessMode = "w"; break;
692 case FileAccessMode_ReadWrite: pszAccessMode = "r+"; break;
693 case FileAccessMode_AppendOnly: RT_FALL_THRU();
694 case FileAccessMode_AppendRead: return VERR_NOT_IMPLEMENTED;
695 default: return VERR_INVALID_PARAMETER;
696 }
697
698 /* Validate and translate sharing mode. */
699 const char *pszSharingMode = NULL;
700 switch (mData.mOpenInfo.mSharingMode)
701 {
702 case FileSharingMode_All: pszSharingMode = ""; break;
703 case FileSharingMode_Read: RT_FALL_THRU();
704 case FileSharingMode_Write: RT_FALL_THRU();
705 case FileSharingMode_ReadWrite: RT_FALL_THRU();
706 case FileSharingMode_Delete: RT_FALL_THRU();
707 case FileSharingMode_ReadDelete: RT_FALL_THRU();
708 case FileSharingMode_WriteDelete: return VERR_NOT_IMPLEMENTED;
709 default: return VERR_INVALID_PARAMETER;
710 }
711
712 int vrc;
713
714 GuestWaitEvent *pEvent = NULL;
715 GuestEventTypes eventTypes;
716 try
717 {
718 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
719
720 vrc = registerWaitEvent(eventTypes, &pEvent);
721 }
722 catch (std::bad_alloc &)
723 {
724 vrc = VERR_NO_MEMORY;
725 }
726
727 if (RT_FAILURE(vrc))
728 return vrc;
729
730 /* Prepare HGCM call. */
731 VBOXHGCMSVCPARM paParms[8];
732 int i = 0;
733 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
734 HGCMSvcSetPv(&paParms[i++], (void*)mData.mOpenInfo.mFilename.c_str(),
735 (ULONG)mData.mOpenInfo.mFilename.length() + 1);
736 HGCMSvcSetStr(&paParms[i++], pszAccessMode);
737 HGCMSvcSetStr(&paParms[i++], pszOpenAction);
738 HGCMSvcSetStr(&paParms[i++], pszSharingMode);
739 HGCMSvcSetU32(&paParms[i++], mData.mOpenInfo.mCreationMode);
740 HGCMSvcSetU64(&paParms[i++], mData.mOpenInfo.muOffset);
741 /** @todo Next protocol version: add flags, replace strings, remove initial offset. */
742
743 alock.release(); /* Drop write lock before sending. */
744
745 vrc = sendMessage(HOST_MSG_FILE_OPEN, i, paParms);
746 if (RT_SUCCESS(vrc))
747 vrc = i_waitForStatusChange(pEvent, uTimeoutMS, NULL /* FileStatus */, prcGuest);
748
749 unregisterWaitEvent(pEvent);
750
751 LogFlowFuncLeaveRC(vrc);
752 return vrc;
753}
754
755int GuestFile::i_queryInfo(GuestFsObjData &objData, int *prcGuest)
756{
757 AssertPtr(mSession);
758 return mSession->i_fsQueryInfo(mData.mOpenInfo.mFilename, FALSE /* fFollowSymlinks */, objData, prcGuest);
759}
760
761int GuestFile::i_readData(uint32_t uSize, uint32_t uTimeoutMS,
762 void* pvData, uint32_t cbData, uint32_t* pcbRead)
763{
764 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
765 AssertReturn(cbData, VERR_INVALID_PARAMETER);
766
767 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
768 uSize, uTimeoutMS, pvData, cbData));
769
770 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
771
772 int vrc;
773
774 GuestWaitEvent *pEvent = NULL;
775 GuestEventTypes eventTypes;
776 try
777 {
778 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
779 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
780
781 vrc = registerWaitEvent(eventTypes, &pEvent);
782 }
783 catch (std::bad_alloc &)
784 {
785 vrc = VERR_NO_MEMORY;
786 }
787
788 if (RT_FAILURE(vrc))
789 return vrc;
790
791 /* Prepare HGCM call. */
792 VBOXHGCMSVCPARM paParms[4];
793 int i = 0;
794 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
795 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
796 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
797
798 alock.release(); /* Drop write lock before sending. */
799
800 vrc = sendMessage(HOST_MSG_FILE_READ, i, paParms);
801 if (RT_SUCCESS(vrc))
802 {
803 uint32_t cbRead = 0;
804 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
805 if (RT_SUCCESS(vrc))
806 {
807 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
808 if (pcbRead)
809 *pcbRead = cbRead;
810 }
811 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
812 {
813 vrc = pEvent->GetGuestError();
814 }
815 }
816
817 unregisterWaitEvent(pEvent);
818
819 LogFlowFuncLeaveRC(vrc);
820 return vrc;
821}
822
823int GuestFile::i_readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
824 void* pvData, size_t cbData, size_t* pcbRead)
825{
826 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
827 uOffset, uSize, uTimeoutMS, pvData, cbData));
828
829 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
830
831 int vrc;
832
833 GuestWaitEvent *pEvent = NULL;
834 GuestEventTypes eventTypes;
835 try
836 {
837 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
838 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
839
840 vrc = registerWaitEvent(eventTypes, &pEvent);
841 }
842 catch (std::bad_alloc &)
843 {
844 vrc = VERR_NO_MEMORY;
845 }
846
847 if (RT_FAILURE(vrc))
848 return vrc;
849
850 /* Prepare HGCM call. */
851 VBOXHGCMSVCPARM paParms[4];
852 int i = 0;
853 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
854 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
855 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset (in bytes) to start reading */);
856 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
857
858 alock.release(); /* Drop write lock before sending. */
859
860 vrc = sendMessage(HOST_MSG_FILE_READ_AT, i, paParms);
861 if (RT_SUCCESS(vrc))
862 {
863 uint32_t cbRead = 0;
864 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
865 if (RT_SUCCESS(vrc))
866 {
867 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
868
869 if (pcbRead)
870 *pcbRead = cbRead;
871 }
872 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
873 {
874 vrc = pEvent->GetGuestError();
875 }
876 }
877
878 unregisterWaitEvent(pEvent);
879
880 LogFlowFuncLeaveRC(vrc);
881 return vrc;
882}
883
884int GuestFile::i_seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType,
885 uint32_t uTimeoutMS, uint64_t *puOffset)
886{
887 LogFlowThisFunc(("iOffset=%RI64, uTimeoutMS=%RU32\n",
888 iOffset, uTimeoutMS));
889
890 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
891
892 int vrc;
893
894 GuestWaitEvent *pEvent = NULL;
895 GuestEventTypes eventTypes;
896 try
897 {
898 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
899 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
900
901 vrc = registerWaitEvent(eventTypes, &pEvent);
902 }
903 catch (std::bad_alloc &)
904 {
905 vrc = VERR_NO_MEMORY;
906 }
907
908 if (RT_FAILURE(vrc))
909 return vrc;
910
911 /* Prepare HGCM call. */
912 VBOXHGCMSVCPARM paParms[4];
913 int i = 0;
914 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
915 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
916 HGCMSvcSetU32(&paParms[i++], eSeekType /* Seek method */);
917 /** @todo uint64_t vs. int64_t! */
918 HGCMSvcSetU64(&paParms[i++], (uint64_t)iOffset /* Offset (in bytes) to start reading */);
919
920 alock.release(); /* Drop write lock before sending. */
921
922 vrc = sendMessage(HOST_MSG_FILE_SEEK, i, paParms);
923 if (RT_SUCCESS(vrc))
924 {
925 uint64_t uOffset;
926 vrc = i_waitForOffsetChange(pEvent, uTimeoutMS, &uOffset);
927 if (RT_SUCCESS(vrc))
928 {
929 LogFlowThisFunc(("uOffset=%RU64\n", uOffset));
930
931 if (puOffset)
932 *puOffset = uOffset;
933 }
934 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
935 {
936 vrc = pEvent->GetGuestError();
937 }
938 }
939
940 unregisterWaitEvent(pEvent);
941
942 LogFlowFuncLeaveRC(vrc);
943 return vrc;
944}
945
946/* static */
947HRESULT GuestFile::i_setErrorExternal(VirtualBoxBase *pInterface, int rcGuest)
948{
949 AssertPtr(pInterface);
950 AssertMsg(RT_FAILURE(rcGuest), ("Guest rc does not indicate a failure when setting error\n"));
951
952 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestFile::i_guestErrorToString(rcGuest).c_str());
953}
954
955int GuestFile::i_setFileStatus(FileStatus_T fileStatus, int fileRc)
956{
957 LogFlowThisFuncEnter();
958
959 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
960
961 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, fileRc=%Rrc\n",
962 mData.mStatus, fileStatus, fileRc));
963
964#ifdef VBOX_STRICT
965 if (fileStatus == FileStatus_Error)
966 {
967 AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc));
968 }
969 else
970 AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc));
971#endif
972
973 if (mData.mStatus != fileStatus)
974 {
975 mData.mStatus = fileStatus;
976 mData.mLastError = fileRc;
977
978 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
979 HRESULT hr = errorInfo.createObject();
980 ComAssertComRC(hr);
981 if (RT_FAILURE(fileRc))
982 {
983 hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, fileRc,
984 COM_IIDOF(IGuestFile), getComponentName(),
985 i_guestErrorToString(fileRc));
986 ComAssertComRC(hr);
987 }
988
989 alock.release(); /* Release lock before firing off event. */
990
991 fireGuestFileStateChangedEvent(mEventSource, mSession,
992 this, fileStatus, errorInfo);
993 }
994
995 return VINF_SUCCESS;
996}
997
998int GuestFile::i_waitForOffsetChange(GuestWaitEvent *pEvent,
999 uint32_t uTimeoutMS, uint64_t *puOffset)
1000{
1001 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1002
1003 VBoxEventType_T evtType;
1004 ComPtr<IEvent> pIEvent;
1005 int vrc = waitForEvent(pEvent, uTimeoutMS,
1006 &evtType, pIEvent.asOutParam());
1007 if (RT_SUCCESS(vrc))
1008 {
1009 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
1010 {
1011 if (puOffset)
1012 {
1013 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
1014 Assert(!pFileEvent.isNull());
1015
1016 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
1017 ComAssertComRC(hr);
1018 }
1019 }
1020 else
1021 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1022 }
1023
1024 return vrc;
1025}
1026
1027int GuestFile::i_waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1028 void *pvData, size_t cbData, uint32_t *pcbRead)
1029{
1030 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1031
1032 VBoxEventType_T evtType;
1033 ComPtr<IEvent> pIEvent;
1034 int vrc = waitForEvent(pEvent, uTimeoutMS,
1035 &evtType, pIEvent.asOutParam());
1036 if (RT_SUCCESS(vrc))
1037 {
1038 if (evtType == VBoxEventType_OnGuestFileRead)
1039 {
1040 vrc = VINF_SUCCESS;
1041
1042 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
1043 Assert(!pFileEvent.isNull());
1044
1045 if (pvData)
1046 {
1047 com::SafeArray <BYTE> data;
1048 HRESULT hrc1 = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1049 ComAssertComRC(hrc1);
1050 const size_t cbRead = data.size();
1051 if (cbRead)
1052 {
1053 if (cbRead <= cbData)
1054 memcpy(pvData, data.raw(), cbRead);
1055 else
1056 vrc = VERR_BUFFER_OVERFLOW;
1057 }
1058 /* else: used to be VERR_NO_DATA, but that messes stuff up. */
1059
1060 if (pcbRead)
1061 {
1062 *pcbRead = (uint32_t)cbRead;
1063 Assert(*pcbRead == cbRead);
1064 }
1065 }
1066 else if (pcbRead)
1067 {
1068 *pcbRead = 0;
1069 HRESULT hrc2 = pFileEvent->COMGETTER(Processed)((ULONG *)pcbRead);
1070 ComAssertComRC(hrc2); NOREF(hrc2);
1071 }
1072 }
1073 else
1074 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1075 }
1076
1077 return vrc;
1078}
1079
1080/**
1081 * Undocumented, use with great care.
1082 *
1083 * @note Similar code in GuestProcess::i_waitForStatusChange() and
1084 * GuestSession::i_waitForStatusChange().
1085 */
1086int GuestFile::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1087 FileStatus_T *pFileStatus, int *prcGuest)
1088{
1089 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1090 /* pFileStatus is optional. */
1091
1092 VBoxEventType_T evtType;
1093 ComPtr<IEvent> pIEvent;
1094 int vrc = waitForEvent(pEvent, uTimeoutMS,
1095 &evtType, pIEvent.asOutParam());
1096 if (RT_SUCCESS(vrc))
1097 {
1098 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
1099 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
1100 Assert(!pFileEvent.isNull());
1101
1102 HRESULT hr;
1103 if (pFileStatus)
1104 {
1105 hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1106 ComAssertComRC(hr);
1107 }
1108
1109 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1110 hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam());
1111 ComAssertComRC(hr);
1112
1113 LONG lGuestRc;
1114 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1115 ComAssertComRC(hr);
1116
1117 LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n",
1118 lGuestRc, lGuestRc));
1119
1120 if (RT_FAILURE((int)lGuestRc))
1121 vrc = VERR_GSTCTL_GUEST_ERROR;
1122
1123 if (prcGuest)
1124 *prcGuest = (int)lGuestRc;
1125 }
1126 /* waitForEvent may also return VERR_GSTCTL_GUEST_ERROR like we do above, so make prcGuest is set. */
1127 /** @todo r=bird: Andy, you seem to have forgotten this scenario. Showed up occasionally when
1128 * using the wrong password with a copyto command in a debug build on windows, error info
1129 * contained "Unknown Status -858993460 (0xcccccccc)". As you know windows fills the stack frames
1130 * with 0xcccccccc in debug builds to highlight use of uninitialized data, so that's what happened
1131 * here. It's actually good you didn't initialize lGuest, as it would be heck to find otherwise.
1132 *
1133 * I'm still not very impressed with the error managment or the usuefullness of the documentation
1134 * in this code, though the latter is getting better! */
1135 else if (vrc == VERR_GSTCTL_GUEST_ERROR && prcGuest)
1136 *prcGuest = pEvent->GuestResult();
1137 Assert(vrc != VERR_GSTCTL_GUEST_ERROR || !prcGuest || *prcGuest != (int)0xcccccccc);
1138
1139 return vrc;
1140}
1141
1142int GuestFile::i_waitForWrite(GuestWaitEvent *pEvent,
1143 uint32_t uTimeoutMS, uint32_t *pcbWritten)
1144{
1145 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1146
1147 VBoxEventType_T evtType;
1148 ComPtr<IEvent> pIEvent;
1149 int vrc = waitForEvent(pEvent, uTimeoutMS,
1150 &evtType, pIEvent.asOutParam());
1151 if (RT_SUCCESS(vrc))
1152 {
1153 if (evtType == VBoxEventType_OnGuestFileWrite)
1154 {
1155 if (pcbWritten)
1156 {
1157 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1158 Assert(!pFileEvent.isNull());
1159
1160 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1161 ComAssertComRC(hr);
1162 }
1163 }
1164 else
1165 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1166 }
1167
1168 return vrc;
1169}
1170
1171int GuestFile::i_writeData(uint32_t uTimeoutMS, const void *pvData, uint32_t cbData,
1172 uint32_t *pcbWritten)
1173{
1174 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1175 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1176
1177 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1178 uTimeoutMS, pvData, cbData));
1179
1180 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1181
1182 int vrc;
1183
1184 GuestWaitEvent *pEvent = NULL;
1185 GuestEventTypes eventTypes;
1186 try
1187 {
1188 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1189 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1190
1191 vrc = registerWaitEvent(eventTypes, &pEvent);
1192 }
1193 catch (std::bad_alloc &)
1194 {
1195 vrc = VERR_NO_MEMORY;
1196 }
1197
1198 if (RT_FAILURE(vrc))
1199 return vrc;
1200
1201 /* Prepare HGCM call. */
1202 VBOXHGCMSVCPARM paParms[8];
1203 int i = 0;
1204 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1205 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1206 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
1207 HGCMSvcSetPv (&paParms[i++], unconst(pvData), cbData);
1208
1209 alock.release(); /* Drop write lock before sending. */
1210
1211 vrc = sendMessage(HOST_MSG_FILE_WRITE, i, paParms);
1212 if (RT_SUCCESS(vrc))
1213 {
1214 uint32_t cbWritten = 0;
1215 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1216 if (RT_SUCCESS(vrc))
1217 {
1218 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1219 if (pcbWritten)
1220 *pcbWritten = cbWritten;
1221 }
1222 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1223 {
1224 vrc = pEvent->GetGuestError();
1225 }
1226 }
1227
1228 unregisterWaitEvent(pEvent);
1229
1230 LogFlowFuncLeaveRC(vrc);
1231 return vrc;
1232}
1233
1234int GuestFile::i_writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
1235 const void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1236{
1237 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1238 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1239
1240 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1241 uOffset, uTimeoutMS, pvData, cbData));
1242
1243 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1244
1245 int vrc;
1246
1247 GuestWaitEvent *pEvent = NULL;
1248 GuestEventTypes eventTypes;
1249 try
1250 {
1251 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1252 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1253
1254 vrc = registerWaitEvent(eventTypes, &pEvent);
1255 }
1256 catch (std::bad_alloc &)
1257 {
1258 vrc = VERR_NO_MEMORY;
1259 }
1260
1261 if (RT_FAILURE(vrc))
1262 return vrc;
1263
1264 /* Prepare HGCM call. */
1265 VBOXHGCMSVCPARM paParms[8];
1266 int i = 0;
1267 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1268 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1269 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset where to starting writing */);
1270 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
1271 HGCMSvcSetPv (&paParms[i++], unconst(pvData), cbData);
1272
1273 alock.release(); /* Drop write lock before sending. */
1274
1275 vrc = sendMessage(HOST_MSG_FILE_WRITE_AT, i, paParms);
1276 if (RT_SUCCESS(vrc))
1277 {
1278 uint32_t cbWritten = 0;
1279 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1280 if (RT_SUCCESS(vrc))
1281 {
1282 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1283 if (pcbWritten)
1284 *pcbWritten = cbWritten;
1285 }
1286 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1287 {
1288 vrc = pEvent->GetGuestError();
1289 }
1290 }
1291
1292 unregisterWaitEvent(pEvent);
1293
1294 LogFlowFuncLeaveRC(vrc);
1295 return vrc;
1296}
1297
1298// Wrapped IGuestFile methods
1299/////////////////////////////////////////////////////////////////////////////
1300HRESULT GuestFile::close()
1301{
1302 AutoCaller autoCaller(this);
1303 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1304
1305 LogFlowThisFuncEnter();
1306
1307 /* Close file on guest. */
1308 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1309 int vrc = i_closeFile(&rcGuest);
1310 /* On failure don't return here, instead do all the cleanup
1311 * work first and then return an error. */
1312
1313 AssertPtr(mSession);
1314 int vrc2 = mSession->i_fileUnregister(this);
1315 if (RT_SUCCESS(vrc))
1316 vrc = vrc2;
1317
1318 if (RT_FAILURE(vrc))
1319 {
1320 if (vrc == VERR_GSTCTL_GUEST_ERROR)
1321 return GuestFile::i_setErrorExternal(this, rcGuest);
1322 return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Closing guest file failed with %Rrc\n"), vrc);
1323 }
1324
1325 LogFlowThisFunc(("Returning S_OK / vrc=%Rrc\n", vrc));
1326 return S_OK;
1327}
1328
1329HRESULT GuestFile::queryInfo(ComPtr<IFsObjInfo> &aObjInfo)
1330{
1331 AutoCaller autoCaller(this);
1332 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1333
1334 LogFlowThisFuncEnter();
1335
1336 HRESULT hr = S_OK;
1337
1338 GuestFsObjData fsObjData;
1339 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1340 int vrc = i_queryInfo(fsObjData, &rcGuest);
1341 if (RT_SUCCESS(vrc))
1342 {
1343 ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
1344 hr = ptrFsObjInfo.createObject();
1345 if (SUCCEEDED(hr))
1346 {
1347 vrc = ptrFsObjInfo->init(fsObjData);
1348 if (RT_SUCCESS(vrc))
1349 hr = ptrFsObjInfo.queryInterfaceTo(aObjInfo.asOutParam());
1350 else
1351 hr = setErrorVrc(vrc);
1352 }
1353 }
1354 else
1355 {
1356 if (GuestProcess::i_isGuestError(vrc))
1357 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1358 else
1359 hr = setErrorVrc(vrc, tr("Querying file information failed: %Rrc"), vrc);
1360 }
1361
1362 LogFlowFuncLeaveRC(vrc);
1363 return hr;
1364}
1365
1366HRESULT GuestFile::querySize(LONG64 *aSize)
1367{
1368 AutoCaller autoCaller(this);
1369 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1370
1371 LogFlowThisFuncEnter();
1372
1373 HRESULT hr = S_OK;
1374
1375 GuestFsObjData fsObjData;
1376 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1377 int vrc = i_queryInfo(fsObjData, &rcGuest);
1378 if (RT_SUCCESS(vrc))
1379 {
1380 *aSize = fsObjData.mObjectSize;
1381 }
1382 else
1383 {
1384 if (GuestProcess::i_isGuestError(vrc))
1385 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1386 else
1387 hr = setErrorVrc(vrc, tr("Querying file size failed: %Rrc"), vrc);
1388 }
1389
1390 LogFlowFuncLeaveRC(vrc);
1391 return hr;
1392}
1393
1394HRESULT GuestFile::read(ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1395{
1396 AutoCaller autoCaller(this);
1397 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1398
1399 if (aToRead == 0)
1400 return setError(E_INVALIDARG, tr("The size to read is zero"));
1401
1402 LogFlowThisFuncEnter();
1403
1404 /* Cap the read at 1MiB because that's all the guest will return anyway. */
1405 if (aToRead > _1M)
1406 aToRead = _1M;
1407
1408 aData.resize(aToRead);
1409
1410 HRESULT hr = S_OK;
1411
1412 uint32_t cbRead;
1413 int vrc = i_readData(aToRead, aTimeoutMS,
1414 &aData.front(), aToRead, &cbRead);
1415
1416 if (RT_SUCCESS(vrc))
1417 {
1418 if (aData.size() != cbRead)
1419 aData.resize(cbRead);
1420 }
1421 else
1422 {
1423 aData.resize(0);
1424
1425 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" failed: %Rrc"),
1426 mData.mOpenInfo.mFilename.c_str(), vrc);
1427 }
1428
1429 LogFlowFuncLeaveRC(vrc);
1430 return hr;
1431}
1432
1433HRESULT GuestFile::readAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1434{
1435 AutoCaller autoCaller(this);
1436 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1437
1438 if (aToRead == 0)
1439 return setError(E_INVALIDARG, tr("The size to read is zero"));
1440
1441 LogFlowThisFuncEnter();
1442
1443 /* Cap the read at 1MiB because that's all the guest will return anyway. */
1444 if (aToRead > _1M)
1445 aToRead = _1M;
1446
1447 aData.resize(aToRead);
1448
1449 HRESULT hr = S_OK;
1450
1451 size_t cbRead;
1452 int vrc = i_readDataAt(aOffset, aToRead, aTimeoutMS,
1453 &aData.front(), aToRead, &cbRead);
1454 if (RT_SUCCESS(vrc))
1455 {
1456 if (aData.size() != cbRead)
1457 aData.resize(cbRead);
1458 }
1459 else
1460 {
1461 aData.resize(0);
1462
1463 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1464 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1465 }
1466
1467 LogFlowFuncLeaveRC(vrc);
1468 return hr;
1469}
1470
1471HRESULT GuestFile::seek(LONG64 aOffset, FileSeekOrigin_T aWhence, LONG64 *aNewOffset)
1472{
1473 AutoCaller autoCaller(this);
1474 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1475
1476 HRESULT hr = S_OK;
1477
1478 GUEST_FILE_SEEKTYPE eSeekType;
1479 switch (aWhence)
1480 {
1481 case FileSeekOrigin_Begin:
1482 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1483 break;
1484
1485 case FileSeekOrigin_Current:
1486 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1487 break;
1488
1489 case FileSeekOrigin_End:
1490 eSeekType = GUEST_FILE_SEEKTYPE_END;
1491 break;
1492
1493 default:
1494 return setError(E_INVALIDARG, tr("Invalid seek type specified"));
1495 }
1496
1497 LogFlowThisFuncEnter();
1498
1499 uint64_t uNewOffset;
1500 int vrc = i_seekAt(aOffset, eSeekType,
1501 30 * 1000 /* 30s timeout */, &uNewOffset);
1502 if (RT_SUCCESS(vrc))
1503 *aNewOffset = RT_MIN(uNewOffset, (uint64_t)INT64_MAX);
1504 else
1505 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"),
1506 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1507
1508 LogFlowFuncLeaveRC(vrc);
1509 return hr;
1510}
1511
1512HRESULT GuestFile::setACL(const com::Utf8Str &aAcl, ULONG aMode)
1513{
1514 RT_NOREF(aAcl, aMode);
1515 ReturnComNotImplemented();
1516}
1517
1518HRESULT GuestFile::setSize(LONG64 aSize)
1519{
1520 RT_NOREF(aSize);
1521 ReturnComNotImplemented();
1522}
1523
1524HRESULT GuestFile::write(const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1525{
1526 AutoCaller autoCaller(this);
1527 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1528
1529 if (aData.size() == 0)
1530 return setError(E_INVALIDARG, tr("No data to write specified"));
1531
1532 LogFlowThisFuncEnter();
1533
1534 HRESULT hr = S_OK;
1535
1536 const uint32_t cbData = (uint32_t)aData.size();
1537 const void *pvData = (void *)&aData.front();
1538 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1539 if (RT_FAILURE(vrc))
1540 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
1541 aData.size(), mData.mOpenInfo.mFilename.c_str(), vrc);
1542
1543 LogFlowFuncLeaveRC(vrc);
1544 return hr;
1545}
1546
1547HRESULT GuestFile::writeAt(LONG64 aOffset, const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1548{
1549 AutoCaller autoCaller(this);
1550 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1551
1552 if (aData.size() == 0)
1553 return setError(E_INVALIDARG, tr("No data to write at specified"));
1554
1555 LogFlowThisFuncEnter();
1556
1557 HRESULT hr = S_OK;
1558
1559 const uint32_t cbData = (uint32_t)aData.size();
1560 const void *pvData = (void *)&aData.front();
1561 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1562 if (RT_FAILURE(vrc))
1563 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
1564 aData.size(), mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1565
1566 LogFlowFuncLeaveRC(vrc);
1567 return hr;
1568}
1569
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