VirtualBox

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

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

Main/Guest*: Must always initalize rcGuest because experience inddicates that the code handling it cannot always be depended upon to set it. bugref:9320

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.4 KB
Line 
1/* $Id: GuestFileImpl.cpp 79189 2019-06-17 16:04:55Z 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 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
1039 Assert(!pFileEvent.isNull());
1040
1041 HRESULT hr;
1042 if (pvData)
1043 {
1044 com::SafeArray <BYTE> data;
1045 hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1046 ComAssertComRC(hr);
1047 const size_t cbRead = data.size();
1048 if (cbRead)
1049 {
1050 if (cbRead <= cbData)
1051 memcpy(pvData, data.raw(), cbRead);
1052 else
1053 vrc = VERR_BUFFER_OVERFLOW;
1054 }
1055 else
1056 vrc = VERR_NO_DATA;
1057 }
1058 if (pcbRead)
1059 {
1060 hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
1061 ComAssertComRC(hr);
1062 }
1063 }
1064 else
1065 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1066 }
1067
1068 return vrc;
1069}
1070
1071/**
1072 * Undocumented, use with great care.
1073 *
1074 * @note Similar code in GuestProcess::i_waitForStatusChange() and
1075 * GuestSession::i_waitForStatusChange().
1076 */
1077int GuestFile::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1078 FileStatus_T *pFileStatus, int *prcGuest)
1079{
1080 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1081 /* pFileStatus is optional. */
1082
1083 VBoxEventType_T evtType;
1084 ComPtr<IEvent> pIEvent;
1085 int vrc = waitForEvent(pEvent, uTimeoutMS,
1086 &evtType, pIEvent.asOutParam());
1087 if (RT_SUCCESS(vrc))
1088 {
1089 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
1090 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
1091 Assert(!pFileEvent.isNull());
1092
1093 HRESULT hr;
1094 if (pFileStatus)
1095 {
1096 hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1097 ComAssertComRC(hr);
1098 }
1099
1100 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1101 hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam());
1102 ComAssertComRC(hr);
1103
1104 LONG lGuestRc;
1105 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1106 ComAssertComRC(hr);
1107
1108 LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n",
1109 lGuestRc, lGuestRc));
1110
1111 if (RT_FAILURE((int)lGuestRc))
1112 vrc = VERR_GSTCTL_GUEST_ERROR;
1113
1114 if (prcGuest)
1115 *prcGuest = (int)lGuestRc;
1116 }
1117 /* waitForEvent may also return VERR_GSTCTL_GUEST_ERROR like we do above, so make prcGuest is set. */
1118 /** @todo r=bird: Andy, you seem to have forgotten this scenario. Showed up occasionally when
1119 * using the wrong password with a copyto command in a debug build on windows, error info
1120 * contained "Unknown Status -858993460 (0xcccccccc)". As you know windows fills the stack frames
1121 * with 0xcccccccc in debug builds to highlight use of uninitialized data, so that's what happened
1122 * here. It's actually good you didn't initialize lGuest, as it would be heck to find otherwise.
1123 *
1124 * I'm still not very impressed with the error managment or the usuefullness of the documentation
1125 * in this code, though the latter is getting better! */
1126 else if (vrc == VERR_GSTCTL_GUEST_ERROR && prcGuest)
1127 *prcGuest = pEvent->GuestResult();
1128 Assert(vrc != VERR_GSTCTL_GUEST_ERROR || !prcGuest || *prcGuest != (int)0xcccccccc);
1129
1130 return vrc;
1131}
1132
1133int GuestFile::i_waitForWrite(GuestWaitEvent *pEvent,
1134 uint32_t uTimeoutMS, uint32_t *pcbWritten)
1135{
1136 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1137
1138 VBoxEventType_T evtType;
1139 ComPtr<IEvent> pIEvent;
1140 int vrc = waitForEvent(pEvent, uTimeoutMS,
1141 &evtType, pIEvent.asOutParam());
1142 if (RT_SUCCESS(vrc))
1143 {
1144 if (evtType == VBoxEventType_OnGuestFileWrite)
1145 {
1146 if (pcbWritten)
1147 {
1148 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1149 Assert(!pFileEvent.isNull());
1150
1151 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1152 ComAssertComRC(hr);
1153 }
1154 }
1155 else
1156 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1157 }
1158
1159 return vrc;
1160}
1161
1162int GuestFile::i_writeData(uint32_t uTimeoutMS, const void *pvData, uint32_t cbData,
1163 uint32_t *pcbWritten)
1164{
1165 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1166 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1167
1168 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1169 uTimeoutMS, pvData, cbData));
1170
1171 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1172
1173 int vrc;
1174
1175 GuestWaitEvent *pEvent = NULL;
1176 GuestEventTypes eventTypes;
1177 try
1178 {
1179 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1180 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1181
1182 vrc = registerWaitEvent(eventTypes, &pEvent);
1183 }
1184 catch (std::bad_alloc &)
1185 {
1186 vrc = VERR_NO_MEMORY;
1187 }
1188
1189 if (RT_FAILURE(vrc))
1190 return vrc;
1191
1192 /* Prepare HGCM call. */
1193 VBOXHGCMSVCPARM paParms[8];
1194 int i = 0;
1195 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1196 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1197 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
1198 HGCMSvcSetPv (&paParms[i++], unconst(pvData), cbData);
1199
1200 alock.release(); /* Drop write lock before sending. */
1201
1202 vrc = sendMessage(HOST_MSG_FILE_WRITE, i, paParms);
1203 if (RT_SUCCESS(vrc))
1204 {
1205 uint32_t cbWritten = 0;
1206 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1207 if (RT_SUCCESS(vrc))
1208 {
1209 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1210 if (pcbWritten)
1211 *pcbWritten = cbWritten;
1212 }
1213 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1214 {
1215 vrc = pEvent->GetGuestError();
1216 }
1217 }
1218
1219 unregisterWaitEvent(pEvent);
1220
1221 LogFlowFuncLeaveRC(vrc);
1222 return vrc;
1223}
1224
1225int GuestFile::i_writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
1226 const void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1227{
1228 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1229 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1230
1231 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1232 uOffset, uTimeoutMS, pvData, cbData));
1233
1234 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1235
1236 int vrc;
1237
1238 GuestWaitEvent *pEvent = NULL;
1239 GuestEventTypes eventTypes;
1240 try
1241 {
1242 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1243 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1244
1245 vrc = registerWaitEvent(eventTypes, &pEvent);
1246 }
1247 catch (std::bad_alloc &)
1248 {
1249 vrc = VERR_NO_MEMORY;
1250 }
1251
1252 if (RT_FAILURE(vrc))
1253 return vrc;
1254
1255 /* Prepare HGCM call. */
1256 VBOXHGCMSVCPARM paParms[8];
1257 int i = 0;
1258 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1259 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1260 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset where to starting writing */);
1261 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
1262 HGCMSvcSetPv (&paParms[i++], unconst(pvData), cbData);
1263
1264 alock.release(); /* Drop write lock before sending. */
1265
1266 vrc = sendMessage(HOST_MSG_FILE_WRITE_AT, i, paParms);
1267 if (RT_SUCCESS(vrc))
1268 {
1269 uint32_t cbWritten = 0;
1270 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1271 if (RT_SUCCESS(vrc))
1272 {
1273 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1274 if (pcbWritten)
1275 *pcbWritten = cbWritten;
1276 }
1277 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1278 {
1279 vrc = pEvent->GetGuestError();
1280 }
1281 }
1282
1283 unregisterWaitEvent(pEvent);
1284
1285 LogFlowFuncLeaveRC(vrc);
1286 return vrc;
1287}
1288
1289// Wrapped IGuestFile methods
1290/////////////////////////////////////////////////////////////////////////////
1291HRESULT GuestFile::close()
1292{
1293 AutoCaller autoCaller(this);
1294 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1295
1296 LogFlowThisFuncEnter();
1297
1298 /* Close file on guest. */
1299 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1300 int vrc = i_closeFile(&rcGuest);
1301 /* On failure don't return here, instead do all the cleanup
1302 * work first and then return an error. */
1303
1304 AssertPtr(mSession);
1305 int vrc2 = mSession->i_fileUnregister(this);
1306 if (RT_SUCCESS(vrc))
1307 vrc = vrc2;
1308
1309 if (RT_FAILURE(vrc))
1310 {
1311 if (vrc == VERR_GSTCTL_GUEST_ERROR)
1312 return GuestFile::i_setErrorExternal(this, rcGuest);
1313 return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Closing guest file failed with %Rrc\n"), vrc);
1314 }
1315
1316 LogFlowThisFunc(("Returning S_OK / vrc=%Rrc\n", vrc));
1317 return S_OK;
1318}
1319
1320HRESULT GuestFile::queryInfo(ComPtr<IFsObjInfo> &aObjInfo)
1321{
1322 AutoCaller autoCaller(this);
1323 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1324
1325 LogFlowThisFuncEnter();
1326
1327 HRESULT hr = S_OK;
1328
1329 GuestFsObjData fsObjData;
1330 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1331 int vrc = i_queryInfo(fsObjData, &rcGuest);
1332 if (RT_SUCCESS(vrc))
1333 {
1334 ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
1335 hr = ptrFsObjInfo.createObject();
1336 if (SUCCEEDED(hr))
1337 {
1338 vrc = ptrFsObjInfo->init(fsObjData);
1339 if (RT_SUCCESS(vrc))
1340 hr = ptrFsObjInfo.queryInterfaceTo(aObjInfo.asOutParam());
1341 else
1342 hr = setErrorVrc(vrc);
1343 }
1344 }
1345 else
1346 {
1347 if (GuestProcess::i_isGuestError(vrc))
1348 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1349 else
1350 hr = setErrorVrc(vrc, tr("Querying file information failed: %Rrc"), vrc);
1351 }
1352
1353 LogFlowFuncLeaveRC(vrc);
1354 return hr;
1355}
1356
1357HRESULT GuestFile::querySize(LONG64 *aSize)
1358{
1359 AutoCaller autoCaller(this);
1360 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1361
1362 LogFlowThisFuncEnter();
1363
1364 HRESULT hr = S_OK;
1365
1366 GuestFsObjData fsObjData;
1367 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1368 int vrc = i_queryInfo(fsObjData, &rcGuest);
1369 if (RT_SUCCESS(vrc))
1370 {
1371 *aSize = fsObjData.mObjectSize;
1372 }
1373 else
1374 {
1375 if (GuestProcess::i_isGuestError(vrc))
1376 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1377 else
1378 hr = setErrorVrc(vrc, tr("Querying file size failed: %Rrc"), vrc);
1379 }
1380
1381 LogFlowFuncLeaveRC(vrc);
1382 return hr;
1383}
1384
1385HRESULT GuestFile::read(ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1386{
1387 AutoCaller autoCaller(this);
1388 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1389
1390 if (aToRead == 0)
1391 return setError(E_INVALIDARG, tr("The size to read is zero"));
1392
1393 LogFlowThisFuncEnter();
1394
1395 aData.resize(aToRead);
1396
1397 HRESULT hr = S_OK;
1398
1399 uint32_t cbRead;
1400 int vrc = i_readData(aToRead, aTimeoutMS,
1401 &aData.front(), aToRead, &cbRead);
1402
1403 if (RT_SUCCESS(vrc))
1404 {
1405 if (aData.size() != cbRead)
1406 aData.resize(cbRead);
1407 }
1408 else
1409 {
1410 aData.resize(0);
1411
1412 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" failed: %Rrc"),
1413 mData.mOpenInfo.mFilename.c_str(), vrc);
1414 }
1415
1416 LogFlowFuncLeaveRC(vrc);
1417 return hr;
1418}
1419
1420HRESULT GuestFile::readAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1421{
1422 AutoCaller autoCaller(this);
1423 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1424
1425 if (aToRead == 0)
1426 return setError(E_INVALIDARG, tr("The size to read is zero"));
1427
1428 LogFlowThisFuncEnter();
1429
1430 aData.resize(aToRead);
1431
1432 HRESULT hr = S_OK;
1433
1434 size_t cbRead;
1435 int vrc = i_readDataAt(aOffset, aToRead, aTimeoutMS,
1436 &aData.front(), aToRead, &cbRead);
1437 if (RT_SUCCESS(vrc))
1438 {
1439 if (aData.size() != cbRead)
1440 aData.resize(cbRead);
1441 }
1442 else
1443 {
1444 aData.resize(0);
1445
1446 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1447 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1448 }
1449
1450 LogFlowFuncLeaveRC(vrc);
1451 return hr;
1452}
1453
1454HRESULT GuestFile::seek(LONG64 aOffset, FileSeekOrigin_T aWhence, LONG64 *aNewOffset)
1455{
1456 AutoCaller autoCaller(this);
1457 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1458
1459 HRESULT hr = S_OK;
1460
1461 GUEST_FILE_SEEKTYPE eSeekType;
1462 switch (aWhence)
1463 {
1464 case FileSeekOrigin_Begin:
1465 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1466 break;
1467
1468 case FileSeekOrigin_Current:
1469 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1470 break;
1471
1472 case FileSeekOrigin_End:
1473 eSeekType = GUEST_FILE_SEEKTYPE_END;
1474 break;
1475
1476 default:
1477 return setError(E_INVALIDARG, tr("Invalid seek type specified"));
1478 }
1479
1480 LogFlowThisFuncEnter();
1481
1482 uint64_t uNewOffset;
1483 int vrc = i_seekAt(aOffset, eSeekType,
1484 30 * 1000 /* 30s timeout */, &uNewOffset);
1485 if (RT_SUCCESS(vrc))
1486 *aNewOffset = RT_MIN(uNewOffset, (uint64_t)INT64_MAX);
1487 else
1488 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"),
1489 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1490
1491 LogFlowFuncLeaveRC(vrc);
1492 return hr;
1493}
1494
1495HRESULT GuestFile::setACL(const com::Utf8Str &aAcl, ULONG aMode)
1496{
1497 RT_NOREF(aAcl, aMode);
1498 ReturnComNotImplemented();
1499}
1500
1501HRESULT GuestFile::setSize(LONG64 aSize)
1502{
1503 RT_NOREF(aSize);
1504 ReturnComNotImplemented();
1505}
1506
1507HRESULT GuestFile::write(const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1508{
1509 AutoCaller autoCaller(this);
1510 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1511
1512 if (aData.size() == 0)
1513 return setError(E_INVALIDARG, tr("No data to write specified"));
1514
1515 LogFlowThisFuncEnter();
1516
1517 HRESULT hr = S_OK;
1518
1519 const uint32_t cbData = (uint32_t)aData.size();
1520 const void *pvData = (void *)&aData.front();
1521 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1522 if (RT_FAILURE(vrc))
1523 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
1524 aData.size(), mData.mOpenInfo.mFilename.c_str(), vrc);
1525
1526 LogFlowFuncLeaveRC(vrc);
1527 return hr;
1528}
1529
1530HRESULT GuestFile::writeAt(LONG64 aOffset, const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1531{
1532 AutoCaller autoCaller(this);
1533 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1534
1535 if (aData.size() == 0)
1536 return setError(E_INVALIDARG, tr("No data to write at specified"));
1537
1538 LogFlowThisFuncEnter();
1539
1540 HRESULT hr = S_OK;
1541
1542 const uint32_t cbData = (uint32_t)aData.size();
1543 const void *pvData = (void *)&aData.front();
1544 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1545 if (RT_FAILURE(vrc))
1546 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
1547 aData.size(), mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1548
1549 LogFlowFuncLeaveRC(vrc);
1550 return hr;
1551}
1552
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