VirtualBox

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

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

GuestCtrlSvc,Main,VBoxService: Implemented IGuestFile::SetSize. bugref:9320

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