VirtualBox

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

Last change on this file since 78352 was 78234, checked in by vboxsync, 6 years ago

Main/GuestCtrl: Fixed three i_waitForStatusChange() methods that would return VERR_GSTCTL_GUEST_ERROR without setting prcGuest, making the caller use uninitialized stack as status code for the operation. bugref:9320

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.9 KB
Line 
1/* $Id: GuestFileImpl.cpp 78234 2019-04-20 23:49:01Z 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 */
399Utf8Str GuestFile::i_guestErrorToString(int rcGuest)
400{
401 Utf8Str strError;
402
403 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
404 switch (rcGuest)
405 {
406 case VERR_ACCESS_DENIED:
407 strError += Utf8StrFmt(tr("Access denied"));
408 break;
409
410 case VERR_ALREADY_EXISTS:
411 strError += Utf8StrFmt(tr("File already exists"));
412 break;
413
414 case VERR_FILE_NOT_FOUND:
415 strError += Utf8StrFmt(tr("File not found"));
416 break;
417
418 case VERR_NET_HOST_NOT_FOUND:
419 strError += Utf8StrFmt(tr("Host name not found"));
420 break;
421
422 case VERR_SHARING_VIOLATION:
423 strError += Utf8StrFmt(tr("Sharing violation"));
424 break;
425
426 default:
427 strError += Utf8StrFmt("%Rrc", rcGuest);
428 break;
429 }
430
431 return strError;
432}
433
434int GuestFile::i_onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
435{
436 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
437 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
438
439 LogFlowThisFuncEnter();
440
441 if (pSvcCbData->mParms < 3)
442 return VERR_INVALID_PARAMETER;
443
444 int idx = 1; /* Current parameter index. */
445 CALLBACKDATA_FILE_NOTIFY dataCb;
446 /* pSvcCb->mpaParms[0] always contains the context ID. */
447 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.uType);
448 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.rc);
449
450 int rcGuest = (int)dataCb.rc; /* uint32_t vs. int. */
451
452 LogFlowThisFunc(("uType=%RU32, rcGuest=%Rrc\n", dataCb.uType, rcGuest));
453
454 if (RT_FAILURE(rcGuest))
455 {
456 int rc2 = i_setFileStatus(FileStatus_Error, rcGuest);
457 AssertRC(rc2);
458
459 /* Ignore rc, as the event to signal might not be there (anymore). */
460 signalWaitEventInternal(pCbCtx, rcGuest, NULL /* pPayload */);
461 return VINF_SUCCESS; /* Report to the guest. */
462 }
463
464 AssertMsg(mObjectID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID),
465 ("File ID %RU32 does not match object ID %RU32\n", mObjectID,
466 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));
467
468 int rc = VERR_NOT_SUPPORTED; /* Play safe by default. */
469
470 switch (dataCb.uType)
471 {
472 case GUEST_FILE_NOTIFYTYPE_ERROR:
473 {
474 rc = i_setFileStatus(FileStatus_Error, rcGuest);
475 break;
476 }
477
478 case GUEST_FILE_NOTIFYTYPE_OPEN:
479 {
480 if (pSvcCbData->mParms == 4)
481 {
482 rc = HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.u.open.uHandle);
483 if (RT_FAILURE(rc))
484 break;
485
486 /* Set the process status. */
487 rc = i_setFileStatus(FileStatus_Open, rcGuest);
488 }
489 break;
490 }
491
492 case GUEST_FILE_NOTIFYTYPE_CLOSE:
493 {
494 rc = i_setFileStatus(FileStatus_Closed, rcGuest);
495 break;
496 }
497
498 case GUEST_FILE_NOTIFYTYPE_READ:
499 {
500 if (pSvcCbData->mParms == 4)
501 {
502 rc = HGCMSvcGetPv(&pSvcCbData->mpaParms[idx++], &dataCb.u.read.pvData,
503 &dataCb.u.read.cbData);
504 if (RT_FAILURE(rc))
505 break;
506
507 const uint32_t cbRead = dataCb.u.read.cbData;
508
509 Log3ThisFunc(("cbRead=%RU32\n", cbRead));
510
511 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
512
513 mData.mOffCurrent += cbRead;
514
515 alock.release();
516
517 com::SafeArray<BYTE> data((size_t)cbRead);
518 data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead);
519
520 fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent,
521 cbRead, ComSafeArrayAsInParam(data));
522 }
523 break;
524 }
525
526 case GUEST_FILE_NOTIFYTYPE_WRITE:
527 {
528 if (pSvcCbData->mParms == 4)
529 {
530 rc = HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.u.write.cbWritten);
531 if (RT_FAILURE(rc))
532 break;
533
534 const uint32_t cbWritten = dataCb.u.write.cbWritten;
535
536 Log3ThisFunc(("cbWritten=%RU32\n", cbWritten));
537
538 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
539
540 mData.mOffCurrent += cbWritten;
541
542 alock.release();
543
544 fireGuestFileWriteEvent(mEventSource, mSession, this, mData.mOffCurrent, cbWritten);
545 }
546 break;
547 }
548
549 case GUEST_FILE_NOTIFYTYPE_SEEK:
550 {
551 if (pSvcCbData->mParms == 4)
552 {
553 rc = HGCMSvcGetU64(&pSvcCbData->mpaParms[idx++], &dataCb.u.seek.uOffActual);
554 if (RT_FAILURE(rc))
555 break;
556
557 Log3ThisFunc(("uOffActual=%RU64\n", dataCb.u.seek.uOffActual));
558
559 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
560
561 mData.mOffCurrent = dataCb.u.seek.uOffActual;
562
563 alock.release();
564
565 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, mData.mOffCurrent, 0 /* Processed */);
566 }
567 break;
568 }
569
570 case GUEST_FILE_NOTIFYTYPE_TELL:
571 {
572 if (pSvcCbData->mParms == 4)
573 {
574 rc = HGCMSvcGetU64(&pSvcCbData->mpaParms[idx++], &dataCb.u.tell.uOffActual);
575 if (RT_FAILURE(rc))
576 break;
577
578 Log3ThisFunc(("uOffActual=%RU64\n", dataCb.u.tell.uOffActual));
579
580 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
581
582 mData.mOffCurrent = dataCb.u.tell.uOffActual;
583
584 alock.release();
585
586 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, mData.mOffCurrent, 0 /* Processed */);
587 }
588 break;
589 }
590
591 default:
592 break;
593 }
594
595 if (RT_SUCCESS(rc))
596 {
597 GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb));
598
599 /* Ignore rc, as the event to signal might not be there (anymore). */
600 signalWaitEventInternal(pCbCtx, rcGuest, &payload);
601 }
602
603 LogFlowThisFunc(("uType=%RU32, rcGuest=%Rrc, rc=%Rrc\n", dataCb.uType, rcGuest, rc));
604 return rc;
605}
606
607int GuestFile::i_onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
608{
609 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
610 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
611
612 int vrc = i_setFileStatus(FileStatus_Down, VINF_SUCCESS);
613
614 LogFlowFuncLeaveRC(vrc);
615 return vrc;
616}
617
618/**
619 * @copydoc GuestObject::i_onUnregister
620 */
621int GuestFile::i_onUnregister(void)
622{
623 LogFlowThisFuncEnter();
624
625 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
626
627 int vrc = VINF_SUCCESS;
628
629 /*
630 * Note: The event source stuff holds references to this object,
631 * so make sure that this is cleaned up *before* calling uninit().
632 */
633 if (!mEventSource.isNull())
634 {
635 mEventSource->UnregisterListener(mLocalListener);
636
637 mLocalListener.setNull();
638 unconst(mEventSource).setNull();
639 }
640
641 LogFlowFuncLeaveRC(vrc);
642 return vrc;
643}
644
645/**
646 * @copydoc GuestObject::i_onSessionStatusChange
647 */
648int GuestFile::i_onSessionStatusChange(GuestSessionStatus_T enmSessionStatus)
649{
650 LogFlowThisFuncEnter();
651
652 int vrc = VINF_SUCCESS;
653
654 /* If the session now is in a terminated state, set the file status
655 * to "down", as there is not much else we can do now. */
656 if (GuestSession::i_isTerminated(enmSessionStatus))
657 vrc = i_setFileStatus(FileStatus_Down, 0 /* fileRc, ignored */);
658
659 LogFlowFuncLeaveRC(vrc);
660 return vrc;
661}
662
663int GuestFile::i_openFile(uint32_t uTimeoutMS, int *prcGuest)
664{
665 AssertReturn(mData.mOpenInfo.mFilename.isNotEmpty(), VERR_INVALID_PARAMETER);
666
667 LogFlowThisFuncEnter();
668
669 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
670
671 LogFlowThisFunc(("strFile=%s, enmAccessMode=0x%x, enmOpenAction=0x%x, uCreationMode=%RU32, mfOpenEx=%RU32\n",
672 mData.mOpenInfo.mFilename.c_str(), mData.mOpenInfo.mAccessMode, mData.mOpenInfo.mOpenAction,
673 mData.mOpenInfo.mCreationMode, mData.mOpenInfo.mfOpenEx));
674
675 /* Validate and translate open action. */
676 const char *pszOpenAction = NULL;
677 switch (mData.mOpenInfo.mOpenAction)
678 {
679 case FileOpenAction_OpenExisting: pszOpenAction = "oe"; break;
680 case FileOpenAction_OpenOrCreate: pszOpenAction = "oc"; break;
681 case FileOpenAction_CreateNew: pszOpenAction = "ce"; break;
682 case FileOpenAction_CreateOrReplace: pszOpenAction = "ca"; break;
683 case FileOpenAction_OpenExistingTruncated: pszOpenAction = "ot"; break;
684 case FileOpenAction_AppendOrCreate:
685 pszOpenAction = "oa"; /** @todo get rid of this one and implement AppendOnly/AppendRead. */
686 break;
687 default:
688 return VERR_INVALID_PARAMETER;
689 }
690
691 /* Validate and translate access mode. */
692 const char *pszAccessMode = NULL;
693 switch (mData.mOpenInfo.mAccessMode)
694 {
695 case FileAccessMode_ReadOnly: pszAccessMode = "r"; break;
696 case FileAccessMode_WriteOnly: pszAccessMode = "w"; break;
697 case FileAccessMode_ReadWrite: pszAccessMode = "r+"; break;
698 case FileAccessMode_AppendOnly: RT_FALL_THRU();
699 case FileAccessMode_AppendRead: return VERR_NOT_IMPLEMENTED;
700 default: return VERR_INVALID_PARAMETER;
701 }
702
703 /* Validate and translate sharing mode. */
704 const char *pszSharingMode = NULL;
705 switch (mData.mOpenInfo.mSharingMode)
706 {
707 case FileSharingMode_All: pszSharingMode = ""; break;
708 case FileSharingMode_Read: RT_FALL_THRU();
709 case FileSharingMode_Write: RT_FALL_THRU();
710 case FileSharingMode_ReadWrite: RT_FALL_THRU();
711 case FileSharingMode_Delete: RT_FALL_THRU();
712 case FileSharingMode_ReadDelete: RT_FALL_THRU();
713 case FileSharingMode_WriteDelete: return VERR_NOT_IMPLEMENTED;
714 default: return VERR_INVALID_PARAMETER;
715 }
716
717 int vrc;
718
719 GuestWaitEvent *pEvent = NULL;
720 GuestEventTypes eventTypes;
721 try
722 {
723 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
724
725 vrc = registerWaitEvent(eventTypes, &pEvent);
726 }
727 catch (std::bad_alloc &)
728 {
729 vrc = VERR_NO_MEMORY;
730 }
731
732 if (RT_FAILURE(vrc))
733 return vrc;
734
735 /* Prepare HGCM call. */
736 VBOXHGCMSVCPARM paParms[8];
737 int i = 0;
738 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
739 HGCMSvcSetPv(&paParms[i++], (void*)mData.mOpenInfo.mFilename.c_str(),
740 (ULONG)mData.mOpenInfo.mFilename.length() + 1);
741 HGCMSvcSetStr(&paParms[i++], pszAccessMode);
742 HGCMSvcSetStr(&paParms[i++], pszOpenAction);
743 HGCMSvcSetStr(&paParms[i++], pszSharingMode);
744 HGCMSvcSetU32(&paParms[i++], mData.mOpenInfo.mCreationMode);
745 HGCMSvcSetU64(&paParms[i++], mData.mOpenInfo.muOffset);
746 /** @todo Next protocol version: add flags, replace strings, remove initial offset. */
747
748 alock.release(); /* Drop write lock before sending. */
749
750 vrc = sendMessage(HOST_MSG_FILE_OPEN, i, paParms);
751 if (RT_SUCCESS(vrc))
752 vrc = i_waitForStatusChange(pEvent, uTimeoutMS, NULL /* FileStatus */, prcGuest);
753
754 unregisterWaitEvent(pEvent);
755
756 LogFlowFuncLeaveRC(vrc);
757 return vrc;
758}
759
760int GuestFile::i_queryInfo(GuestFsObjData &objData, int *prcGuest)
761{
762 AssertPtr(mSession);
763 return mSession->i_fsQueryInfo(mData.mOpenInfo.mFilename, FALSE /* fFollowSymlinks */, objData, prcGuest);
764}
765
766int GuestFile::i_readData(uint32_t uSize, uint32_t uTimeoutMS,
767 void* pvData, uint32_t cbData, uint32_t* pcbRead)
768{
769 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
770 AssertReturn(cbData, VERR_INVALID_PARAMETER);
771
772 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
773 uSize, uTimeoutMS, pvData, cbData));
774
775 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
776
777 int vrc;
778
779 GuestWaitEvent *pEvent = NULL;
780 GuestEventTypes eventTypes;
781 try
782 {
783 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
784 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
785
786 vrc = registerWaitEvent(eventTypes, &pEvent);
787 }
788 catch (std::bad_alloc &)
789 {
790 vrc = VERR_NO_MEMORY;
791 }
792
793 if (RT_FAILURE(vrc))
794 return vrc;
795
796 /* Prepare HGCM call. */
797 VBOXHGCMSVCPARM paParms[4];
798 int i = 0;
799 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
800 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
801 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
802
803 alock.release(); /* Drop write lock before sending. */
804
805 vrc = sendMessage(HOST_MSG_FILE_READ, i, paParms);
806 if (RT_SUCCESS(vrc))
807 {
808 uint32_t cbRead = 0;
809 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
810 if (RT_SUCCESS(vrc))
811 {
812 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
813 if (pcbRead)
814 *pcbRead = cbRead;
815 }
816 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
817 {
818 vrc = pEvent->GetGuestError();
819 }
820 }
821
822 unregisterWaitEvent(pEvent);
823
824 LogFlowFuncLeaveRC(vrc);
825 return vrc;
826}
827
828int GuestFile::i_readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
829 void* pvData, size_t cbData, size_t* pcbRead)
830{
831 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
832 uOffset, uSize, uTimeoutMS, pvData, cbData));
833
834 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
835
836 int vrc;
837
838 GuestWaitEvent *pEvent = NULL;
839 GuestEventTypes eventTypes;
840 try
841 {
842 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
843 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
844
845 vrc = registerWaitEvent(eventTypes, &pEvent);
846 }
847 catch (std::bad_alloc &)
848 {
849 vrc = VERR_NO_MEMORY;
850 }
851
852 if (RT_FAILURE(vrc))
853 return vrc;
854
855 /* Prepare HGCM call. */
856 VBOXHGCMSVCPARM paParms[4];
857 int i = 0;
858 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
859 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
860 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset (in bytes) to start reading */);
861 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
862
863 alock.release(); /* Drop write lock before sending. */
864
865 vrc = sendMessage(HOST_MSG_FILE_READ_AT, i, paParms);
866 if (RT_SUCCESS(vrc))
867 {
868 uint32_t cbRead = 0;
869 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
870 if (RT_SUCCESS(vrc))
871 {
872 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
873
874 if (pcbRead)
875 *pcbRead = cbRead;
876 }
877 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
878 {
879 vrc = pEvent->GetGuestError();
880 }
881 }
882
883 unregisterWaitEvent(pEvent);
884
885 LogFlowFuncLeaveRC(vrc);
886 return vrc;
887}
888
889int GuestFile::i_seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType,
890 uint32_t uTimeoutMS, uint64_t *puOffset)
891{
892 LogFlowThisFunc(("iOffset=%RI64, uTimeoutMS=%RU32\n",
893 iOffset, uTimeoutMS));
894
895 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
896
897 int vrc;
898
899 GuestWaitEvent *pEvent = NULL;
900 GuestEventTypes eventTypes;
901 try
902 {
903 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
904 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
905
906 vrc = registerWaitEvent(eventTypes, &pEvent);
907 }
908 catch (std::bad_alloc &)
909 {
910 vrc = VERR_NO_MEMORY;
911 }
912
913 if (RT_FAILURE(vrc))
914 return vrc;
915
916 /* Prepare HGCM call. */
917 VBOXHGCMSVCPARM paParms[4];
918 int i = 0;
919 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
920 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
921 HGCMSvcSetU32(&paParms[i++], eSeekType /* Seek method */);
922 /** @todo uint64_t vs. int64_t! */
923 HGCMSvcSetU64(&paParms[i++], (uint64_t)iOffset /* Offset (in bytes) to start reading */);
924
925 alock.release(); /* Drop write lock before sending. */
926
927 vrc = sendMessage(HOST_MSG_FILE_SEEK, i, paParms);
928 if (RT_SUCCESS(vrc))
929 {
930 uint64_t uOffset;
931 vrc = i_waitForOffsetChange(pEvent, uTimeoutMS, &uOffset);
932 if (RT_SUCCESS(vrc))
933 {
934 LogFlowThisFunc(("uOffset=%RU64\n", uOffset));
935
936 if (puOffset)
937 *puOffset = uOffset;
938 }
939 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
940 {
941 vrc = pEvent->GetGuestError();
942 }
943 }
944
945 unregisterWaitEvent(pEvent);
946
947 LogFlowFuncLeaveRC(vrc);
948 return vrc;
949}
950
951/* static */
952HRESULT GuestFile::i_setErrorExternal(VirtualBoxBase *pInterface, int rcGuest)
953{
954 AssertPtr(pInterface);
955 AssertMsg(RT_FAILURE(rcGuest), ("Guest rc does not indicate a failure when setting error\n"));
956
957 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestFile::i_guestErrorToString(rcGuest).c_str());
958}
959
960int GuestFile::i_setFileStatus(FileStatus_T fileStatus, int fileRc)
961{
962 LogFlowThisFuncEnter();
963
964 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
965
966 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, fileRc=%Rrc\n",
967 mData.mStatus, fileStatus, fileRc));
968
969#ifdef VBOX_STRICT
970 if (fileStatus == FileStatus_Error)
971 {
972 AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc));
973 }
974 else
975 AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc));
976#endif
977
978 if (mData.mStatus != fileStatus)
979 {
980 mData.mStatus = fileStatus;
981 mData.mLastError = fileRc;
982
983 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
984 HRESULT hr = errorInfo.createObject();
985 ComAssertComRC(hr);
986 if (RT_FAILURE(fileRc))
987 {
988 hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, fileRc,
989 COM_IIDOF(IGuestFile), getComponentName(),
990 i_guestErrorToString(fileRc));
991 ComAssertComRC(hr);
992 }
993
994 alock.release(); /* Release lock before firing off event. */
995
996 fireGuestFileStateChangedEvent(mEventSource, mSession,
997 this, fileStatus, errorInfo);
998 }
999
1000 return VINF_SUCCESS;
1001}
1002
1003int GuestFile::i_waitForOffsetChange(GuestWaitEvent *pEvent,
1004 uint32_t uTimeoutMS, uint64_t *puOffset)
1005{
1006 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1007
1008 VBoxEventType_T evtType;
1009 ComPtr<IEvent> pIEvent;
1010 int vrc = waitForEvent(pEvent, uTimeoutMS,
1011 &evtType, pIEvent.asOutParam());
1012 if (RT_SUCCESS(vrc))
1013 {
1014 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
1015 {
1016 if (puOffset)
1017 {
1018 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
1019 Assert(!pFileEvent.isNull());
1020
1021 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
1022 ComAssertComRC(hr);
1023 }
1024 }
1025 else
1026 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1027 }
1028
1029 return vrc;
1030}
1031
1032int GuestFile::i_waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1033 void *pvData, size_t cbData, uint32_t *pcbRead)
1034{
1035 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1036
1037 VBoxEventType_T evtType;
1038 ComPtr<IEvent> pIEvent;
1039 int vrc = waitForEvent(pEvent, uTimeoutMS,
1040 &evtType, pIEvent.asOutParam());
1041 if (RT_SUCCESS(vrc))
1042 {
1043 if (evtType == VBoxEventType_OnGuestFileRead)
1044 {
1045 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
1046 Assert(!pFileEvent.isNull());
1047
1048 HRESULT hr;
1049 if (pvData)
1050 {
1051 com::SafeArray <BYTE> data;
1052 hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1053 ComAssertComRC(hr);
1054 const size_t cbRead = data.size();
1055 if (cbRead)
1056 {
1057 if (cbRead <= cbData)
1058 memcpy(pvData, data.raw(), cbRead);
1059 else
1060 vrc = VERR_BUFFER_OVERFLOW;
1061 }
1062 else
1063 vrc = VERR_NO_DATA;
1064 }
1065 if (pcbRead)
1066 {
1067 hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
1068 ComAssertComRC(hr);
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;
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; int rcGuest;
1337 int vrc = i_queryInfo(fsObjData, &rcGuest);
1338 if (RT_SUCCESS(vrc))
1339 {
1340 ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
1341 hr = ptrFsObjInfo.createObject();
1342 if (SUCCEEDED(hr))
1343 {
1344 vrc = ptrFsObjInfo->init(fsObjData);
1345 if (RT_SUCCESS(vrc))
1346 hr = ptrFsObjInfo.queryInterfaceTo(aObjInfo.asOutParam());
1347 else
1348 hr = setErrorVrc(vrc);
1349 }
1350 }
1351 else
1352 {
1353 if (GuestProcess::i_isGuestError(vrc))
1354 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1355 else
1356 hr = setErrorVrc(vrc, tr("Querying file information failed: %Rrc"), vrc);
1357 }
1358
1359 LogFlowFuncLeaveRC(vrc);
1360 return hr;
1361}
1362
1363HRESULT GuestFile::querySize(LONG64 *aSize)
1364{
1365 AutoCaller autoCaller(this);
1366 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1367
1368 LogFlowThisFuncEnter();
1369
1370 HRESULT hr = S_OK;
1371
1372 GuestFsObjData fsObjData; int rcGuest;
1373 int vrc = i_queryInfo(fsObjData, &rcGuest);
1374 if (RT_SUCCESS(vrc))
1375 {
1376 *aSize = fsObjData.mObjectSize;
1377 }
1378 else
1379 {
1380 if (GuestProcess::i_isGuestError(vrc))
1381 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1382 else
1383 hr = setErrorVrc(vrc, tr("Querying file size failed: %Rrc"), vrc);
1384 }
1385
1386 LogFlowFuncLeaveRC(vrc);
1387 return hr;
1388}
1389
1390HRESULT GuestFile::read(ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1391{
1392 AutoCaller autoCaller(this);
1393 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1394
1395 if (aToRead == 0)
1396 return setError(E_INVALIDARG, tr("The size to read is zero"));
1397
1398 LogFlowThisFuncEnter();
1399
1400 aData.resize(aToRead);
1401
1402 HRESULT hr = S_OK;
1403
1404 uint32_t cbRead;
1405 int vrc = i_readData(aToRead, aTimeoutMS,
1406 &aData.front(), aToRead, &cbRead);
1407
1408 if (RT_SUCCESS(vrc))
1409 {
1410 if (aData.size() != cbRead)
1411 aData.resize(cbRead);
1412 }
1413 else
1414 {
1415 aData.resize(0);
1416
1417 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" failed: %Rrc"),
1418 mData.mOpenInfo.mFilename.c_str(), vrc);
1419 }
1420
1421 LogFlowFuncLeaveRC(vrc);
1422 return hr;
1423}
1424
1425HRESULT GuestFile::readAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1426{
1427 AutoCaller autoCaller(this);
1428 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1429
1430 if (aToRead == 0)
1431 return setError(E_INVALIDARG, tr("The size to read is zero"));
1432
1433 LogFlowThisFuncEnter();
1434
1435 aData.resize(aToRead);
1436
1437 HRESULT hr = S_OK;
1438
1439 size_t cbRead;
1440 int vrc = i_readDataAt(aOffset, aToRead, aTimeoutMS,
1441 &aData.front(), aToRead, &cbRead);
1442 if (RT_SUCCESS(vrc))
1443 {
1444 if (aData.size() != cbRead)
1445 aData.resize(cbRead);
1446 }
1447 else
1448 {
1449 aData.resize(0);
1450
1451 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1452 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1453 }
1454
1455 LogFlowFuncLeaveRC(vrc);
1456 return hr;
1457}
1458
1459HRESULT GuestFile::seek(LONG64 aOffset, FileSeekOrigin_T aWhence, LONG64 *aNewOffset)
1460{
1461 AutoCaller autoCaller(this);
1462 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1463
1464 HRESULT hr = S_OK;
1465
1466 GUEST_FILE_SEEKTYPE eSeekType;
1467 switch (aWhence)
1468 {
1469 case FileSeekOrigin_Begin:
1470 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1471 break;
1472
1473 case FileSeekOrigin_Current:
1474 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1475 break;
1476
1477 case FileSeekOrigin_End:
1478 eSeekType = GUEST_FILE_SEEKTYPE_END;
1479 break;
1480
1481 default:
1482 return setError(E_INVALIDARG, tr("Invalid seek type specified"));
1483 }
1484
1485 LogFlowThisFuncEnter();
1486
1487 uint64_t uNewOffset;
1488 int vrc = i_seekAt(aOffset, eSeekType,
1489 30 * 1000 /* 30s timeout */, &uNewOffset);
1490 if (RT_SUCCESS(vrc))
1491 *aNewOffset = RT_MIN(uNewOffset, (uint64_t)INT64_MAX);
1492 else
1493 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"),
1494 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1495
1496 LogFlowFuncLeaveRC(vrc);
1497 return hr;
1498}
1499
1500HRESULT GuestFile::setACL(const com::Utf8Str &aAcl, ULONG aMode)
1501{
1502 RT_NOREF(aAcl, aMode);
1503 ReturnComNotImplemented();
1504}
1505
1506HRESULT GuestFile::setSize(LONG64 aSize)
1507{
1508 RT_NOREF(aSize);
1509 ReturnComNotImplemented();
1510}
1511
1512HRESULT GuestFile::write(const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1513{
1514 AutoCaller autoCaller(this);
1515 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1516
1517 if (aData.size() == 0)
1518 return setError(E_INVALIDARG, tr("No data to write specified"));
1519
1520 LogFlowThisFuncEnter();
1521
1522 HRESULT hr = S_OK;
1523
1524 const uint32_t cbData = (uint32_t)aData.size();
1525 const void *pvData = (void *)&aData.front();
1526 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1527 if (RT_FAILURE(vrc))
1528 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
1529 aData.size(), mData.mOpenInfo.mFilename.c_str(), vrc);
1530
1531 LogFlowFuncLeaveRC(vrc);
1532 return hr;
1533}
1534
1535HRESULT GuestFile::writeAt(LONG64 aOffset, const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1536{
1537 AutoCaller autoCaller(this);
1538 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1539
1540 if (aData.size() == 0)
1541 return setError(E_INVALIDARG, tr("No data to write at specified"));
1542
1543 LogFlowThisFuncEnter();
1544
1545 HRESULT hr = S_OK;
1546
1547 const uint32_t cbData = (uint32_t)aData.size();
1548 const void *pvData = (void *)&aData.front();
1549 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1550 if (RT_FAILURE(vrc))
1551 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
1552 aData.size(), mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1553
1554 LogFlowFuncLeaveRC(vrc);
1555 return hr;
1556}
1557
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