VirtualBox

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

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

Main/GuestFileImpl.cpp: Do not fail with a bland IPRT error when a read returns zero bytes, just return a zero byte result! bugref:9320

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.7 KB
Line 
1/* $Id: GuestFileImpl.cpp 79253 2019-06-20 02:21:53Z 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 /* mData.mOffCurrent gets updated on i_readData[At]() / i_writeData[At]() file notification callbacks.
300 * So no need to take another roundtrip into the guest asking for the current offset (using tell). */
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->uMessage, pSvcCb));
336
337 int vrc;
338 switch (pCbCtx->uMessage)
339 {
340 case GUEST_MSG_DISCONNECTED:
341 vrc = i_onGuestDisconnected(pCbCtx, pSvcCb);
342 break;
343
344 case GUEST_MSG_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 *prcGuest)
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 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
386 HGCMSvcSetU32(&paParms[i++], mObjectID /* Guest file ID */);
387
388 vrc = sendMessage(HOST_MSG_FILE_CLOSE, i, paParms);
389 if (RT_SUCCESS(vrc))
390 vrc = i_waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */,
391 NULL /* FileStatus */, prcGuest);
392 unregisterWaitEvent(pEvent);
393
394 LogFlowFuncLeaveRC(vrc);
395 return vrc;
396}
397
398/* static */ const char *GuestFile::i_guestVrcToString(int rcGuest)
399{
400 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
401 switch (rcGuest)
402 {
403 case VERR_ACCESS_DENIED: return tr("Access denied");
404 case VERR_ALREADY_EXISTS: return tr("File already exists");
405 case VERR_FILE_NOT_FOUND: return tr("File not found");
406 case VERR_NET_HOST_NOT_FOUND: return tr("Host name not found");
407 case VERR_SHARING_VIOLATION: return tr("Sharing violation");
408 default: return RTErrGetDefine(rcGuest);
409 }
410}
411
412/**
413 * @todo r=bird: This is an absolutely cryptic way of reporting errors. You may convert
414 * this to a const char * returning function for explaining rcGuest and
415 * use that as part of a _proper_ error message. This alone extremely
416 * user unfriendly. E.g. which file is not found? One of the source files,
417 * a destination file, what are you referring to?!?
418 *
419 * I've addressed one of these that annoyed me, you can do the rest of them.
420 */
421/* static */ Utf8Str GuestFile::i_guestErrorToString(int rcGuest)
422{
423 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
424 return i_guestVrcToString(rcGuest);
425}
426
427int GuestFile::i_onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
428{
429 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
430 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
431
432 LogFlowThisFuncEnter();
433
434 if (pSvcCbData->mParms < 3)
435 return VERR_INVALID_PARAMETER;
436
437 int idx = 1; /* Current parameter index. */
438 CALLBACKDATA_FILE_NOTIFY dataCb;
439 /* pSvcCb->mpaParms[0] always contains the context ID. */
440 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.uType);
441 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.rc);
442
443 int rcGuest = (int)dataCb.rc; /* uint32_t vs. int. */
444
445 LogFlowThisFunc(("uType=%RU32, rcGuest=%Rrc\n", dataCb.uType, rcGuest));
446
447 if (RT_FAILURE(rcGuest))
448 {
449 int rc2 = i_setFileStatus(FileStatus_Error, rcGuest);
450 AssertRC(rc2);
451
452 /* Ignore rc, as the event to signal might not be there (anymore). */
453 signalWaitEventInternal(pCbCtx, rcGuest, NULL /* pPayload */);
454 return VINF_SUCCESS; /* Report to the guest. */
455 }
456
457 AssertMsg(mObjectID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID),
458 ("File ID %RU32 does not match object ID %RU32\n", mObjectID,
459 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));
460
461 int rc = VERR_NOT_SUPPORTED; /* Play safe by default. */
462
463 switch (dataCb.uType)
464 {
465 case GUEST_FILE_NOTIFYTYPE_ERROR:
466 {
467 rc = i_setFileStatus(FileStatus_Error, rcGuest);
468 break;
469 }
470
471 case GUEST_FILE_NOTIFYTYPE_OPEN:
472 {
473 if (pSvcCbData->mParms == 4)
474 {
475 rc = HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.u.open.uHandle);
476 if (RT_FAILURE(rc))
477 break;
478
479 /* Set the process status. */
480 rc = i_setFileStatus(FileStatus_Open, rcGuest);
481 }
482 break;
483 }
484
485 case GUEST_FILE_NOTIFYTYPE_CLOSE:
486 {
487 rc = i_setFileStatus(FileStatus_Closed, rcGuest);
488 break;
489 }
490
491 case GUEST_FILE_NOTIFYTYPE_READ:
492 {
493 if (pSvcCbData->mParms == 4)
494 {
495 rc = HGCMSvcGetPv(&pSvcCbData->mpaParms[idx++], &dataCb.u.read.pvData,
496 &dataCb.u.read.cbData);
497 if (RT_FAILURE(rc))
498 break;
499
500 const uint32_t cbRead = dataCb.u.read.cbData;
501
502 Log3ThisFunc(("cbRead=%RU32\n", cbRead));
503
504 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
505
506 mData.mOffCurrent += cbRead;
507
508 alock.release();
509
510 com::SafeArray<BYTE> data((size_t)cbRead);
511 data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead);
512
513 fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent,
514 cbRead, ComSafeArrayAsInParam(data));
515 }
516 break;
517 }
518
519 case GUEST_FILE_NOTIFYTYPE_WRITE:
520 {
521 if (pSvcCbData->mParms == 4)
522 {
523 rc = HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.u.write.cbWritten);
524 if (RT_FAILURE(rc))
525 break;
526
527 const uint32_t cbWritten = dataCb.u.write.cbWritten;
528
529 Log3ThisFunc(("cbWritten=%RU32\n", cbWritten));
530
531 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
532
533 mData.mOffCurrent += cbWritten;
534
535 alock.release();
536
537 fireGuestFileWriteEvent(mEventSource, mSession, this, mData.mOffCurrent, cbWritten);
538 }
539 break;
540 }
541
542 case GUEST_FILE_NOTIFYTYPE_SEEK:
543 {
544 if (pSvcCbData->mParms == 4)
545 {
546 rc = HGCMSvcGetU64(&pSvcCbData->mpaParms[idx++], &dataCb.u.seek.uOffActual);
547 if (RT_FAILURE(rc))
548 break;
549
550 Log3ThisFunc(("uOffActual=%RU64\n", dataCb.u.seek.uOffActual));
551
552 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
553
554 mData.mOffCurrent = dataCb.u.seek.uOffActual;
555
556 alock.release();
557
558 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, mData.mOffCurrent, 0 /* Processed */);
559 }
560 break;
561 }
562
563 case GUEST_FILE_NOTIFYTYPE_TELL:
564 {
565 if (pSvcCbData->mParms == 4)
566 {
567 rc = HGCMSvcGetU64(&pSvcCbData->mpaParms[idx++], &dataCb.u.tell.uOffActual);
568 if (RT_FAILURE(rc))
569 break;
570
571 Log3ThisFunc(("uOffActual=%RU64\n", dataCb.u.tell.uOffActual));
572
573 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
574
575 mData.mOffCurrent = dataCb.u.tell.uOffActual;
576
577 alock.release();
578
579 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, mData.mOffCurrent, 0 /* Processed */);
580 }
581 break;
582 }
583
584 default:
585 break;
586 }
587
588 if (RT_SUCCESS(rc))
589 {
590 GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb));
591
592 /* Ignore rc, as the event to signal might not be there (anymore). */
593 signalWaitEventInternal(pCbCtx, rcGuest, &payload);
594 }
595
596 LogFlowThisFunc(("uType=%RU32, rcGuest=%Rrc, rc=%Rrc\n", dataCb.uType, rcGuest, rc));
597 return rc;
598}
599
600int GuestFile::i_onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
601{
602 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
603 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
604
605 int vrc = i_setFileStatus(FileStatus_Down, VINF_SUCCESS);
606
607 LogFlowFuncLeaveRC(vrc);
608 return vrc;
609}
610
611/**
612 * @copydoc GuestObject::i_onUnregister
613 */
614int GuestFile::i_onUnregister(void)
615{
616 LogFlowThisFuncEnter();
617
618 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
619
620 int vrc = VINF_SUCCESS;
621
622 /*
623 * Note: The event source stuff holds references to this object,
624 * so make sure that this is cleaned up *before* calling uninit().
625 */
626 if (!mEventSource.isNull())
627 {
628 mEventSource->UnregisterListener(mLocalListener);
629
630 mLocalListener.setNull();
631 unconst(mEventSource).setNull();
632 }
633
634 LogFlowFuncLeaveRC(vrc);
635 return vrc;
636}
637
638/**
639 * @copydoc GuestObject::i_onSessionStatusChange
640 */
641int GuestFile::i_onSessionStatusChange(GuestSessionStatus_T enmSessionStatus)
642{
643 LogFlowThisFuncEnter();
644
645 int vrc = VINF_SUCCESS;
646
647 /* If the session now is in a terminated state, set the file status
648 * to "down", as there is not much else we can do now. */
649 if (GuestSession::i_isTerminated(enmSessionStatus))
650 vrc = i_setFileStatus(FileStatus_Down, 0 /* fileRc, ignored */);
651
652 LogFlowFuncLeaveRC(vrc);
653 return vrc;
654}
655
656int GuestFile::i_openFile(uint32_t uTimeoutMS, int *prcGuest)
657{
658 AssertReturn(mData.mOpenInfo.mFilename.isNotEmpty(), VERR_INVALID_PARAMETER);
659
660 LogFlowThisFuncEnter();
661
662 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
663
664 LogFlowThisFunc(("strFile=%s, enmAccessMode=0x%x, enmOpenAction=0x%x, uCreationMode=%RU32, mfOpenEx=%RU32\n",
665 mData.mOpenInfo.mFilename.c_str(), mData.mOpenInfo.mAccessMode, mData.mOpenInfo.mOpenAction,
666 mData.mOpenInfo.mCreationMode, mData.mOpenInfo.mfOpenEx));
667
668 /* Validate and translate open action. */
669 const char *pszOpenAction = NULL;
670 switch (mData.mOpenInfo.mOpenAction)
671 {
672 case FileOpenAction_OpenExisting: pszOpenAction = "oe"; break;
673 case FileOpenAction_OpenOrCreate: pszOpenAction = "oc"; break;
674 case FileOpenAction_CreateNew: pszOpenAction = "ce"; break;
675 case FileOpenAction_CreateOrReplace: pszOpenAction = "ca"; break;
676 case FileOpenAction_OpenExistingTruncated: pszOpenAction = "ot"; break;
677 case FileOpenAction_AppendOrCreate:
678 pszOpenAction = "oa"; /** @todo get rid of this one and implement AppendOnly/AppendRead. */
679 break;
680 default:
681 return VERR_INVALID_PARAMETER;
682 }
683
684 /* Validate and translate access mode. */
685 const char *pszAccessMode = NULL;
686 switch (mData.mOpenInfo.mAccessMode)
687 {
688 case FileAccessMode_ReadOnly: pszAccessMode = "r"; break;
689 case FileAccessMode_WriteOnly: pszAccessMode = "w"; break;
690 case FileAccessMode_ReadWrite: pszAccessMode = "r+"; break;
691 case FileAccessMode_AppendOnly: RT_FALL_THRU();
692 case FileAccessMode_AppendRead: return VERR_NOT_IMPLEMENTED;
693 default: return VERR_INVALID_PARAMETER;
694 }
695
696 /* Validate and translate sharing mode. */
697 const char *pszSharingMode = NULL;
698 switch (mData.mOpenInfo.mSharingMode)
699 {
700 case FileSharingMode_All: pszSharingMode = ""; break;
701 case FileSharingMode_Read: RT_FALL_THRU();
702 case FileSharingMode_Write: RT_FALL_THRU();
703 case FileSharingMode_ReadWrite: RT_FALL_THRU();
704 case FileSharingMode_Delete: RT_FALL_THRU();
705 case FileSharingMode_ReadDelete: RT_FALL_THRU();
706 case FileSharingMode_WriteDelete: return VERR_NOT_IMPLEMENTED;
707 default: return VERR_INVALID_PARAMETER;
708 }
709
710 int vrc;
711
712 GuestWaitEvent *pEvent = NULL;
713 GuestEventTypes eventTypes;
714 try
715 {
716 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
717
718 vrc = registerWaitEvent(eventTypes, &pEvent);
719 }
720 catch (std::bad_alloc &)
721 {
722 vrc = VERR_NO_MEMORY;
723 }
724
725 if (RT_FAILURE(vrc))
726 return vrc;
727
728 /* Prepare HGCM call. */
729 VBOXHGCMSVCPARM paParms[8];
730 int i = 0;
731 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
732 HGCMSvcSetPv(&paParms[i++], (void*)mData.mOpenInfo.mFilename.c_str(),
733 (ULONG)mData.mOpenInfo.mFilename.length() + 1);
734 HGCMSvcSetStr(&paParms[i++], pszAccessMode);
735 HGCMSvcSetStr(&paParms[i++], pszOpenAction);
736 HGCMSvcSetStr(&paParms[i++], pszSharingMode);
737 HGCMSvcSetU32(&paParms[i++], mData.mOpenInfo.mCreationMode);
738 HGCMSvcSetU64(&paParms[i++], mData.mOpenInfo.muOffset);
739 /** @todo Next protocol version: add flags, replace strings, remove initial offset. */
740
741 alock.release(); /* Drop write lock before sending. */
742
743 vrc = sendMessage(HOST_MSG_FILE_OPEN, i, paParms);
744 if (RT_SUCCESS(vrc))
745 vrc = i_waitForStatusChange(pEvent, uTimeoutMS, NULL /* FileStatus */, prcGuest);
746
747 unregisterWaitEvent(pEvent);
748
749 LogFlowFuncLeaveRC(vrc);
750 return vrc;
751}
752
753int GuestFile::i_queryInfo(GuestFsObjData &objData, int *prcGuest)
754{
755 AssertPtr(mSession);
756 return mSession->i_fsQueryInfo(mData.mOpenInfo.mFilename, FALSE /* fFollowSymlinks */, objData, prcGuest);
757}
758
759int GuestFile::i_readData(uint32_t uSize, uint32_t uTimeoutMS,
760 void* pvData, uint32_t cbData, uint32_t* pcbRead)
761{
762 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
763 AssertReturn(cbData, VERR_INVALID_PARAMETER);
764
765 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
766 uSize, uTimeoutMS, pvData, cbData));
767
768 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
769
770 int vrc;
771
772 GuestWaitEvent *pEvent = NULL;
773 GuestEventTypes eventTypes;
774 try
775 {
776 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
777 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
778
779 vrc = registerWaitEvent(eventTypes, &pEvent);
780 }
781 catch (std::bad_alloc &)
782 {
783 vrc = VERR_NO_MEMORY;
784 }
785
786 if (RT_FAILURE(vrc))
787 return vrc;
788
789 /* Prepare HGCM call. */
790 VBOXHGCMSVCPARM paParms[4];
791 int i = 0;
792 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
793 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
794 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
795
796 alock.release(); /* Drop write lock before sending. */
797
798 vrc = sendMessage(HOST_MSG_FILE_READ, i, paParms);
799 if (RT_SUCCESS(vrc))
800 {
801 uint32_t cbRead = 0;
802 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
803 if (RT_SUCCESS(vrc))
804 {
805 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
806 if (pcbRead)
807 *pcbRead = cbRead;
808 }
809 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
810 {
811 vrc = pEvent->GetGuestError();
812 }
813 }
814
815 unregisterWaitEvent(pEvent);
816
817 LogFlowFuncLeaveRC(vrc);
818 return vrc;
819}
820
821int GuestFile::i_readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
822 void* pvData, size_t cbData, size_t* pcbRead)
823{
824 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
825 uOffset, uSize, uTimeoutMS, pvData, cbData));
826
827 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
828
829 int vrc;
830
831 GuestWaitEvent *pEvent = NULL;
832 GuestEventTypes eventTypes;
833 try
834 {
835 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
836 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
837
838 vrc = registerWaitEvent(eventTypes, &pEvent);
839 }
840 catch (std::bad_alloc &)
841 {
842 vrc = VERR_NO_MEMORY;
843 }
844
845 if (RT_FAILURE(vrc))
846 return vrc;
847
848 /* Prepare HGCM call. */
849 VBOXHGCMSVCPARM paParms[4];
850 int i = 0;
851 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
852 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
853 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset (in bytes) to start reading */);
854 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
855
856 alock.release(); /* Drop write lock before sending. */
857
858 vrc = sendMessage(HOST_MSG_FILE_READ_AT, i, paParms);
859 if (RT_SUCCESS(vrc))
860 {
861 uint32_t cbRead = 0;
862 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
863 if (RT_SUCCESS(vrc))
864 {
865 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
866
867 if (pcbRead)
868 *pcbRead = cbRead;
869 }
870 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
871 {
872 vrc = pEvent->GetGuestError();
873 }
874 }
875
876 unregisterWaitEvent(pEvent);
877
878 LogFlowFuncLeaveRC(vrc);
879 return vrc;
880}
881
882int GuestFile::i_seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType,
883 uint32_t uTimeoutMS, uint64_t *puOffset)
884{
885 LogFlowThisFunc(("iOffset=%RI64, uTimeoutMS=%RU32\n",
886 iOffset, uTimeoutMS));
887
888 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
889
890 int vrc;
891
892 GuestWaitEvent *pEvent = NULL;
893 GuestEventTypes eventTypes;
894 try
895 {
896 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
897 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
898
899 vrc = registerWaitEvent(eventTypes, &pEvent);
900 }
901 catch (std::bad_alloc &)
902 {
903 vrc = VERR_NO_MEMORY;
904 }
905
906 if (RT_FAILURE(vrc))
907 return vrc;
908
909 /* Prepare HGCM call. */
910 VBOXHGCMSVCPARM paParms[4];
911 int i = 0;
912 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
913 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
914 HGCMSvcSetU32(&paParms[i++], eSeekType /* Seek method */);
915 /** @todo uint64_t vs. int64_t! */
916 HGCMSvcSetU64(&paParms[i++], (uint64_t)iOffset /* Offset (in bytes) to start reading */);
917
918 alock.release(); /* Drop write lock before sending. */
919
920 vrc = sendMessage(HOST_MSG_FILE_SEEK, i, paParms);
921 if (RT_SUCCESS(vrc))
922 {
923 uint64_t uOffset;
924 vrc = i_waitForOffsetChange(pEvent, uTimeoutMS, &uOffset);
925 if (RT_SUCCESS(vrc))
926 {
927 LogFlowThisFunc(("uOffset=%RU64\n", uOffset));
928
929 if (puOffset)
930 *puOffset = uOffset;
931 }
932 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
933 {
934 vrc = pEvent->GetGuestError();
935 }
936 }
937
938 unregisterWaitEvent(pEvent);
939
940 LogFlowFuncLeaveRC(vrc);
941 return vrc;
942}
943
944/* static */
945HRESULT GuestFile::i_setErrorExternal(VirtualBoxBase *pInterface, int rcGuest)
946{
947 AssertPtr(pInterface);
948 AssertMsg(RT_FAILURE(rcGuest), ("Guest rc does not indicate a failure when setting error\n"));
949
950 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestFile::i_guestErrorToString(rcGuest).c_str());
951}
952
953int GuestFile::i_setFileStatus(FileStatus_T fileStatus, int fileRc)
954{
955 LogFlowThisFuncEnter();
956
957 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
958
959 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, fileRc=%Rrc\n",
960 mData.mStatus, fileStatus, fileRc));
961
962#ifdef VBOX_STRICT
963 if (fileStatus == FileStatus_Error)
964 {
965 AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc));
966 }
967 else
968 AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc));
969#endif
970
971 if (mData.mStatus != fileStatus)
972 {
973 mData.mStatus = fileStatus;
974 mData.mLastError = fileRc;
975
976 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
977 HRESULT hr = errorInfo.createObject();
978 ComAssertComRC(hr);
979 if (RT_FAILURE(fileRc))
980 {
981 hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, fileRc,
982 COM_IIDOF(IGuestFile), getComponentName(),
983 i_guestErrorToString(fileRc));
984 ComAssertComRC(hr);
985 }
986
987 alock.release(); /* Release lock before firing off event. */
988
989 fireGuestFileStateChangedEvent(mEventSource, mSession,
990 this, fileStatus, errorInfo);
991 }
992
993 return VINF_SUCCESS;
994}
995
996int GuestFile::i_waitForOffsetChange(GuestWaitEvent *pEvent,
997 uint32_t uTimeoutMS, uint64_t *puOffset)
998{
999 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1000
1001 VBoxEventType_T evtType;
1002 ComPtr<IEvent> pIEvent;
1003 int vrc = waitForEvent(pEvent, uTimeoutMS,
1004 &evtType, pIEvent.asOutParam());
1005 if (RT_SUCCESS(vrc))
1006 {
1007 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
1008 {
1009 if (puOffset)
1010 {
1011 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
1012 Assert(!pFileEvent.isNull());
1013
1014 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
1015 ComAssertComRC(hr);
1016 }
1017 }
1018 else
1019 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1020 }
1021
1022 return vrc;
1023}
1024
1025int GuestFile::i_waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1026 void *pvData, size_t cbData, uint32_t *pcbRead)
1027{
1028 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1029
1030 VBoxEventType_T evtType;
1031 ComPtr<IEvent> pIEvent;
1032 int vrc = waitForEvent(pEvent, uTimeoutMS,
1033 &evtType, pIEvent.asOutParam());
1034 if (RT_SUCCESS(vrc))
1035 {
1036 if (evtType == VBoxEventType_OnGuestFileRead)
1037 {
1038 vrc = VINF_SUCCESS;
1039
1040 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
1041 Assert(!pFileEvent.isNull());
1042
1043 if (pvData)
1044 {
1045 com::SafeArray <BYTE> data;
1046 HRESULT hrc1 = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1047 ComAssertComRC(hrc1);
1048 const size_t cbRead = data.size();
1049 if (cbRead)
1050 {
1051 if (cbRead <= cbData)
1052 memcpy(pvData, data.raw(), cbRead);
1053 else
1054 vrc = VERR_BUFFER_OVERFLOW;
1055 }
1056 /* else: used to be VERR_NO_DATA, but that messes stuff up. */
1057
1058 if (pcbRead)
1059 {
1060 *pcbRead = (uint32_t)cbRead;
1061 Assert(*pcbRead == cbRead);
1062 }
1063 }
1064 else if (pcbRead)
1065 {
1066 *pcbRead = 0;
1067 HRESULT hrc2 = pFileEvent->COMGETTER(Processed)((ULONG *)pcbRead);
1068 ComAssertComRC(hrc2); NOREF(hrc2);
1069 }
1070 }
1071 else
1072 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1073 }
1074
1075 return vrc;
1076}
1077
1078/**
1079 * Undocumented, use with great care.
1080 *
1081 * @note Similar code in GuestProcess::i_waitForStatusChange() and
1082 * GuestSession::i_waitForStatusChange().
1083 */
1084int GuestFile::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1085 FileStatus_T *pFileStatus, int *prcGuest)
1086{
1087 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1088 /* pFileStatus is optional. */
1089
1090 VBoxEventType_T evtType;
1091 ComPtr<IEvent> pIEvent;
1092 int vrc = waitForEvent(pEvent, uTimeoutMS,
1093 &evtType, pIEvent.asOutParam());
1094 if (RT_SUCCESS(vrc))
1095 {
1096 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
1097 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
1098 Assert(!pFileEvent.isNull());
1099
1100 HRESULT hr;
1101 if (pFileStatus)
1102 {
1103 hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1104 ComAssertComRC(hr);
1105 }
1106
1107 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1108 hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam());
1109 ComAssertComRC(hr);
1110
1111 LONG lGuestRc;
1112 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1113 ComAssertComRC(hr);
1114
1115 LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n",
1116 lGuestRc, lGuestRc));
1117
1118 if (RT_FAILURE((int)lGuestRc))
1119 vrc = VERR_GSTCTL_GUEST_ERROR;
1120
1121 if (prcGuest)
1122 *prcGuest = (int)lGuestRc;
1123 }
1124 /* waitForEvent may also return VERR_GSTCTL_GUEST_ERROR like we do above, so make prcGuest is set. */
1125 /** @todo r=bird: Andy, you seem to have forgotten this scenario. Showed up occasionally when
1126 * using the wrong password with a copyto command in a debug build on windows, error info
1127 * contained "Unknown Status -858993460 (0xcccccccc)". As you know windows fills the stack frames
1128 * with 0xcccccccc in debug builds to highlight use of uninitialized data, so that's what happened
1129 * here. It's actually good you didn't initialize lGuest, as it would be heck to find otherwise.
1130 *
1131 * I'm still not very impressed with the error managment or the usuefullness of the documentation
1132 * in this code, though the latter is getting better! */
1133 else if (vrc == VERR_GSTCTL_GUEST_ERROR && prcGuest)
1134 *prcGuest = pEvent->GuestResult();
1135 Assert(vrc != VERR_GSTCTL_GUEST_ERROR || !prcGuest || *prcGuest != (int)0xcccccccc);
1136
1137 return vrc;
1138}
1139
1140int GuestFile::i_waitForWrite(GuestWaitEvent *pEvent,
1141 uint32_t uTimeoutMS, uint32_t *pcbWritten)
1142{
1143 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1144
1145 VBoxEventType_T evtType;
1146 ComPtr<IEvent> pIEvent;
1147 int vrc = waitForEvent(pEvent, uTimeoutMS,
1148 &evtType, pIEvent.asOutParam());
1149 if (RT_SUCCESS(vrc))
1150 {
1151 if (evtType == VBoxEventType_OnGuestFileWrite)
1152 {
1153 if (pcbWritten)
1154 {
1155 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1156 Assert(!pFileEvent.isNull());
1157
1158 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1159 ComAssertComRC(hr);
1160 }
1161 }
1162 else
1163 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1164 }
1165
1166 return vrc;
1167}
1168
1169int GuestFile::i_writeData(uint32_t uTimeoutMS, const void *pvData, uint32_t cbData,
1170 uint32_t *pcbWritten)
1171{
1172 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1173 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1174
1175 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1176 uTimeoutMS, pvData, cbData));
1177
1178 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1179
1180 int vrc;
1181
1182 GuestWaitEvent *pEvent = NULL;
1183 GuestEventTypes eventTypes;
1184 try
1185 {
1186 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1187 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1188
1189 vrc = registerWaitEvent(eventTypes, &pEvent);
1190 }
1191 catch (std::bad_alloc &)
1192 {
1193 vrc = VERR_NO_MEMORY;
1194 }
1195
1196 if (RT_FAILURE(vrc))
1197 return vrc;
1198
1199 /* Prepare HGCM call. */
1200 VBOXHGCMSVCPARM paParms[8];
1201 int i = 0;
1202 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1203 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1204 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
1205 HGCMSvcSetPv (&paParms[i++], unconst(pvData), cbData);
1206
1207 alock.release(); /* Drop write lock before sending. */
1208
1209 vrc = sendMessage(HOST_MSG_FILE_WRITE, i, paParms);
1210 if (RT_SUCCESS(vrc))
1211 {
1212 uint32_t cbWritten = 0;
1213 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1214 if (RT_SUCCESS(vrc))
1215 {
1216 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1217 if (pcbWritten)
1218 *pcbWritten = cbWritten;
1219 }
1220 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1221 {
1222 vrc = pEvent->GetGuestError();
1223 }
1224 }
1225
1226 unregisterWaitEvent(pEvent);
1227
1228 LogFlowFuncLeaveRC(vrc);
1229 return vrc;
1230}
1231
1232int GuestFile::i_writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
1233 const void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1234{
1235 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1236 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1237
1238 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1239 uOffset, uTimeoutMS, pvData, cbData));
1240
1241 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1242
1243 int vrc;
1244
1245 GuestWaitEvent *pEvent = NULL;
1246 GuestEventTypes eventTypes;
1247 try
1248 {
1249 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1250 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1251
1252 vrc = registerWaitEvent(eventTypes, &pEvent);
1253 }
1254 catch (std::bad_alloc &)
1255 {
1256 vrc = VERR_NO_MEMORY;
1257 }
1258
1259 if (RT_FAILURE(vrc))
1260 return vrc;
1261
1262 /* Prepare HGCM call. */
1263 VBOXHGCMSVCPARM paParms[8];
1264 int i = 0;
1265 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1266 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1267 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset where to starting writing */);
1268 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
1269 HGCMSvcSetPv (&paParms[i++], unconst(pvData), cbData);
1270
1271 alock.release(); /* Drop write lock before sending. */
1272
1273 vrc = sendMessage(HOST_MSG_FILE_WRITE_AT, i, paParms);
1274 if (RT_SUCCESS(vrc))
1275 {
1276 uint32_t cbWritten = 0;
1277 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1278 if (RT_SUCCESS(vrc))
1279 {
1280 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1281 if (pcbWritten)
1282 *pcbWritten = cbWritten;
1283 }
1284 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1285 {
1286 vrc = pEvent->GetGuestError();
1287 }
1288 }
1289
1290 unregisterWaitEvent(pEvent);
1291
1292 LogFlowFuncLeaveRC(vrc);
1293 return vrc;
1294}
1295
1296// Wrapped IGuestFile methods
1297/////////////////////////////////////////////////////////////////////////////
1298HRESULT GuestFile::close()
1299{
1300 AutoCaller autoCaller(this);
1301 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1302
1303 LogFlowThisFuncEnter();
1304
1305 /* Close file on guest. */
1306 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1307 int vrc = i_closeFile(&rcGuest);
1308 /* On failure don't return here, instead do all the cleanup
1309 * work first and then return an error. */
1310
1311 AssertPtr(mSession);
1312 int vrc2 = mSession->i_fileUnregister(this);
1313 if (RT_SUCCESS(vrc))
1314 vrc = vrc2;
1315
1316 if (RT_FAILURE(vrc))
1317 {
1318 if (vrc == VERR_GSTCTL_GUEST_ERROR)
1319 return GuestFile::i_setErrorExternal(this, rcGuest);
1320 return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Closing guest file failed with %Rrc\n"), vrc);
1321 }
1322
1323 LogFlowThisFunc(("Returning S_OK / vrc=%Rrc\n", vrc));
1324 return S_OK;
1325}
1326
1327HRESULT GuestFile::queryInfo(ComPtr<IFsObjInfo> &aObjInfo)
1328{
1329 AutoCaller autoCaller(this);
1330 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1331
1332 LogFlowThisFuncEnter();
1333
1334 HRESULT hr = S_OK;
1335
1336 GuestFsObjData fsObjData;
1337 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1338 int vrc = i_queryInfo(fsObjData, &rcGuest);
1339 if (RT_SUCCESS(vrc))
1340 {
1341 ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
1342 hr = ptrFsObjInfo.createObject();
1343 if (SUCCEEDED(hr))
1344 {
1345 vrc = ptrFsObjInfo->init(fsObjData);
1346 if (RT_SUCCESS(vrc))
1347 hr = ptrFsObjInfo.queryInterfaceTo(aObjInfo.asOutParam());
1348 else
1349 hr = setErrorVrc(vrc);
1350 }
1351 }
1352 else
1353 {
1354 if (GuestProcess::i_isGuestError(vrc))
1355 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1356 else
1357 hr = setErrorVrc(vrc, tr("Querying file information failed: %Rrc"), vrc);
1358 }
1359
1360 LogFlowFuncLeaveRC(vrc);
1361 return hr;
1362}
1363
1364HRESULT GuestFile::querySize(LONG64 *aSize)
1365{
1366 AutoCaller autoCaller(this);
1367 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1368
1369 LogFlowThisFuncEnter();
1370
1371 HRESULT hr = S_OK;
1372
1373 GuestFsObjData fsObjData;
1374 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1375 int vrc = i_queryInfo(fsObjData, &rcGuest);
1376 if (RT_SUCCESS(vrc))
1377 {
1378 *aSize = fsObjData.mObjectSize;
1379 }
1380 else
1381 {
1382 if (GuestProcess::i_isGuestError(vrc))
1383 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1384 else
1385 hr = setErrorVrc(vrc, tr("Querying file size failed: %Rrc"), vrc);
1386 }
1387
1388 LogFlowFuncLeaveRC(vrc);
1389 return hr;
1390}
1391
1392HRESULT GuestFile::read(ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1393{
1394 AutoCaller autoCaller(this);
1395 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1396
1397 if (aToRead == 0)
1398 return setError(E_INVALIDARG, tr("The size to read is zero"));
1399
1400 LogFlowThisFuncEnter();
1401
1402 aData.resize(aToRead);
1403
1404 HRESULT hr = S_OK;
1405
1406 uint32_t cbRead;
1407 int vrc = i_readData(aToRead, aTimeoutMS,
1408 &aData.front(), aToRead, &cbRead);
1409
1410 if (RT_SUCCESS(vrc))
1411 {
1412 if (aData.size() != cbRead)
1413 aData.resize(cbRead);
1414 }
1415 else
1416 {
1417 aData.resize(0);
1418
1419 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" failed: %Rrc"),
1420 mData.mOpenInfo.mFilename.c_str(), vrc);
1421 }
1422
1423 LogFlowFuncLeaveRC(vrc);
1424 return hr;
1425}
1426
1427HRESULT GuestFile::readAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1428{
1429 AutoCaller autoCaller(this);
1430 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1431
1432 if (aToRead == 0)
1433 return setError(E_INVALIDARG, tr("The size to read is zero"));
1434
1435 LogFlowThisFuncEnter();
1436
1437 aData.resize(aToRead);
1438
1439 HRESULT hr = S_OK;
1440
1441 size_t cbRead;
1442 int vrc = i_readDataAt(aOffset, aToRead, aTimeoutMS,
1443 &aData.front(), aToRead, &cbRead);
1444 if (RT_SUCCESS(vrc))
1445 {
1446 if (aData.size() != cbRead)
1447 aData.resize(cbRead);
1448 }
1449 else
1450 {
1451 aData.resize(0);
1452
1453 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1454 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1455 }
1456
1457 LogFlowFuncLeaveRC(vrc);
1458 return hr;
1459}
1460
1461HRESULT GuestFile::seek(LONG64 aOffset, FileSeekOrigin_T aWhence, LONG64 *aNewOffset)
1462{
1463 AutoCaller autoCaller(this);
1464 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1465
1466 HRESULT hr = S_OK;
1467
1468 GUEST_FILE_SEEKTYPE eSeekType;
1469 switch (aWhence)
1470 {
1471 case FileSeekOrigin_Begin:
1472 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1473 break;
1474
1475 case FileSeekOrigin_Current:
1476 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1477 break;
1478
1479 case FileSeekOrigin_End:
1480 eSeekType = GUEST_FILE_SEEKTYPE_END;
1481 break;
1482
1483 default:
1484 return setError(E_INVALIDARG, tr("Invalid seek type specified"));
1485 }
1486
1487 LogFlowThisFuncEnter();
1488
1489 uint64_t uNewOffset;
1490 int vrc = i_seekAt(aOffset, eSeekType,
1491 30 * 1000 /* 30s timeout */, &uNewOffset);
1492 if (RT_SUCCESS(vrc))
1493 *aNewOffset = RT_MIN(uNewOffset, (uint64_t)INT64_MAX);
1494 else
1495 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"),
1496 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1497
1498 LogFlowFuncLeaveRC(vrc);
1499 return hr;
1500}
1501
1502HRESULT GuestFile::setACL(const com::Utf8Str &aAcl, ULONG aMode)
1503{
1504 RT_NOREF(aAcl, aMode);
1505 ReturnComNotImplemented();
1506}
1507
1508HRESULT GuestFile::setSize(LONG64 aSize)
1509{
1510 RT_NOREF(aSize);
1511 ReturnComNotImplemented();
1512}
1513
1514HRESULT GuestFile::write(const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1515{
1516 AutoCaller autoCaller(this);
1517 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1518
1519 if (aData.size() == 0)
1520 return setError(E_INVALIDARG, tr("No data to write specified"));
1521
1522 LogFlowThisFuncEnter();
1523
1524 HRESULT hr = S_OK;
1525
1526 const uint32_t cbData = (uint32_t)aData.size();
1527 const void *pvData = (void *)&aData.front();
1528 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1529 if (RT_FAILURE(vrc))
1530 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
1531 aData.size(), mData.mOpenInfo.mFilename.c_str(), vrc);
1532
1533 LogFlowFuncLeaveRC(vrc);
1534 return hr;
1535}
1536
1537HRESULT GuestFile::writeAt(LONG64 aOffset, const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1538{
1539 AutoCaller autoCaller(this);
1540 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1541
1542 if (aData.size() == 0)
1543 return setError(E_INVALIDARG, tr("No data to write at specified"));
1544
1545 LogFlowThisFuncEnter();
1546
1547 HRESULT hr = S_OK;
1548
1549 const uint32_t cbData = (uint32_t)aData.size();
1550 const void *pvData = (void *)&aData.front();
1551 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1552 if (RT_FAILURE(vrc))
1553 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
1554 aData.size(), mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1555
1556 LogFlowFuncLeaveRC(vrc);
1557 return hr;
1558}
1559
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