VirtualBox

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

Last change on this file since 104001 was 104001, checked in by vboxsync, 7 months ago

Guest Control/Main: Renaming (removed "File" from some internal GuestFile APIs; unnecessary).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.5 KB
RevLine 
[42084]1/* $Id: GuestFileImpl.cpp 104001 2024-03-22 16:03:33Z vboxsync $ */
2/** @file
[44863]3 * VirtualBox Main - Guest file handling.
[42084]4 */
5
6/*
[98103]7 * Copyright (C) 2012-2023 Oracle and/or its affiliates.
[42084]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[42084]26 */
27
28
[57358]29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[71173]32#define LOG_GROUP LOG_GROUP_MAIN_GUESTFILE
[67914]33#include "LoggingNew.h"
34
[55645]35#ifndef VBOX_WITH_GUEST_CONTROL
36# error "VBOX_WITH_GUEST_CONTROL must defined in this file"
37#endif
[42084]38#include "GuestFileImpl.h"
[42611]39#include "GuestSessionImpl.h"
[42478]40#include "GuestCtrlImplPrivate.h"
[44863]41#include "ConsoleImpl.h"
[45805]42#include "VirtualBoxErrorInfoImpl.h"
[42084]43
44#include "Global.h"
45#include "AutoCaller.h"
[45415]46#include "VBoxEvents.h"
[42084]47
[45415]48#include <iprt/cpp/utils.h> /* For unconst(). */
[44863]49#include <iprt/file.h>
[45780]50
[42084]51#include <VBox/com/array.h>
[45780]52#include <VBox/com/listeners.h>
[79287]53#include <VBox/AssertGuest.h>
[42084]54
55
[45780]56/**
57 * Internal listener class to serve events in an
58 * active manner, e.g. without polling delays.
59 */
60class GuestFileListener
61{
62public:
63
64 GuestFileListener(void)
65 {
66 }
67
[62157]68 virtual ~GuestFileListener()
69 {
70 }
71
[45780]72 HRESULT init(GuestFile *pFile)
73 {
[49610]74 AssertPtrReturn(pFile, E_POINTER);
[45780]75 mFile = pFile;
76 return S_OK;
77 }
78
79 void uninit(void)
80 {
[49610]81 mFile = NULL;
[45780]82 }
83
84 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
85 {
86 switch (aType)
87 {
88 case VBoxEventType_OnGuestFileStateChanged:
89 case VBoxEventType_OnGuestFileOffsetChanged:
90 case VBoxEventType_OnGuestFileRead:
91 case VBoxEventType_OnGuestFileWrite:
92 {
[49610]93 AssertPtrReturn(mFile, E_POINTER);
[94942]94 int vrc2 = mFile->signalWaitEvent(aType, aEvent);
95 RT_NOREF(vrc2);
[45780]96#ifdef DEBUG_andy
[94942]97 LogFlowFunc(("Signalling events of type=%RU32, file=%p resulted in vrc=%Rrc\n",
98 aType, mFile, vrc2));
[45780]99#endif
100 break;
101 }
102
103 default:
[49504]104 AssertMsgFailed(("Unhandled event %RU32\n", aType));
[45780]105 break;
106 }
107
108 return S_OK;
109 }
110
111private:
112
[92897]113 /** Weak pointer to the guest file object to listen for. */
[49610]114 GuestFile *mFile;
[45780]115};
116typedef ListenerImpl<GuestFileListener, GuestFile*> GuestFileListenerImpl;
117
118VBOX_LISTENER_DECLARE(GuestFileListenerImpl)
119
[42084]120// constructor / destructor
121/////////////////////////////////////////////////////////////////////////////
122
123DEFINE_EMPTY_CTOR_DTOR(GuestFile)
124
[42897]125HRESULT GuestFile::FinalConstruct(void)
[42084]126{
[49389]127 LogFlowThisFuncEnter();
[42084]128 return BaseFinalConstruct();
129}
130
131void GuestFile::FinalRelease(void)
132{
133 LogFlowThisFuncEnter();
134 uninit();
135 BaseFinalRelease();
136 LogFlowThisFuncLeave();
137}
138
139// public initializer/uninitializer for internal purposes only
140/////////////////////////////////////////////////////////////////////////////
141
[45109]142/**
143 * Initializes a file object but does *not* open the file on the guest
144 * yet. This is done in the dedidcated openFile call.
145 *
146 * @return IPRT status code.
147 * @param pConsole Pointer to console object.
148 * @param pSession Pointer to session object.
[71406]149 * @param aObjectID The object's ID.
[45109]150 * @param openInfo File opening information.
151 */
[45434]152int GuestFile::init(Console *pConsole, GuestSession *pSession,
[71406]153 ULONG aObjectID, const GuestFileOpenInfo &openInfo)
[42084]154{
[71406]155 LogFlowThisFunc(("pConsole=%p, pSession=%p, aObjectID=%RU32, strPath=%s\n",
[75926]156 pConsole, pSession, aObjectID, openInfo.mFilename.c_str()));
[44863]157
158 AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
159 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
160
[42084]161 /* Enclose the state transition NotReady->InInit->Ready. */
162 AutoInitSpan autoInitSpan(this);
[44863]163 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
[42084]164
[71406]165 int vrc = bindToSession(pConsole, pSession, aObjectID);
[44863]166 if (RT_SUCCESS(vrc))
167 {
[47817]168 mSession = pSession;
169
[77385]170 mData.mOpenInfo = openInfo;
[44863]171 mData.mInitialSize = 0;
[77385]172 mData.mStatus = FileStatus_Undefined;
173 mData.mLastError = VINF_SUCCESS;
174 mData.mOffCurrent = 0;
[42611]175
[45415]176 unconst(mEventSource).createObject();
[50544]177 HRESULT hr = mEventSource->init();
[45415]178 if (FAILED(hr))
179 vrc = VERR_COM_UNEXPECTED;
180 }
181
182 if (RT_SUCCESS(vrc))
183 {
[45780]184 try
185 {
186 GuestFileListener *pListener = new GuestFileListener();
187 ComObjPtr<GuestFileListenerImpl> thisListener;
188 HRESULT hr = thisListener.createObject();
189 if (SUCCEEDED(hr))
190 hr = thisListener->init(pListener, this);
191
192 if (SUCCEEDED(hr))
193 {
194 com::SafeArray <VBoxEventType_T> eventTypes;
195 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
196 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
197 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
198 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
[47469]199 hr = mEventSource->RegisterListener(thisListener,
[45780]200 ComSafeArrayAsInParam(eventTypes),
201 TRUE /* Active listener */);
202 if (SUCCEEDED(hr))
203 {
[47469]204 vrc = baseInit();
205 if (RT_SUCCESS(vrc))
206 {
207 mLocalListener = thisListener;
208 }
[45780]209 }
210 else
211 vrc = VERR_COM_UNEXPECTED;
212 }
213 else
214 vrc = VERR_COM_UNEXPECTED;
215 }
216 catch(std::bad_alloc &)
217 {
218 vrc = VERR_NO_MEMORY;
219 }
220 }
221
222 if (RT_SUCCESS(vrc))
223 {
[44863]224 /* Confirm a successful initialization when it's the case. */
225 autoInitSpan.setSucceeded();
226 }
[45415]227 else
228 autoInitSpan.setFailed();
[42611]229
[45415]230 LogFlowFuncLeaveRC(vrc);
[44863]231 return vrc;
[42084]232}
233
234/**
235 * Uninitializes the instance.
236 * Called from FinalRelease().
237 */
238void GuestFile::uninit(void)
239{
240 /* Enclose the state transition Ready->InUninit->NotReady. */
241 AutoUninitSpan autoUninitSpan(this);
242 if (autoUninitSpan.uninitDone())
243 return;
[42611]244
[49504]245 LogFlowThisFuncEnter();
246
[47469]247 baseUninit();
[42897]248 LogFlowThisFuncLeave();
[42084]249}
250
251// implementation of public getters/setters for attributes
252/////////////////////////////////////////////////////////////////////////////
253
[50618]254HRESULT GuestFile::getCreationMode(ULONG *aCreationMode)
[42084]255{
[42611]256 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
257
[44863]258 *aCreationMode = mData.mOpenInfo.mCreationMode;
[42611]259
260 return S_OK;
261}
262
[55631]263HRESULT GuestFile::getOpenAction(FileOpenAction_T *aOpenAction)
[42611]264{
265 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
266
[55631]267 *aOpenAction = mData.mOpenInfo.mOpenAction;
[42611]268
269 return S_OK;
[42084]270}
271
[50618]272HRESULT GuestFile::getEventSource(ComPtr<IEventSource> &aEventSource)
[45426]273{
[47836]274 /* No need to lock - lifetime constant. */
[50618]275 mEventSource.queryInterfaceTo(aEventSource.asOutParam());
[45426]276
277 return S_OK;
278}
279
[75926]280HRESULT GuestFile::getFilename(com::Utf8Str &aFilename)
[42611]281{
282 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
283
[75926]284 aFilename = mData.mOpenInfo.mFilename;
[42611]285
286 return S_OK;
287}
288
[50618]289HRESULT GuestFile::getId(ULONG *aId)
[47858]290{
291 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
292
[71406]293 *aId = mObjectID;
[47858]294
295 return S_OK;
296}
297
[50618]298HRESULT GuestFile::getInitialSize(LONG64 *aInitialSize)
[42084]299{
[42611]300 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
301
302 *aInitialSize = mData.mInitialSize;
303
304 return S_OK;
[42084]305}
306
[50618]307HRESULT GuestFile::getOffset(LONG64 *aOffset)
[42084]308{
[42611]309 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
310
[79302]311 /*
312 * This is updated by GuestFile::i_onFileNotify() when read, write and seek
313 * confirmation messages are recevied.
314 *
315 * Note! This will not be accurate with older (< 5.2.32, 6.0.0 - 6.0.9)
[84564]316 * Guest Additions when using writeAt, readAt or writing to a file
[79302]317 * opened in append mode.
318 */
[44863]319 *aOffset = mData.mOffCurrent;
[42611]320
321 return S_OK;
[42084]322}
323
[55631]324HRESULT GuestFile::getAccessMode(FileAccessMode_T *aAccessMode)
[42084]325{
[42611]326 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
327
[55631]328 *aAccessMode = mData.mOpenInfo.mAccessMode;
[42611]329
330 return S_OK;
[42084]331}
332
[50618]333HRESULT GuestFile::getStatus(FileStatus_T *aStatus)
[45415]334{
335 LogFlowThisFuncEnter();
336
337 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
338
339 *aStatus = mData.mStatus;
340
341 return S_OK;
342}
343
[42611]344// private methods
345/////////////////////////////////////////////////////////////////////////////
346
[92897]347/**
348 * Entry point for guest side file callbacks.
349 *
350 * @returns VBox status code.
351 * @param pCbCtx Host callback context.
[92916]352 * @param pSvcCb Host callback data.
[92897]353 */
[50618]354int GuestFile::i_callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
[44863]355{
[49349]356 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
357 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
358
[44863]359 LogFlowThisFunc(("strName=%s, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
[76958]360 mData.mOpenInfo.mFilename.c_str(), pCbCtx->uContextID, pCbCtx->uMessage, pSvcCb));
[44863]361
362 int vrc;
[76958]363 switch (pCbCtx->uMessage)
[44863]364 {
[76958]365 case GUEST_MSG_DISCONNECTED:
[50618]366 vrc = i_onGuestDisconnected(pCbCtx, pSvcCb);
[44863]367 break;
368
[76958]369 case GUEST_MSG_FILE_NOTIFY:
[104001]370 vrc = i_onNotify(pCbCtx, pSvcCb);
[44863]371 break;
372
373 default:
374 /* Silently ignore not implemented functions. */
375 vrc = VERR_NOT_SUPPORTED;
376 break;
377 }
378
379#ifdef DEBUG
380 LogFlowFuncLeaveRC(vrc);
381#endif
382 return vrc;
383}
384
[92897]385/**
[97626]386 * Closes the file on the guest side and unregisters it.
[92897]387 *
388 * @returns VBox status code.
389 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
390 * @param prcGuest Where to return the guest error when VERR_GSTCTL_GUEST_ERROR
391 * was returned.
392 */
[104001]393int GuestFile::i_close(int *prcGuest)
[45109]394{
[75926]395 LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFilename.c_str()));
[45109]396
[45780]397 int vrc;
398
399 GuestWaitEvent *pEvent = NULL;
[49349]400 GuestEventTypes eventTypes;
[45780]401 try
[45415]402 {
[45780]403 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
[45109]404
[47469]405 vrc = registerWaitEvent(eventTypes, &pEvent);
[45415]406 }
[73505]407 catch (std::bad_alloc &)
[45780]408 {
409 vrc = VERR_NO_MEMORY;
410 }
[45109]411
[45780]412 if (RT_FAILURE(vrc))
413 return vrc;
414
415 /* Prepare HGCM call. */
416 VBOXHGCMSVCPARM paParms[4];
417 int i = 0;
[75737]418 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
419 HGCMSvcSetU32(&paParms[i++], mObjectID /* Guest file ID */);
[45780]420
[76958]421 vrc = sendMessage(HOST_MSG_FILE_CLOSE, i, paParms);
[45780]422 if (RT_SUCCESS(vrc))
[50618]423 vrc = i_waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */,
[71299]424 NULL /* FileStatus */, prcGuest);
[47469]425 unregisterWaitEvent(pEvent);
[45780]426
[97626]427 /* Unregister the file object from the guest session. */
428 AssertPtr(mSession);
429 int vrc2 = mSession->i_fileUnregister(this);
430 if (RT_SUCCESS(vrc))
431 vrc = vrc2;
432
[45109]433 LogFlowFuncLeaveRC(vrc);
434 return vrc;
435}
436
[78666]437/**
[84648]438 * Converts a given guest file error to a string.
[78666]439 *
[84648]440 * @returns Error string.
441 * @param rcGuest Guest file error to return string for.
442 * @param pcszWhat Hint of what was involved when the error occurred.
[78666]443 */
[84648]444/* static */
445Utf8Str GuestFile::i_guestErrorToString(int rcGuest, const char *pcszWhat)
[78666]446{
[84648]447 AssertPtrReturn(pcszWhat, "");
448
449 Utf8Str strErr;
[84054]450 switch (rcGuest)
451 {
[91518]452#define CASE_MSG(a_iRc, ...) \
453 case a_iRc: strErr.printf(__VA_ARGS__); break;
[84648]454 CASE_MSG(VERR_ACCESS_DENIED , tr("Access to guest file \"%s\" denied"), pcszWhat);
455 CASE_MSG(VERR_ALREADY_EXISTS , tr("Guest file \"%s\" already exists"), pcszWhat);
456 CASE_MSG(VERR_FILE_NOT_FOUND , tr("Guest file \"%s\" not found"), pcszWhat);
457 CASE_MSG(VERR_NET_HOST_NOT_FOUND, tr("Host name \"%s\", not found"), pcszWhat);
458 CASE_MSG(VERR_SHARING_VIOLATION , tr("Sharing violation for guest file \"%s\""), pcszWhat);
[84054]459 default:
[91518]460 strErr.printf(tr("Error %Rrc for guest file \"%s\" occurred\n"), rcGuest, pcszWhat);
[84648]461 break;
[91518]462#undef CASE_MSG
[84054]463 }
[84648]464
465 return strErr;
[45109]466}
467
[92897]468/**
469 * Called when the guest side notifies the host of a file event.
470 *
471 * @returns VBox status code.
472 * @param pCbCtx Host callback context.
473 * @param pSvcCbData Host callback data.
474 */
[104001]475int GuestFile::i_onNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
[45109]476{
477 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
[44863]478 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
479
[47817]480 LogFlowThisFuncEnter();
481
[44863]482 if (pSvcCbData->mParms < 3)
483 return VERR_INVALID_PARAMETER;
484
[47817]485 int idx = 1; /* Current parameter index. */
[45109]486 CALLBACKDATA_FILE_NOTIFY dataCb;
[84508]487 RT_ZERO(dataCb);
[44863]488 /* pSvcCb->mpaParms[0] always contains the context ID. */
[75737]489 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.uType);
490 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.rc);
[44863]491
[94942]492 int vrcGuest = (int)dataCb.rc; /* uint32_t vs. int. */
[45415]493
[94942]494 LogFlowThisFunc(("uType=%RU32, vrcGuest=%Rrc\n", dataCb.uType, vrcGuest));
[47817]495
[94942]496 if (RT_FAILURE(vrcGuest))
[47817]497 {
[94942]498 int vrc2 = i_setFileStatus(FileStatus_Error, vrcGuest);
499 AssertRC(vrc2);
[47817]500
[98278]501 /* Ignore return code, as the event to signal might not be there (anymore). */
[94942]502 signalWaitEventInternal(pCbCtx, vrcGuest, NULL /* pPayload */);
[47817]503 return VINF_SUCCESS; /* Report to the guest. */
504 }
505
[71782]506 AssertMsg(mObjectID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID),
507 ("File ID %RU32 does not match object ID %RU32\n", mObjectID,
508 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));
509
[94942]510 int vrc = VERR_NOT_SUPPORTED; /* Play safe by default. */
[71782]511
[45109]512 switch (dataCb.uType)
513 {
514 case GUEST_FILE_NOTIFYTYPE_ERROR:
[45415]515 {
[94942]516 vrc = i_setFileStatus(FileStatus_Error, vrcGuest);
[45109]517 break;
[45415]518 }
[44863]519
[45109]520 case GUEST_FILE_NOTIFYTYPE_OPEN:
[45415]521 {
[45109]522 if (pSvcCbData->mParms == 4)
523 {
[94942]524 vrc = HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.u.open.uHandle);
525 if (RT_FAILURE(vrc))
[71782]526 break;
[45109]527
[45415]528 /* Set the process status. */
[94942]529 vrc = i_setFileStatus(FileStatus_Open, vrcGuest);
[45109]530 }
531 break;
[45415]532 }
[45109]533
534 case GUEST_FILE_NOTIFYTYPE_CLOSE:
[45415]535 {
[94942]536 vrc = i_setFileStatus(FileStatus_Closed, vrcGuest);
[45109]537 break;
[45415]538 }
[45109]539
540 case GUEST_FILE_NOTIFYTYPE_READ:
[47817]541 {
[97610]542 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 4, ("mParms=%u\n", pSvcCbData->mParms),
543 vrc = VERR_WRONG_PARAMETER_COUNT);
544 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx].type == VBOX_HGCM_SVC_PARM_PTR,
545 ("type=%u\n", pSvcCbData->mpaParms[idx].type),
546 vrc = VERR_WRONG_PARAMETER_TYPE);
[47817]547
[97610]548 vrc = HGCMSvcGetPv(&pSvcCbData->mpaParms[idx++], &dataCb.u.read.pvData, &dataCb.u.read.cbData);
549 if (RT_FAILURE(vrc))
550 break;
[71782]551
[97610]552 const uint32_t cbRead = dataCb.u.read.cbData;
553 Log3ThisFunc(("cbRead=%RU32\n", cbRead));
[71782]554
[97610]555 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
556 mData.mOffCurrent += cbRead; /* Bogus for readAt, which is why we've got GUEST_FILE_NOTIFYTYPE_READ_OFFSET. */
557 alock.release();
[45109]558
[97610]559 try
560 {
[48818]561 com::SafeArray<BYTE> data((size_t)cbRead);
[97610]562 AssertBreakStmt(data.size() == cbRead, vrc = VERR_NO_MEMORY);
[85307]563 data.initFrom((BYTE *)dataCb.u.read.pvData, cbRead);
[85300]564 ::FireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent, cbRead, ComSafeArrayAsInParam(data));
[45109]565 }
[97610]566 catch (std::bad_alloc &)
567 {
568 vrc = VERR_NO_MEMORY;
569 }
[45109]570 break;
[47817]571 }
[45109]572
[79296]573 case GUEST_FILE_NOTIFYTYPE_READ_OFFSET:
574 {
575 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 5, ("mParms=%u\n", pSvcCbData->mParms),
[94942]576 vrc = VERR_WRONG_PARAMETER_COUNT);
[79296]577 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx].type == VBOX_HGCM_SVC_PARM_PTR,
578 ("type=%u\n", pSvcCbData->mpaParms[idx].type),
[94942]579 vrc = VERR_WRONG_PARAMETER_TYPE);
[79296]580 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx + 1].type == VBOX_HGCM_SVC_PARM_64BIT,
[97610]581 ("type=%u\n", pSvcCbData->mpaParms[idx + 1].type),
[94942]582 vrc = VERR_WRONG_PARAMETER_TYPE);
[79296]583 BYTE const * const pbData = (BYTE const *)pSvcCbData->mpaParms[idx].u.pointer.addr;
584 uint32_t const cbRead = pSvcCbData->mpaParms[idx].u.pointer.size;
585 int64_t offNew = (int64_t)pSvcCbData->mpaParms[idx + 1].u.uint64;
586 Log3ThisFunc(("cbRead=%RU32 offNew=%RI64 (%#RX64)\n", cbRead, offNew, offNew));
587
588 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
589 if (offNew < 0) /* non-seekable */
590 offNew = mData.mOffCurrent + cbRead;
591 mData.mOffCurrent = offNew;
592 alock.release();
593
594 try
595 {
596 com::SafeArray<BYTE> data((size_t)cbRead);
[97610]597 AssertBreakStmt(data.size() == cbRead, vrc = VERR_NO_MEMORY);
[79296]598 data.initFrom(pbData, cbRead);
[85300]599 ::FireGuestFileReadEvent(mEventSource, mSession, this, offNew, cbRead, ComSafeArrayAsInParam(data));
[94942]600 vrc = VINF_SUCCESS;
[79296]601 }
602 catch (std::bad_alloc &)
603 {
[94942]604 vrc = VERR_NO_MEMORY;
[79296]605 }
606 break;
607 }
608
[45109]609 case GUEST_FILE_NOTIFYTYPE_WRITE:
[47817]610 {
[97610]611 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 4, ("mParms=%u\n", pSvcCbData->mParms),
612 vrc = VERR_WRONG_PARAMETER_COUNT);
613 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx].type == VBOX_HGCM_SVC_PARM_32BIT,
614 ("type=%u\n", pSvcCbData->mpaParms[idx].type),
615 vrc = VERR_WRONG_PARAMETER_TYPE);
[45109]616
[97610]617 uint32_t const cbWritten = pSvcCbData->mpaParms[idx].u.uint32;
[71782]618
[97610]619 Log3ThisFunc(("cbWritten=%RU32\n", cbWritten));
[77075]620
[97610]621 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
622 mData.mOffCurrent += cbWritten; /* Bogus for writeAt and append mode, thus GUEST_FILE_NOTIFYTYPE_WRITE_OFFSET. */
623 alock.release();
[47817]624
[97610]625 ::FireGuestFileWriteEvent(mEventSource, mSession, this, mData.mOffCurrent, cbWritten);
[45109]626 break;
[47817]627 }
[45109]628
[79296]629 case GUEST_FILE_NOTIFYTYPE_WRITE_OFFSET:
630 {
631 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 5, ("mParms=%u\n", pSvcCbData->mParms),
[94942]632 vrc = VERR_WRONG_PARAMETER_COUNT);
[79296]633 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx].type == VBOX_HGCM_SVC_PARM_32BIT,
634 ("type=%u\n", pSvcCbData->mpaParms[idx].type),
[94942]635 vrc = VERR_WRONG_PARAMETER_TYPE);
[79296]636 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx + 1].type == VBOX_HGCM_SVC_PARM_64BIT,
637 ("type=%u\n", pSvcCbData->mpaParms[idx].type),
[94942]638 vrc = VERR_WRONG_PARAMETER_TYPE);
[79296]639 uint32_t const cbWritten = pSvcCbData->mpaParms[idx].u.uint32;
640 int64_t offNew = (int64_t)pSvcCbData->mpaParms[idx + 1].u.uint64;
641 Log3ThisFunc(("cbWritten=%RU32 offNew=%RI64 (%#RX64)\n", cbWritten, offNew, offNew));
642
643 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
644 if (offNew < 0) /* non-seekable */
645 offNew = mData.mOffCurrent + cbWritten;
646 mData.mOffCurrent = offNew;
647 alock.release();
648
[85300]649 HRESULT hrc2 = ::FireGuestFileWriteEvent(mEventSource, mSession, this, offNew, cbWritten);
[94942]650 vrc = SUCCEEDED(hrc2) ? VINF_SUCCESS : Global::vboxStatusCodeFromCOM(hrc2);
[79296]651 break;
652 }
653
[45109]654 case GUEST_FILE_NOTIFYTYPE_SEEK:
[47817]655 {
[97610]656 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 4, ("mParms=%u\n", pSvcCbData->mParms),
657 vrc = VERR_WRONG_PARAMETER_COUNT);
[45109]658
[97610]659 vrc = HGCMSvcGetU64(&pSvcCbData->mpaParms[idx++], &dataCb.u.seek.uOffActual);
660 if (RT_FAILURE(vrc))
661 break;
[71782]662
[97610]663 Log3ThisFunc(("uOffActual=%RU64\n", dataCb.u.seek.uOffActual));
[47817]664
[97610]665 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
666 mData.mOffCurrent = dataCb.u.seek.uOffActual;
667 alock.release();
[45415]668
[97610]669 ::FireGuestFileOffsetChangedEvent(mEventSource, mSession, this, dataCb.u.seek.uOffActual, 0 /* Processed */);
[45109]670 break;
[47817]671 }
[45109]672
673 case GUEST_FILE_NOTIFYTYPE_TELL:
[79300]674 /* We don't issue any HOST_MSG_FILE_TELL, so we shouldn't get these notifications! */
675 AssertFailed();
[45109]676 break;
677
[79287]678 case GUEST_FILE_NOTIFYTYPE_SET_SIZE:
679 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 4, ("mParms=%u\n", pSvcCbData->mParms),
[94942]680 vrc = VERR_WRONG_PARAMETER_COUNT);
[79287]681 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx].type == VBOX_HGCM_SVC_PARM_64BIT,
682 ("type=%u\n", pSvcCbData->mpaParms[idx].type),
[94942]683 vrc = VERR_WRONG_PARAMETER_TYPE);
[79287]684 dataCb.u.SetSize.cbSize = pSvcCbData->mpaParms[idx].u.uint64;
685 Log3ThisFunc(("cbSize=%RU64\n", dataCb.u.SetSize.cbSize));
686
[85300]687 ::FireGuestFileSizeChangedEvent(mEventSource, mSession, this, dataCb.u.SetSize.cbSize);
[94942]688 vrc = VINF_SUCCESS;
[79287]689 break;
690
[45109]691 default:
692 break;
693 }
694
[97610]695 try
[49349]696 {
[97610]697 if (RT_SUCCESS(vrc))
[84745]698 {
699 GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb));
[71636]700
[98278]701 /* Ignore return code, as the event to signal might not be there (anymore). */
[94942]702 signalWaitEventInternal(pCbCtx, vrcGuest, &payload);
[84745]703 }
[97610]704 else /* OOM situation, wrong HGCM parameters or smth. not expected. */
[84745]705 {
[98278]706 /* Ignore return code, as the event to signal might not be there (anymore). */
[97610]707 signalWaitEventInternalEx(pCbCtx, vrc, 0 /* guestRc */, NULL /* pPayload */);
[84745]708 }
[49349]709 }
[97610]710 catch (int vrcEx) /* Thrown by GuestWaitEventPayload constructor. */
711 {
712 /* Also try to signal the waiter, to let it know of the OOM situation.
[98278]713 * Ignore return code, as the event to signal might not be there (anymore). */
[97610]714 signalWaitEventInternalEx(pCbCtx, vrcEx, 0 /* guestRc */, NULL /* pPayload */);
715 vrc = vrcEx;
716 }
[49349]717
[98278]718 LogFlowThisFunc(("uType=%RU32, rcGuest=%Rrc, vrc=%Rrc\n", dataCb.uType, vrcGuest, vrc));
[94942]719 return vrc;
[44863]720}
721
[92897]722/**
723 * Called when the guest side of the file has been disconnected (closed, terminated, +++).
724 *
725 * @returns VBox status code.
726 * @param pCbCtx Host callback context.
727 * @param pSvcCbData Host callback data.
728 */
[50618]729int GuestFile::i_onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
[44863]730{
[45109]731 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
732 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
[44863]733
[50618]734 int vrc = i_setFileStatus(FileStatus_Down, VINF_SUCCESS);
[44863]735
736 LogFlowFuncLeaveRC(vrc);
737 return vrc;
738}
739
[49504]740/**
[77587]741 * @copydoc GuestObject::i_onUnregister
[49504]742 */
[77587]743int GuestFile::i_onUnregister(void)
[49504]744{
745 LogFlowThisFuncEnter();
746
747 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
748
749 int vrc = VINF_SUCCESS;
750
[49610]751 /*
[49504]752 * Note: The event source stuff holds references to this object,
753 * so make sure that this is cleaned up *before* calling uninit().
754 */
755 if (!mEventSource.isNull())
756 {
757 mEventSource->UnregisterListener(mLocalListener);
758
759 mLocalListener.setNull();
760 unconst(mEventSource).setNull();
761 }
762
763 LogFlowFuncLeaveRC(vrc);
764 return vrc;
765}
766
[77587]767/**
768 * @copydoc GuestObject::i_onSessionStatusChange
769 */
770int GuestFile::i_onSessionStatusChange(GuestSessionStatus_T enmSessionStatus)
771{
772 LogFlowThisFuncEnter();
773
774 int vrc = VINF_SUCCESS;
775
776 /* If the session now is in a terminated state, set the file status
777 * to "down", as there is not much else we can do now. */
778 if (GuestSession::i_isTerminated(enmSessionStatus))
779 vrc = i_setFileStatus(FileStatus_Down, 0 /* fileRc, ignored */);
780
781 LogFlowFuncLeaveRC(vrc);
782 return vrc;
783}
784
[92897]785/**
786 * Opens the file on the guest.
787 *
788 * @returns VBox status code.
789 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
790 * @param uTimeoutMS Timeout (in ms) to wait.
791 * @param prcGuest Where to return the guest error when VERR_GSTCTL_GUEST_ERROR
792 * was returned. Optional.
793 */
[104001]794int GuestFile::i_open(uint32_t uTimeoutMS, int *prcGuest)
[44863]795{
[75926]796 AssertReturn(mData.mOpenInfo.mFilename.isNotEmpty(), VERR_INVALID_PARAMETER);
[71782]797
[47817]798 LogFlowThisFuncEnter();
799
[49006]800 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
[47817]801
[79285]802 LogFlowThisFunc(("strFile=%s, enmAccessMode=%d, enmOpenAction=%d, uCreationMode=%o, mfOpenEx=%#x\n",
[75926]803 mData.mOpenInfo.mFilename.c_str(), mData.mOpenInfo.mAccessMode, mData.mOpenInfo.mOpenAction,
[71782]804 mData.mOpenInfo.mCreationMode, mData.mOpenInfo.mfOpenEx));
805
806 /* Validate and translate open action. */
807 const char *pszOpenAction = NULL;
808 switch (mData.mOpenInfo.mOpenAction)
809 {
[72980]810 case FileOpenAction_OpenExisting: pszOpenAction = "oe"; break;
811 case FileOpenAction_OpenOrCreate: pszOpenAction = "oc"; break;
812 case FileOpenAction_CreateNew: pszOpenAction = "ce"; break;
813 case FileOpenAction_CreateOrReplace: pszOpenAction = "ca"; break;
814 case FileOpenAction_OpenExistingTruncated: pszOpenAction = "ot"; break;
815 case FileOpenAction_AppendOrCreate:
[71782]816 pszOpenAction = "oa"; /** @todo get rid of this one and implement AppendOnly/AppendRead. */
817 break;
818 default:
819 return VERR_INVALID_PARAMETER;
820 }
821
822 /* Validate and translate access mode. */
823 const char *pszAccessMode = NULL;
824 switch (mData.mOpenInfo.mAccessMode)
825 {
[72980]826 case FileAccessMode_ReadOnly: pszAccessMode = "r"; break;
827 case FileAccessMode_WriteOnly: pszAccessMode = "w"; break;
828 case FileAccessMode_ReadWrite: pszAccessMode = "r+"; break;
[79285]829 case FileAccessMode_AppendOnly: pszAccessMode = "a"; break;
830 case FileAccessMode_AppendRead: pszAccessMode = "a+"; break;
[72980]831 default: return VERR_INVALID_PARAMETER;
[71782]832 }
833
834 /* Validate and translate sharing mode. */
835 const char *pszSharingMode = NULL;
836 switch (mData.mOpenInfo.mSharingMode)
837 {
[72980]838 case FileSharingMode_All: pszSharingMode = ""; break;
839 case FileSharingMode_Read: RT_FALL_THRU();
840 case FileSharingMode_Write: RT_FALL_THRU();
841 case FileSharingMode_ReadWrite: RT_FALL_THRU();
842 case FileSharingMode_Delete: RT_FALL_THRU();
843 case FileSharingMode_ReadDelete: RT_FALL_THRU();
844 case FileSharingMode_WriteDelete: return VERR_NOT_IMPLEMENTED;
845 default: return VERR_INVALID_PARAMETER;
[71782]846 }
847
[45780]848 int vrc;
[44863]849
[45780]850 GuestWaitEvent *pEvent = NULL;
[49349]851 GuestEventTypes eventTypes;
[45780]852 try
853 {
854 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
855
[47469]856 vrc = registerWaitEvent(eventTypes, &pEvent);
[45780]857 }
[73505]858 catch (std::bad_alloc &)
[45780]859 {
860 vrc = VERR_NO_MEMORY;
861 }
862
863 if (RT_FAILURE(vrc))
864 return vrc;
865
[45109]866 /* Prepare HGCM call. */
867 VBOXHGCMSVCPARM paParms[8];
[45415]868 int i = 0;
[75737]869 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
[75926]870 HGCMSvcSetPv(&paParms[i++], (void*)mData.mOpenInfo.mFilename.c_str(),
871 (ULONG)mData.mOpenInfo.mFilename.length() + 1);
[75737]872 HGCMSvcSetStr(&paParms[i++], pszAccessMode);
873 HGCMSvcSetStr(&paParms[i++], pszOpenAction);
874 HGCMSvcSetStr(&paParms[i++], pszSharingMode);
875 HGCMSvcSetU32(&paParms[i++], mData.mOpenInfo.mCreationMode);
[79285]876 HGCMSvcSetU64(&paParms[i++], 0 /*unused offset*/);
[55668]877 /** @todo Next protocol version: add flags, replace strings, remove initial offset. */
[45109]878
[49006]879 alock.release(); /* Drop write lock before sending. */
[47817]880
[76958]881 vrc = sendMessage(HOST_MSG_FILE_OPEN, i, paParms);
[45415]882 if (RT_SUCCESS(vrc))
[71406]883 vrc = i_waitForStatusChange(pEvent, uTimeoutMS, NULL /* FileStatus */, prcGuest);
[45109]884
[47469]885 unregisterWaitEvent(pEvent);
[45780]886
[45109]887 LogFlowFuncLeaveRC(vrc);
888 return vrc;
889}
890
[92897]891/**
892 * Queries file system information from a guest file.
893 *
894 * @returns VBox status code.
895 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
896 * @param objData Where to store the file system object data on success.
897 * @param prcGuest Where to return the guest error when VERR_GSTCTL_GUEST_ERROR
898 * was returned. Optional.
899 */
[71782]900int GuestFile::i_queryInfo(GuestFsObjData &objData, int *prcGuest)
901{
[98526]902 AssertPtrReturn(mSession, VERR_OBJECT_DESTROYED);
[99252]903 return mSession->i_fsObjQueryInfo(mData.mOpenInfo.mFilename, FALSE /* fFollowSymlinks */, objData, prcGuest);
[71782]904}
905
[92897]906/**
907 * Reads data from a guest file.
908 *
909 * @returns VBox status code.
910 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
911 * @param uSize Size (in bytes) to read.
912 * @param uTimeoutMS Timeout (in ms) to wait.
913 * @param pvData Where to store the read data on success.
914 * @param cbData Size (in bytes) of \a pvData on input.
915 * @param pcbRead Where to return to size (in bytes) read on success.
916 * Optional.
917 */
[50618]918int GuestFile::i_readData(uint32_t uSize, uint32_t uTimeoutMS,
919 void* pvData, uint32_t cbData, uint32_t* pcbRead)
[45109]920{
[45434]921 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
922 AssertReturn(cbData, VERR_INVALID_PARAMETER);
923
[45109]924 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
925 uSize, uTimeoutMS, pvData, cbData));
[49006]926
927 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
928
[45780]929 int vrc;
[45109]930
[45780]931 GuestWaitEvent *pEvent = NULL;
[49349]932 GuestEventTypes eventTypes;
[45780]933 try
[45109]934 {
[45780]935 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
936 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
[45109]937
[47469]938 vrc = registerWaitEvent(eventTypes, &pEvent);
[45780]939 }
[73505]940 catch (std::bad_alloc &)
[45780]941 {
942 vrc = VERR_NO_MEMORY;
943 }
[45109]944
[45780]945 if (RT_FAILURE(vrc))
946 return vrc;
[45415]947
[45780]948 /* Prepare HGCM call. */
949 VBOXHGCMSVCPARM paParms[4];
950 int i = 0;
[75737]951 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
952 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
953 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
[45780]954
[49006]955 alock.release(); /* Drop write lock before sending. */
956
[76958]957 vrc = sendMessage(HOST_MSG_FILE_READ, i, paParms);
[45780]958 if (RT_SUCCESS(vrc))
[63154]959 {
960 uint32_t cbRead = 0;
[50618]961 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
[63154]962 if (RT_SUCCESS(vrc))
963 {
964 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
965 if (pcbRead)
966 *pcbRead = cbRead;
967 }
[98278]968 else if (pEvent->HasGuestError()) /* Return guest vrc if available. */
[98666]969 vrc = pEvent->GuestResult();
[45109]970 }
971
[47469]972 unregisterWaitEvent(pEvent);
[45780]973
[45109]974 LogFlowFuncLeaveRC(vrc);
975 return vrc;
976}
977
[92897]978/**
979 * Reads data from a specific position from a guest file.
980 *
981 * @returns VBox status code.
982 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
983 * @param uOffset Offset (in bytes) to start reading from.
984 * @param uSize Size (in bytes) to read.
985 * @param uTimeoutMS Timeout (in ms) to wait.
986 * @param pvData Where to store the read data on success.
987 * @param cbData Size (in bytes) of \a pvData on input.
988 * @param pcbRead Where to return to size (in bytes) read on success.
989 * Optional.
990 */
[50618]991int GuestFile::i_readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
992 void* pvData, size_t cbData, size_t* pcbRead)
[45109]993{
994 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
995 uOffset, uSize, uTimeoutMS, pvData, cbData));
[49006]996
997 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
998
[45780]999 int vrc;
[45109]1000
[45780]1001 GuestWaitEvent *pEvent = NULL;
[49349]1002 GuestEventTypes eventTypes;
[45780]1003 try
[45109]1004 {
[45780]1005 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1006 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
[45109]1007
[47469]1008 vrc = registerWaitEvent(eventTypes, &pEvent);
[45780]1009 }
[73505]1010 catch (std::bad_alloc &)
[45780]1011 {
1012 vrc = VERR_NO_MEMORY;
1013 }
[45109]1014
[45780]1015 if (RT_FAILURE(vrc))
1016 return vrc;
[45415]1017
[45780]1018 /* Prepare HGCM call. */
1019 VBOXHGCMSVCPARM paParms[4];
1020 int i = 0;
[75737]1021 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1022 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1023 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset (in bytes) to start reading */);
1024 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
[45415]1025
[49006]1026 alock.release(); /* Drop write lock before sending. */
1027
[76958]1028 vrc = sendMessage(HOST_MSG_FILE_READ_AT, i, paParms);
[45780]1029 if (RT_SUCCESS(vrc))
[63154]1030 {
1031 uint32_t cbRead = 0;
[50618]1032 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
[63154]1033 if (RT_SUCCESS(vrc))
1034 {
1035 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
[45780]1036
[63154]1037 if (pcbRead)
1038 *pcbRead = cbRead;
1039 }
[98278]1040 else if (pEvent->HasGuestError()) /* Return guest vrc if available. */
[98666]1041 vrc = pEvent->GuestResult();
[45109]1042 }
1043
[47469]1044 unregisterWaitEvent(pEvent);
[45780]1045
[45109]1046 LogFlowFuncLeaveRC(vrc);
1047 return vrc;
1048}
1049
[92897]1050/**
1051 * Seeks a guest file to a specific position.
1052 *
1053 * @returns VBox status code.
1054 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1055 * @param iOffset Offset (in bytes) to seek.
1056 * @param eSeekType Seek type to use.
1057 * @param uTimeoutMS Timeout (in ms) to wait.
1058 * @param puOffset Where to return the new current file position (in bytes) on success.
1059 */
[50618]1060int GuestFile::i_seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType,
1061 uint32_t uTimeoutMS, uint64_t *puOffset)
[45109]1062{
[48818]1063 LogFlowThisFunc(("iOffset=%RI64, uTimeoutMS=%RU32\n",
1064 iOffset, uTimeoutMS));
[49006]1065
1066 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1067
[45780]1068 int vrc;
[45109]1069
[45780]1070 GuestWaitEvent *pEvent = NULL;
[49349]1071 GuestEventTypes eventTypes;
[45780]1072 try
1073 {
1074 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1075 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
1076
[47469]1077 vrc = registerWaitEvent(eventTypes, &pEvent);
[45780]1078 }
[73505]1079 catch (std::bad_alloc &)
[45780]1080 {
1081 vrc = VERR_NO_MEMORY;
1082 }
1083
1084 if (RT_FAILURE(vrc))
1085 return vrc;
1086
[45109]1087 /* Prepare HGCM call. */
1088 VBOXHGCMSVCPARM paParms[4];
[45415]1089 int i = 0;
[75737]1090 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1091 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1092 HGCMSvcSetU32(&paParms[i++], eSeekType /* Seek method */);
[48818]1093 /** @todo uint64_t vs. int64_t! */
[75737]1094 HGCMSvcSetU64(&paParms[i++], (uint64_t)iOffset /* Offset (in bytes) to start reading */);
[45109]1095
[49006]1096 alock.release(); /* Drop write lock before sending. */
1097
[76958]1098 vrc = sendMessage(HOST_MSG_FILE_SEEK, i, paParms);
[45415]1099 if (RT_SUCCESS(vrc))
[72096]1100 {
1101 uint64_t uOffset;
1102 vrc = i_waitForOffsetChange(pEvent, uTimeoutMS, &uOffset);
1103 if (RT_SUCCESS(vrc))
1104 {
1105 LogFlowThisFunc(("uOffset=%RU64\n", uOffset));
[45109]1106
[72096]1107 if (puOffset)
1108 *puOffset = uOffset;
1109 }
[98278]1110 else if (pEvent->HasGuestError()) /* Return guest vrc if available. */
[98666]1111 vrc = pEvent->GuestResult();
[72096]1112 }
1113
[47469]1114 unregisterWaitEvent(pEvent);
[45780]1115
[45109]1116 LogFlowFuncLeaveRC(vrc);
1117 return vrc;
1118}
1119
[92897]1120/**
1121 * Sets the current internal file object status.
1122 *
1123 * @returns VBox status code.
1124 * @param fileStatus New file status to set.
[98278]1125 * @param vrcFile New result code to set.
[92897]1126 *
1127 * @note Takes the write lock.
1128 */
[98278]1129int GuestFile::i_setFileStatus(FileStatus_T fileStatus, int vrcFile)
[45415]1130{
[47817]1131 LogFlowThisFuncEnter();
1132
1133 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1134
[98278]1135 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, vrcFile=%Rrc\n", mData.mStatus, fileStatus, vrcFile));
[44863]1136
[45415]1137#ifdef VBOX_STRICT
1138 if (fileStatus == FileStatus_Error)
[98278]1139 AssertMsg(RT_FAILURE(vrcFile), ("Guest vrc must be an error (%Rrc)\n", vrcFile));
[45415]1140 else
[98278]1141 AssertMsg(RT_SUCCESS(vrcFile), ("Guest vrc must not be an error (%Rrc)\n", vrcFile));
[45415]1142#endif
1143
1144 if (mData.mStatus != fileStatus)
[44863]1145 {
[47817]1146 mData.mStatus = fileStatus;
[98278]1147 mData.mLastError = vrcFile;
[45415]1148
[45805]1149 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
[98278]1150 HRESULT hrc = errorInfo.createObject();
[98282]1151 ComAssertComRCRet(hrc, VERR_COM_UNEXPECTED);
[98278]1152 if (RT_FAILURE(vrcFile))
[45415]1153 {
[98282]1154 hrc = errorInfo->initEx(VBOX_E_GSTCTL_GUEST_ERROR, vrcFile,
[98278]1155 COM_IIDOF(IGuestFile), getComponentName(),
1156 i_guestErrorToString(vrcFile, mData.mOpenInfo.mFilename.c_str()));
[98282]1157 ComAssertComRCRet(hrc, VERR_COM_UNEXPECTED);
[45415]1158 }
[98282]1159 /* Note: On vrcFile success, errorInfo is set to S_OK and also sent via the event below. */
[45415]1160
[47817]1161 alock.release(); /* Release lock before firing off event. */
1162
[85300]1163 ::FireGuestFileStateChangedEvent(mEventSource, mSession, this, fileStatus, errorInfo);
[44863]1164 }
1165
[45415]1166 return VINF_SUCCESS;
1167}
1168
[92897]1169/**
1170 * Waits for a guest file offset change.
1171 *
1172 * @returns VBox status code.
1173 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1174 * @param pEvent Guest wait event to wait for.
1175 * @param uTimeoutMS Timeout (in ms) to wait.
1176 * @param puOffset Where to return the new offset (in bytes) on success.
1177 * Optional and can be NULL.
1178 */
[50618]1179int GuestFile::i_waitForOffsetChange(GuestWaitEvent *pEvent,
1180 uint32_t uTimeoutMS, uint64_t *puOffset)
[45415]1181{
[45780]1182 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
[45415]1183
[49440]1184 VBoxEventType_T evtType;
1185 ComPtr<IEvent> pIEvent;
[45780]1186 int vrc = waitForEvent(pEvent, uTimeoutMS,
[49440]1187 &evtType, pIEvent.asOutParam());
[45780]1188 if (RT_SUCCESS(vrc))
[44863]1189 {
[49440]1190 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
1191 {
1192 if (puOffset)
1193 {
1194 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
1195 Assert(!pFileEvent.isNull());
[45415]1196
[49440]1197 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
1198 ComAssertComRC(hr);
1199 }
1200 }
1201 else
1202 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
[44863]1203 }
1204
1205 return vrc;
1206}
1207
[92897]1208/**
1209 * Waits for reading from a guest file.
1210 *
1211 * @returns VBox status code.
1212 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1213 * @param pEvent Guest wait event to wait for.
1214 * @param uTimeoutMS Timeout (in ms) to wait.
1215 * @param pvData Where to store read file data on success.
1216 * @param cbData Size (in bytes) of \a pvData.
1217 * @param pcbRead Where to return the actual bytes read on success.
1218 * Optional and can be NULL.
1219 */
[50618]1220int GuestFile::i_waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1221 void *pvData, size_t cbData, uint32_t *pcbRead)
[45434]1222{
[45780]1223 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
[45434]1224
[49440]1225 VBoxEventType_T evtType;
1226 ComPtr<IEvent> pIEvent;
[45780]1227 int vrc = waitForEvent(pEvent, uTimeoutMS,
[49440]1228 &evtType, pIEvent.asOutParam());
[45780]1229 if (RT_SUCCESS(vrc))
[45434]1230 {
[49440]1231 if (evtType == VBoxEventType_OnGuestFileRead)
1232 {
[79253]1233 vrc = VINF_SUCCESS;
1234
[49440]1235 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
1236 Assert(!pFileEvent.isNull());
[49349]1237
[49440]1238 if (pvData)
1239 {
1240 com::SafeArray <BYTE> data;
[79253]1241 HRESULT hrc1 = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1242 ComAssertComRC(hrc1);
[71782]1243 const size_t cbRead = data.size();
1244 if (cbRead)
[49440]1245 {
[71782]1246 if (cbRead <= cbData)
1247 memcpy(pvData, data.raw(), cbRead);
1248 else
1249 vrc = VERR_BUFFER_OVERFLOW;
[49440]1250 }
[79253]1251 /* else: used to be VERR_NO_DATA, but that messes stuff up. */
1252
1253 if (pcbRead)
1254 {
1255 *pcbRead = (uint32_t)cbRead;
1256 Assert(*pcbRead == cbRead);
1257 }
[49440]1258 }
[79253]1259 else if (pcbRead)
[49440]1260 {
[79253]1261 *pcbRead = 0;
1262 HRESULT hrc2 = pFileEvent->COMGETTER(Processed)((ULONG *)pcbRead);
1263 ComAssertComRC(hrc2); NOREF(hrc2);
[49440]1264 }
[45434]1265 }
[45780]1266 else
[49440]1267 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
[45434]1268 }
1269
1270 return vrc;
1271}
1272
[78234]1273/**
[92897]1274 * Waits for a guest file status change.
[78234]1275 *
1276 * @note Similar code in GuestProcess::i_waitForStatusChange() and
1277 * GuestSession::i_waitForStatusChange().
[92897]1278 *
1279 * @returns VBox status code.
1280 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1281 * @param pEvent Guest wait event to wait for.
1282 * @param uTimeoutMS Timeout (in ms) to wait.
1283 * @param pFileStatus Where to return the file status on success.
1284 * @param prcGuest Where to return the guest error when VERR_GSTCTL_GUEST_ERROR
1285 * was returned.
[78234]1286 */
[50618]1287int GuestFile::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
[71299]1288 FileStatus_T *pFileStatus, int *prcGuest)
[45434]1289{
[45780]1290 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
[49440]1291 /* pFileStatus is optional. */
[45780]1292
[49440]1293 VBoxEventType_T evtType;
1294 ComPtr<IEvent> pIEvent;
[45780]1295 int vrc = waitForEvent(pEvent, uTimeoutMS,
[49440]1296 &evtType, pIEvent.asOutParam());
[45780]1297 if (RT_SUCCESS(vrc))
[45434]1298 {
[49440]1299 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
1300 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
1301 Assert(!pFileEvent.isNull());
[45434]1302
[49440]1303 HRESULT hr;
1304 if (pFileStatus)
1305 {
1306 hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1307 ComAssertComRC(hr);
1308 }
[47817]1309
[49440]1310 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1311 hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam());
1312 ComAssertComRC(hr);
[47817]1313
[49440]1314 LONG lGuestRc;
1315 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1316 ComAssertComRC(hr);
1317
1318 LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n",
1319 lGuestRc, lGuestRc));
1320
1321 if (RT_FAILURE((int)lGuestRc))
1322 vrc = VERR_GSTCTL_GUEST_ERROR;
1323
[71299]1324 if (prcGuest)
1325 *prcGuest = (int)lGuestRc;
[45434]1326 }
[78234]1327 /* waitForEvent may also return VERR_GSTCTL_GUEST_ERROR like we do above, so make prcGuest is set. */
1328 /** @todo r=bird: Andy, you seem to have forgotten this scenario. Showed up occasionally when
1329 * using the wrong password with a copyto command in a debug build on windows, error info
1330 * contained "Unknown Status -858993460 (0xcccccccc)". As you know windows fills the stack frames
1331 * with 0xcccccccc in debug builds to highlight use of uninitialized data, so that's what happened
1332 * here. It's actually good you didn't initialize lGuest, as it would be heck to find otherwise.
1333 *
1334 * I'm still not very impressed with the error managment or the usuefullness of the documentation
1335 * in this code, though the latter is getting better! */
1336 else if (vrc == VERR_GSTCTL_GUEST_ERROR && prcGuest)
1337 *prcGuest = pEvent->GuestResult();
1338 Assert(vrc != VERR_GSTCTL_GUEST_ERROR || !prcGuest || *prcGuest != (int)0xcccccccc);
[45434]1339
1340 return vrc;
1341}
1342
[50618]1343int GuestFile::i_waitForWrite(GuestWaitEvent *pEvent,
1344 uint32_t uTimeoutMS, uint32_t *pcbWritten)
[45109]1345{
[45780]1346 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1347
[49440]1348 VBoxEventType_T evtType;
1349 ComPtr<IEvent> pIEvent;
[45780]1350 int vrc = waitForEvent(pEvent, uTimeoutMS,
[49440]1351 &evtType, pIEvent.asOutParam());
[45780]1352 if (RT_SUCCESS(vrc))
[45434]1353 {
[49440]1354 if (evtType == VBoxEventType_OnGuestFileWrite)
1355 {
1356 if (pcbWritten)
1357 {
1358 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1359 Assert(!pFileEvent.isNull());
[45434]1360
[49440]1361 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1362 ComAssertComRC(hr);
1363 }
1364 }
1365 else
1366 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
[45434]1367 }
1368
1369 return vrc;
[45109]1370}
1371
[92897]1372/**
1373 * Writes data to a guest file.
1374 *
1375 * @returns VBox status code.
1376 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1377 * @param uTimeoutMS Timeout (in ms) to wait.
1378 * @param pvData Data to write.
1379 * @param cbData Size (in bytes) of \a pvData to write.
1380 * @param pcbWritten Where to return to size (in bytes) written on success.
1381 * Optional.
1382 */
[77387]1383int GuestFile::i_writeData(uint32_t uTimeoutMS, const void *pvData, uint32_t cbData,
[50618]1384 uint32_t *pcbWritten)
[45109]1385{
1386 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1387 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1388
1389 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1390 uTimeoutMS, pvData, cbData));
[49006]1391
1392 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1393
[45780]1394 int vrc;
[45109]1395
[45780]1396 GuestWaitEvent *pEvent = NULL;
[49349]1397 GuestEventTypes eventTypes;
[45780]1398 try
[45109]1399 {
[45780]1400 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1401 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
[45109]1402
[47469]1403 vrc = registerWaitEvent(eventTypes, &pEvent);
[45780]1404 }
[73505]1405 catch (std::bad_alloc &)
[45780]1406 {
1407 vrc = VERR_NO_MEMORY;
1408 }
[45109]1409
[45780]1410 if (RT_FAILURE(vrc))
1411 return vrc;
[45109]1412
[45780]1413 /* Prepare HGCM call. */
1414 VBOXHGCMSVCPARM paParms[8];
1415 int i = 0;
[75737]1416 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1417 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1418 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
[77387]1419 HGCMSvcSetPv (&paParms[i++], unconst(pvData), cbData);
[45780]1420
[49006]1421 alock.release(); /* Drop write lock before sending. */
1422
[76958]1423 vrc = sendMessage(HOST_MSG_FILE_WRITE, i, paParms);
[45780]1424 if (RT_SUCCESS(vrc))
[63154]1425 {
1426 uint32_t cbWritten = 0;
[50618]1427 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
[63154]1428 if (RT_SUCCESS(vrc))
1429 {
1430 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
[71816]1431 if (pcbWritten)
[63154]1432 *pcbWritten = cbWritten;
1433 }
[98278]1434 else if (pEvent->HasGuestError()) /* Return guest vrc if available. */
[98666]1435 vrc = pEvent->GuestResult();
[45109]1436 }
1437
[47469]1438 unregisterWaitEvent(pEvent);
[45780]1439
[45109]1440 LogFlowFuncLeaveRC(vrc);
1441 return vrc;
1442}
1443
[92897]1444
1445/**
1446 * Writes data to a specific position to a guest file.
1447 *
1448 * @returns VBox status code.
1449 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1450 * @param uOffset Offset (in bytes) to start writing at.
1451 * @param uTimeoutMS Timeout (in ms) to wait.
1452 * @param pvData Data to write.
1453 * @param cbData Size (in bytes) of \a pvData to write.
1454 * @param pcbWritten Where to return to size (in bytes) written on success.
1455 * Optional.
1456 */
[50618]1457int GuestFile::i_writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
[77387]1458 const void *pvData, uint32_t cbData, uint32_t *pcbWritten)
[45109]1459{
1460 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1461 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1462
1463 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1464 uOffset, uTimeoutMS, pvData, cbData));
[49006]1465
1466 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1467
[45780]1468 int vrc;
[45109]1469
[45780]1470 GuestWaitEvent *pEvent = NULL;
[49349]1471 GuestEventTypes eventTypes;
[45780]1472 try
[45109]1473 {
[45780]1474 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1475 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
[45109]1476
[47469]1477 vrc = registerWaitEvent(eventTypes, &pEvent);
[45780]1478 }
[73505]1479 catch (std::bad_alloc &)
[45780]1480 {
1481 vrc = VERR_NO_MEMORY;
1482 }
[45434]1483
[45780]1484 if (RT_FAILURE(vrc))
1485 return vrc;
[45109]1486
[45780]1487 /* Prepare HGCM call. */
1488 VBOXHGCMSVCPARM paParms[8];
1489 int i = 0;
[75737]1490 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1491 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1492 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset where to starting writing */);
1493 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
[77387]1494 HGCMSvcSetPv (&paParms[i++], unconst(pvData), cbData);
[45780]1495
[49006]1496 alock.release(); /* Drop write lock before sending. */
1497
[76958]1498 vrc = sendMessage(HOST_MSG_FILE_WRITE_AT, i, paParms);
[45780]1499 if (RT_SUCCESS(vrc))
[63154]1500 {
1501 uint32_t cbWritten = 0;
[50618]1502 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
[63154]1503 if (RT_SUCCESS(vrc))
1504 {
1505 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
[71816]1506 if (pcbWritten)
[63154]1507 *pcbWritten = cbWritten;
1508 }
[98278]1509 else if (pEvent->HasGuestError()) /* Return guest vrc if available. */
[98666]1510 vrc = pEvent->GuestResult();
[45109]1511 }
1512
[47469]1513 unregisterWaitEvent(pEvent);
[45780]1514
[45109]1515 LogFlowFuncLeaveRC(vrc);
1516 return vrc;
1517}
1518
[50618]1519// Wrapped IGuestFile methods
[42084]1520/////////////////////////////////////////////////////////////////////////////
[50618]1521HRESULT GuestFile::close()
[42084]1522{
[71560]1523 AutoCaller autoCaller(this);
[98262]1524 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71560]1525
[42846]1526 LogFlowThisFuncEnter();
[42084]1527
[45109]1528 /* Close file on guest. */
[94942]1529 int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
[104001]1530 int vrc = i_close(&vrcGuest);
[73003]1531 if (RT_FAILURE(vrc))
[45109]1532 {
[73003]1533 if (vrc == VERR_GSTCTL_GUEST_ERROR)
[91503]1534 {
[94942]1535 GuestErrorInfo ge(GuestErrorInfo::Type_File, vrcGuest, mData.mOpenInfo.mFilename.c_str());
1536 return setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Closing guest file failed: %s"),
[91516]1537 GuestBase::getErrorAsString(ge).c_str());
[91503]1538 }
[84648]1539 return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Closing guest file \"%s\" failed with %Rrc\n"),
1540 mData.mOpenInfo.mFilename.c_str(), vrc);
[45109]1541 }
1542
[73003]1543 LogFlowThisFunc(("Returning S_OK / vrc=%Rrc\n", vrc));
[42846]1544 return S_OK;
[42084]1545}
1546
[50618]1547HRESULT GuestFile::queryInfo(ComPtr<IFsObjInfo> &aObjInfo)
[42084]1548{
[71782]1549 AutoCaller autoCaller(this);
[98262]1550 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71782]1551
1552 LogFlowThisFuncEnter();
1553
[94942]1554 HRESULT hrc = S_OK;
[71782]1555
[79189]1556 GuestFsObjData fsObjData;
[94942]1557 int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1558 int vrc = i_queryInfo(fsObjData, &vrcGuest);
[71782]1559 if (RT_SUCCESS(vrc))
1560 {
1561 ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
[94942]1562 hrc = ptrFsObjInfo.createObject();
1563 if (SUCCEEDED(hrc))
[71782]1564 {
1565 vrc = ptrFsObjInfo->init(fsObjData);
1566 if (RT_SUCCESS(vrc))
[94942]1567 hrc = ptrFsObjInfo.queryInterfaceTo(aObjInfo.asOutParam());
[71782]1568 else
[94942]1569 hrc = setErrorVrc(vrc,
1570 tr("Initialization of guest file object for \"%s\" failed: %Rrc"),
1571 mData.mOpenInfo.mFilename.c_str(), vrc);
[71782]1572 }
1573 }
1574 else
1575 {
1576 if (GuestProcess::i_isGuestError(vrc))
[91503]1577 {
[98526]1578 GuestErrorInfo ge(
1579#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
1580 GuestErrorInfo::Type_ToolStat,
1581#else
1582 GuestErrorInfo::Type_File,
1583#endif
1584 vrcGuest, mData.mOpenInfo.mFilename.c_str());
[94942]1585 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Querying guest file information failed: %s"),
1586 GuestBase::getErrorAsString(ge).c_str());
[91503]1587 }
[71782]1588 else
[94942]1589 hrc = setErrorVrc(vrc,
1590 tr("Querying guest file information for \"%s\" failed: %Rrc"), mData.mOpenInfo.mFilename.c_str(), vrc);
[71782]1591 }
1592
1593 LogFlowFuncLeaveRC(vrc);
[94942]1594 return hrc;
[42084]1595}
1596
[55631]1597HRESULT GuestFile::querySize(LONG64 *aSize)
1598{
[71782]1599 AutoCaller autoCaller(this);
[98262]1600 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71782]1601
1602 LogFlowThisFuncEnter();
1603
[94942]1604 HRESULT hrc = S_OK;
[71782]1605
[79189]1606 GuestFsObjData fsObjData;
[94942]1607 int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1608 int vrc = i_queryInfo(fsObjData, &vrcGuest);
[71782]1609 if (RT_SUCCESS(vrc))
1610 {
1611 *aSize = fsObjData.mObjectSize;
1612 }
1613 else
1614 {
1615 if (GuestProcess::i_isGuestError(vrc))
[91503]1616 {
[98526]1617 GuestErrorInfo ge(
1618#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
1619 GuestErrorInfo::Type_ToolStat,
1620#else
1621 GuestErrorInfo::Type_File,
1622#endif
1623 vrcGuest, mData.mOpenInfo.mFilename.c_str());
[94942]1624 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Querying guest file size failed: %s"),
1625 GuestBase::getErrorAsString(ge).c_str());
[91503]1626 }
[71782]1627 else
[94942]1628 hrc = setErrorVrc(vrc, tr("Querying guest file size for \"%s\" failed: %Rrc"), mData.mOpenInfo.mFilename.c_str(), vrc);
[71782]1629 }
1630
1631 LogFlowFuncLeaveRC(vrc);
[94942]1632 return hrc;
[55631]1633}
1634
[50618]1635HRESULT GuestFile::read(ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
[42084]1636{
[71560]1637 AutoCaller autoCaller(this);
[98262]1638 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71560]1639
[45109]1640 if (aToRead == 0)
1641 return setError(E_INVALIDARG, tr("The size to read is zero"));
1642
[71560]1643 LogFlowThisFuncEnter();
1644
[79278]1645 /* Cap the read at 1MiB because that's all the guest will return anyway. */
1646 if (aToRead > _1M)
1647 aToRead = _1M;
1648
[94942]1649 HRESULT hrc = S_OK;
[45109]1650
[97609]1651 int vrc;
1652 try
1653 {
1654 aData.resize(aToRead);
1655
1656 uint32_t cbRead;
1657 vrc = i_readData(aToRead, aTimeoutMS,
[52934]1658 &aData.front(), aToRead, &cbRead);
[50618]1659
[97609]1660 if (RT_SUCCESS(vrc))
1661 {
1662 if (aData.size() != cbRead)
1663 aData.resize(cbRead);
1664 }
1665 else
1666 {
1667 aData.resize(0);
1668 }
1669 }
1670 catch (std::bad_alloc &)
[45109]1671 {
[97609]1672 vrc = VERR_NO_MEMORY;
[45109]1673 }
[52934]1674
[97609]1675 if (RT_FAILURE(vrc))
[94942]1676 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" failed: %Rrc"),
1677 mData.mOpenInfo.mFilename.c_str(), vrc);
[45109]1678
1679 LogFlowFuncLeaveRC(vrc);
[94942]1680 return hrc;
[42084]1681}
[71782]1682
[50618]1683HRESULT GuestFile::readAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
[42084]1684{
[71560]1685 AutoCaller autoCaller(this);
[98262]1686 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71560]1687
[45109]1688 if (aToRead == 0)
[84648]1689 return setError(E_INVALIDARG, tr("The size to read for guest file \"%s\" is zero"), mData.mOpenInfo.mFilename.c_str());
[45109]1690
[71560]1691 LogFlowThisFuncEnter();
1692
[79278]1693 /* Cap the read at 1MiB because that's all the guest will return anyway. */
1694 if (aToRead > _1M)
1695 aToRead = _1M;
1696
[94942]1697 HRESULT hrc = S_OK;
[45109]1698
[97609]1699 int vrc;
1700 try
1701 {
1702 aData.resize(aToRead);
1703
1704 size_t cbRead;
1705 vrc = i_readDataAt(aOffset, aToRead, aTimeoutMS,
[52934]1706 &aData.front(), aToRead, &cbRead);
[97609]1707 if (RT_SUCCESS(vrc))
1708 {
1709 if (aData.size() != cbRead)
1710 aData.resize(cbRead);
1711 }
1712 else
1713 {
1714 aData.resize(0);
1715 }
1716 }
1717 catch (std::bad_alloc &)
[45109]1718 {
[97609]1719 vrc = VERR_NO_MEMORY;
[45109]1720 }
[52934]1721
[97609]1722 if (RT_FAILURE(vrc))
[94942]1723 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1724 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
[45109]1725
1726 LogFlowFuncLeaveRC(vrc);
[94942]1727 return hrc;
[42084]1728}
1729
[55631]1730HRESULT GuestFile::seek(LONG64 aOffset, FileSeekOrigin_T aWhence, LONG64 *aNewOffset)
[42084]1731{
[71560]1732 AutoCaller autoCaller(this);
[98262]1733 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[45109]1734
[94942]1735 HRESULT hrc = S_OK;
[45109]1736
1737 GUEST_FILE_SEEKTYPE eSeekType;
[50618]1738 switch (aWhence)
[45109]1739 {
[55668]1740 case FileSeekOrigin_Begin:
[45109]1741 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1742 break;
1743
[55631]1744 case FileSeekOrigin_Current:
[45109]1745 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1746 break;
1747
[55631]1748 case FileSeekOrigin_End:
1749 eSeekType = GUEST_FILE_SEEKTYPE_END;
1750 break;
1751
[45109]1752 default:
[84648]1753 return setError(E_INVALIDARG, tr("Invalid seek type for guest file \"%s\" specified"),
1754 mData.mOpenInfo.mFilename.c_str());
[45109]1755 }
1756
[71560]1757 LogFlowThisFuncEnter();
1758
[55631]1759 uint64_t uNewOffset;
[50618]1760 int vrc = i_seekAt(aOffset, eSeekType,
[55631]1761 30 * 1000 /* 30s timeout */, &uNewOffset);
1762 if (RT_SUCCESS(vrc))
1763 *aNewOffset = RT_MIN(uNewOffset, (uint64_t)INT64_MAX);
1764 else
[94942]1765 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"),
1766 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
[45109]1767
1768 LogFlowFuncLeaveRC(vrc);
[94942]1769 return hrc;
[42084]1770}
1771
[55631]1772HRESULT GuestFile::setACL(const com::Utf8Str &aAcl, ULONG aMode)
[42084]1773{
[63244]1774 RT_NOREF(aAcl, aMode);
[42084]1775 ReturnComNotImplemented();
1776}
1777
[55631]1778HRESULT GuestFile::setSize(LONG64 aSize)
1779{
[79287]1780 LogFlowThisFuncEnter();
1781
1782 /*
1783 * Validate.
1784 */
1785 if (aSize < 0)
[84648]1786 return setError(E_INVALIDARG, tr("The size (%RI64) for guest file \"%s\" cannot be a negative value"),
1787 aSize, mData.mOpenInfo.mFilename.c_str());
[79287]1788
1789 /*
1790 * Register event callbacks.
1791 */
1792 int vrc;
1793 GuestWaitEvent *pWaitEvent = NULL;
1794 GuestEventTypes lstEventTypes;
1795 try
1796 {
1797 lstEventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1798 lstEventTypes.push_back(VBoxEventType_OnGuestFileSizeChanged);
1799 }
1800 catch (std::bad_alloc &)
1801 {
1802 return E_OUTOFMEMORY;
1803 }
1804
1805 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1806
1807 vrc = registerWaitEvent(lstEventTypes, &pWaitEvent);
1808 if (RT_SUCCESS(vrc))
1809 {
1810 /*
1811 * Send of the HGCM message.
1812 */
1813 VBOXHGCMSVCPARM aParms[3];
1814 HGCMSvcSetU32(&aParms[0], pWaitEvent->ContextID());
1815 HGCMSvcSetU32(&aParms[1], mObjectID /* File handle */);
1816 HGCMSvcSetU64(&aParms[2], aSize);
1817
1818 alock.release(); /* Drop write lock before sending. */
1819
1820 vrc = sendMessage(HOST_MSG_FILE_SET_SIZE, RT_ELEMENTS(aParms), aParms);
1821 if (RT_SUCCESS(vrc))
1822 {
1823 /*
1824 * Wait for the event.
1825 */
1826 VBoxEventType_T enmEvtType;
1827 ComPtr<IEvent> pIEvent;
1828 vrc = waitForEvent(pWaitEvent, RT_MS_1MIN / 2, &enmEvtType, pIEvent.asOutParam());
1829 if (RT_SUCCESS(vrc))
1830 {
1831 if (enmEvtType == VBoxEventType_OnGuestFileSizeChanged)
1832 vrc = VINF_SUCCESS;
1833 else
1834 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1835 }
[98666]1836
1837 if (pWaitEvent->HasGuestError()) /* Return guest vrc if available. */
1838 vrc = pWaitEvent->GuestResult();
[79287]1839 }
1840
1841 /*
1842 * Unregister the wait event and deal with error reporting if needed.
1843 */
1844 unregisterWaitEvent(pWaitEvent);
1845 }
1846 HRESULT hrc;
1847 if (RT_SUCCESS(vrc))
1848 hrc = S_OK;
1849 else
[91718]1850 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
1851 tr("Setting the guest file size of \"%s\" to %RU64 (%#RX64) bytes failed: %Rrc", "", aSize),
[79287]1852 mData.mOpenInfo.mFilename.c_str(), aSize, aSize, vrc);
1853 LogFlowFuncLeaveRC(vrc);
1854 return hrc;
[55631]1855}
1856
[50618]1857HRESULT GuestFile::write(const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
[42084]1858{
[71560]1859 AutoCaller autoCaller(this);
[98262]1860 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71560]1861
[77386]1862 if (aData.size() == 0)
[84648]1863 return setError(E_INVALIDARG, tr("No data to write specified"), mData.mOpenInfo.mFilename.c_str());
[77386]1864
[45109]1865 LogFlowThisFuncEnter();
1866
[94942]1867 HRESULT hrc = S_OK;
[45109]1868
[77387]1869 const uint32_t cbData = (uint32_t)aData.size();
1870 const void *pvData = (void *)&aData.front();
[71560]1871 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
[45109]1872 if (RT_FAILURE(vrc))
[94942]1873 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zu bytes to guest file \"%s\" failed: %Rrc", "", aData.size()),
1874 aData.size(), mData.mOpenInfo.mFilename.c_str(), vrc);
[45109]1875
1876 LogFlowFuncLeaveRC(vrc);
[94942]1877 return hrc;
[42084]1878}
1879
[50618]1880HRESULT GuestFile::writeAt(LONG64 aOffset, const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
[42084]1881{
[71560]1882 AutoCaller autoCaller(this);
[98262]1883 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71560]1884
[77386]1885 if (aData.size() == 0)
[84648]1886 return setError(E_INVALIDARG, tr("No data to write at for guest file \"%s\" specified"), mData.mOpenInfo.mFilename.c_str());
[77386]1887
[45109]1888 LogFlowThisFuncEnter();
1889
[94942]1890 HRESULT hrc = S_OK;
[45109]1891
[77387]1892 const uint32_t cbData = (uint32_t)aData.size();
1893 const void *pvData = (void *)&aData.front();
[79282]1894 int vrc = i_writeDataAt(aOffset, aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
[45109]1895 if (RT_FAILURE(vrc))
[94942]1896 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
1897 tr("Writing %zu bytes to file \"%s\" (at offset %RU64) failed: %Rrc", "", aData.size()),
1898 aData.size(), mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
[45109]1899
1900 LogFlowFuncLeaveRC(vrc);
[94942]1901 return hrc;
[42084]1902}
1903
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