VirtualBox

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

Last change on this file was 104003, checked in by vboxsync, 2 months ago

Guest Control/Main: Added a new define GSTCTL_DEFAULT_TIMEOUT_MS and replaced most of the hardcoded timeout values with it.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.4 KB
RevLine 
[42084]1/* $Id: GuestFileImpl.cpp 104003 2024-03-22 16:13:12Z 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))
[104003]423 vrc = i_waitForStatusChange(pEvent, GSTCTL_DEFAULT_TIMEOUT_MS, NULL /* FileStatus */, prcGuest);
[47469]424 unregisterWaitEvent(pEvent);
[45780]425
[97626]426 /* Unregister the file object from the guest session. */
427 AssertPtr(mSession);
428 int vrc2 = mSession->i_fileUnregister(this);
429 if (RT_SUCCESS(vrc))
430 vrc = vrc2;
431
[45109]432 LogFlowFuncLeaveRC(vrc);
433 return vrc;
434}
435
[78666]436/**
[84648]437 * Converts a given guest file error to a string.
[78666]438 *
[84648]439 * @returns Error string.
440 * @param rcGuest Guest file error to return string for.
441 * @param pcszWhat Hint of what was involved when the error occurred.
[78666]442 */
[84648]443/* static */
444Utf8Str GuestFile::i_guestErrorToString(int rcGuest, const char *pcszWhat)
[78666]445{
[84648]446 AssertPtrReturn(pcszWhat, "");
447
448 Utf8Str strErr;
[84054]449 switch (rcGuest)
450 {
[91518]451#define CASE_MSG(a_iRc, ...) \
452 case a_iRc: strErr.printf(__VA_ARGS__); break;
[84648]453 CASE_MSG(VERR_ACCESS_DENIED , tr("Access to guest file \"%s\" denied"), pcszWhat);
454 CASE_MSG(VERR_ALREADY_EXISTS , tr("Guest file \"%s\" already exists"), pcszWhat);
455 CASE_MSG(VERR_FILE_NOT_FOUND , tr("Guest file \"%s\" not found"), pcszWhat);
456 CASE_MSG(VERR_NET_HOST_NOT_FOUND, tr("Host name \"%s\", not found"), pcszWhat);
457 CASE_MSG(VERR_SHARING_VIOLATION , tr("Sharing violation for guest file \"%s\""), pcszWhat);
[84054]458 default:
[91518]459 strErr.printf(tr("Error %Rrc for guest file \"%s\" occurred\n"), rcGuest, pcszWhat);
[84648]460 break;
[91518]461#undef CASE_MSG
[84054]462 }
[84648]463
464 return strErr;
[45109]465}
466
[92897]467/**
468 * Called when the guest side notifies the host of a file event.
469 *
470 * @returns VBox status code.
471 * @param pCbCtx Host callback context.
472 * @param pSvcCbData Host callback data.
473 */
[104001]474int GuestFile::i_onNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
[45109]475{
476 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
[44863]477 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
478
[47817]479 LogFlowThisFuncEnter();
480
[44863]481 if (pSvcCbData->mParms < 3)
482 return VERR_INVALID_PARAMETER;
483
[47817]484 int idx = 1; /* Current parameter index. */
[45109]485 CALLBACKDATA_FILE_NOTIFY dataCb;
[84508]486 RT_ZERO(dataCb);
[44863]487 /* pSvcCb->mpaParms[0] always contains the context ID. */
[75737]488 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.uType);
489 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.rc);
[44863]490
[94942]491 int vrcGuest = (int)dataCb.rc; /* uint32_t vs. int. */
[45415]492
[94942]493 LogFlowThisFunc(("uType=%RU32, vrcGuest=%Rrc\n", dataCb.uType, vrcGuest));
[47817]494
[94942]495 if (RT_FAILURE(vrcGuest))
[47817]496 {
[94942]497 int vrc2 = i_setFileStatus(FileStatus_Error, vrcGuest);
498 AssertRC(vrc2);
[47817]499
[98278]500 /* Ignore return code, as the event to signal might not be there (anymore). */
[94942]501 signalWaitEventInternal(pCbCtx, vrcGuest, NULL /* pPayload */);
[47817]502 return VINF_SUCCESS; /* Report to the guest. */
503 }
504
[71782]505 AssertMsg(mObjectID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID),
506 ("File ID %RU32 does not match object ID %RU32\n", mObjectID,
507 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));
508
[94942]509 int vrc = VERR_NOT_SUPPORTED; /* Play safe by default. */
[71782]510
[45109]511 switch (dataCb.uType)
512 {
513 case GUEST_FILE_NOTIFYTYPE_ERROR:
[45415]514 {
[94942]515 vrc = i_setFileStatus(FileStatus_Error, vrcGuest);
[45109]516 break;
[45415]517 }
[44863]518
[45109]519 case GUEST_FILE_NOTIFYTYPE_OPEN:
[45415]520 {
[45109]521 if (pSvcCbData->mParms == 4)
522 {
[94942]523 vrc = HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.u.open.uHandle);
524 if (RT_FAILURE(vrc))
[71782]525 break;
[45109]526
[45415]527 /* Set the process status. */
[94942]528 vrc = i_setFileStatus(FileStatus_Open, vrcGuest);
[45109]529 }
530 break;
[45415]531 }
[45109]532
533 case GUEST_FILE_NOTIFYTYPE_CLOSE:
[45415]534 {
[94942]535 vrc = i_setFileStatus(FileStatus_Closed, vrcGuest);
[45109]536 break;
[45415]537 }
[45109]538
539 case GUEST_FILE_NOTIFYTYPE_READ:
[47817]540 {
[97610]541 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 4, ("mParms=%u\n", pSvcCbData->mParms),
542 vrc = VERR_WRONG_PARAMETER_COUNT);
543 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx].type == VBOX_HGCM_SVC_PARM_PTR,
544 ("type=%u\n", pSvcCbData->mpaParms[idx].type),
545 vrc = VERR_WRONG_PARAMETER_TYPE);
[47817]546
[97610]547 vrc = HGCMSvcGetPv(&pSvcCbData->mpaParms[idx++], &dataCb.u.read.pvData, &dataCb.u.read.cbData);
548 if (RT_FAILURE(vrc))
549 break;
[71782]550
[97610]551 const uint32_t cbRead = dataCb.u.read.cbData;
552 Log3ThisFunc(("cbRead=%RU32\n", cbRead));
[71782]553
[97610]554 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
555 mData.mOffCurrent += cbRead; /* Bogus for readAt, which is why we've got GUEST_FILE_NOTIFYTYPE_READ_OFFSET. */
556 alock.release();
[45109]557
[97610]558 try
559 {
[48818]560 com::SafeArray<BYTE> data((size_t)cbRead);
[97610]561 AssertBreakStmt(data.size() == cbRead, vrc = VERR_NO_MEMORY);
[85307]562 data.initFrom((BYTE *)dataCb.u.read.pvData, cbRead);
[85300]563 ::FireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent, cbRead, ComSafeArrayAsInParam(data));
[45109]564 }
[97610]565 catch (std::bad_alloc &)
566 {
567 vrc = VERR_NO_MEMORY;
568 }
[45109]569 break;
[47817]570 }
[45109]571
[79296]572 case GUEST_FILE_NOTIFYTYPE_READ_OFFSET:
573 {
574 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 5, ("mParms=%u\n", pSvcCbData->mParms),
[94942]575 vrc = VERR_WRONG_PARAMETER_COUNT);
[79296]576 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx].type == VBOX_HGCM_SVC_PARM_PTR,
577 ("type=%u\n", pSvcCbData->mpaParms[idx].type),
[94942]578 vrc = VERR_WRONG_PARAMETER_TYPE);
[79296]579 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx + 1].type == VBOX_HGCM_SVC_PARM_64BIT,
[97610]580 ("type=%u\n", pSvcCbData->mpaParms[idx + 1].type),
[94942]581 vrc = VERR_WRONG_PARAMETER_TYPE);
[79296]582 BYTE const * const pbData = (BYTE const *)pSvcCbData->mpaParms[idx].u.pointer.addr;
583 uint32_t const cbRead = pSvcCbData->mpaParms[idx].u.pointer.size;
584 int64_t offNew = (int64_t)pSvcCbData->mpaParms[idx + 1].u.uint64;
585 Log3ThisFunc(("cbRead=%RU32 offNew=%RI64 (%#RX64)\n", cbRead, offNew, offNew));
586
587 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
588 if (offNew < 0) /* non-seekable */
589 offNew = mData.mOffCurrent + cbRead;
590 mData.mOffCurrent = offNew;
591 alock.release();
592
593 try
594 {
595 com::SafeArray<BYTE> data((size_t)cbRead);
[97610]596 AssertBreakStmt(data.size() == cbRead, vrc = VERR_NO_MEMORY);
[79296]597 data.initFrom(pbData, cbRead);
[85300]598 ::FireGuestFileReadEvent(mEventSource, mSession, this, offNew, cbRead, ComSafeArrayAsInParam(data));
[94942]599 vrc = VINF_SUCCESS;
[79296]600 }
601 catch (std::bad_alloc &)
602 {
[94942]603 vrc = VERR_NO_MEMORY;
[79296]604 }
605 break;
606 }
607
[45109]608 case GUEST_FILE_NOTIFYTYPE_WRITE:
[47817]609 {
[97610]610 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 4, ("mParms=%u\n", pSvcCbData->mParms),
611 vrc = VERR_WRONG_PARAMETER_COUNT);
612 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx].type == VBOX_HGCM_SVC_PARM_32BIT,
613 ("type=%u\n", pSvcCbData->mpaParms[idx].type),
614 vrc = VERR_WRONG_PARAMETER_TYPE);
[45109]615
[97610]616 uint32_t const cbWritten = pSvcCbData->mpaParms[idx].u.uint32;
[71782]617
[97610]618 Log3ThisFunc(("cbWritten=%RU32\n", cbWritten));
[77075]619
[97610]620 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
621 mData.mOffCurrent += cbWritten; /* Bogus for writeAt and append mode, thus GUEST_FILE_NOTIFYTYPE_WRITE_OFFSET. */
622 alock.release();
[47817]623
[97610]624 ::FireGuestFileWriteEvent(mEventSource, mSession, this, mData.mOffCurrent, cbWritten);
[45109]625 break;
[47817]626 }
[45109]627
[79296]628 case GUEST_FILE_NOTIFYTYPE_WRITE_OFFSET:
629 {
630 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 5, ("mParms=%u\n", pSvcCbData->mParms),
[94942]631 vrc = VERR_WRONG_PARAMETER_COUNT);
[79296]632 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx].type == VBOX_HGCM_SVC_PARM_32BIT,
633 ("type=%u\n", pSvcCbData->mpaParms[idx].type),
[94942]634 vrc = VERR_WRONG_PARAMETER_TYPE);
[79296]635 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx + 1].type == VBOX_HGCM_SVC_PARM_64BIT,
636 ("type=%u\n", pSvcCbData->mpaParms[idx].type),
[94942]637 vrc = VERR_WRONG_PARAMETER_TYPE);
[79296]638 uint32_t const cbWritten = pSvcCbData->mpaParms[idx].u.uint32;
639 int64_t offNew = (int64_t)pSvcCbData->mpaParms[idx + 1].u.uint64;
640 Log3ThisFunc(("cbWritten=%RU32 offNew=%RI64 (%#RX64)\n", cbWritten, offNew, offNew));
641
642 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
643 if (offNew < 0) /* non-seekable */
644 offNew = mData.mOffCurrent + cbWritten;
645 mData.mOffCurrent = offNew;
646 alock.release();
647
[85300]648 HRESULT hrc2 = ::FireGuestFileWriteEvent(mEventSource, mSession, this, offNew, cbWritten);
[94942]649 vrc = SUCCEEDED(hrc2) ? VINF_SUCCESS : Global::vboxStatusCodeFromCOM(hrc2);
[79296]650 break;
651 }
652
[45109]653 case GUEST_FILE_NOTIFYTYPE_SEEK:
[47817]654 {
[97610]655 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 4, ("mParms=%u\n", pSvcCbData->mParms),
656 vrc = VERR_WRONG_PARAMETER_COUNT);
[45109]657
[97610]658 vrc = HGCMSvcGetU64(&pSvcCbData->mpaParms[idx++], &dataCb.u.seek.uOffActual);
659 if (RT_FAILURE(vrc))
660 break;
[71782]661
[97610]662 Log3ThisFunc(("uOffActual=%RU64\n", dataCb.u.seek.uOffActual));
[47817]663
[97610]664 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
665 mData.mOffCurrent = dataCb.u.seek.uOffActual;
666 alock.release();
[45415]667
[97610]668 ::FireGuestFileOffsetChangedEvent(mEventSource, mSession, this, dataCb.u.seek.uOffActual, 0 /* Processed */);
[45109]669 break;
[47817]670 }
[45109]671
672 case GUEST_FILE_NOTIFYTYPE_TELL:
[79300]673 /* We don't issue any HOST_MSG_FILE_TELL, so we shouldn't get these notifications! */
674 AssertFailed();
[45109]675 break;
676
[79287]677 case GUEST_FILE_NOTIFYTYPE_SET_SIZE:
678 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 4, ("mParms=%u\n", pSvcCbData->mParms),
[94942]679 vrc = VERR_WRONG_PARAMETER_COUNT);
[79287]680 ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx].type == VBOX_HGCM_SVC_PARM_64BIT,
681 ("type=%u\n", pSvcCbData->mpaParms[idx].type),
[94942]682 vrc = VERR_WRONG_PARAMETER_TYPE);
[79287]683 dataCb.u.SetSize.cbSize = pSvcCbData->mpaParms[idx].u.uint64;
684 Log3ThisFunc(("cbSize=%RU64\n", dataCb.u.SetSize.cbSize));
685
[85300]686 ::FireGuestFileSizeChangedEvent(mEventSource, mSession, this, dataCb.u.SetSize.cbSize);
[94942]687 vrc = VINF_SUCCESS;
[79287]688 break;
689
[45109]690 default:
691 break;
692 }
693
[97610]694 try
[49349]695 {
[97610]696 if (RT_SUCCESS(vrc))
[84745]697 {
698 GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb));
[71636]699
[98278]700 /* Ignore return code, as the event to signal might not be there (anymore). */
[94942]701 signalWaitEventInternal(pCbCtx, vrcGuest, &payload);
[84745]702 }
[97610]703 else /* OOM situation, wrong HGCM parameters or smth. not expected. */
[84745]704 {
[98278]705 /* Ignore return code, as the event to signal might not be there (anymore). */
[97610]706 signalWaitEventInternalEx(pCbCtx, vrc, 0 /* guestRc */, NULL /* pPayload */);
[84745]707 }
[49349]708 }
[97610]709 catch (int vrcEx) /* Thrown by GuestWaitEventPayload constructor. */
710 {
711 /* Also try to signal the waiter, to let it know of the OOM situation.
[98278]712 * Ignore return code, as the event to signal might not be there (anymore). */
[97610]713 signalWaitEventInternalEx(pCbCtx, vrcEx, 0 /* guestRc */, NULL /* pPayload */);
714 vrc = vrcEx;
715 }
[49349]716
[98278]717 LogFlowThisFunc(("uType=%RU32, rcGuest=%Rrc, vrc=%Rrc\n", dataCb.uType, vrcGuest, vrc));
[94942]718 return vrc;
[44863]719}
720
[92897]721/**
722 * Called when the guest side of the file has been disconnected (closed, terminated, +++).
723 *
724 * @returns VBox status code.
725 * @param pCbCtx Host callback context.
726 * @param pSvcCbData Host callback data.
727 */
[50618]728int GuestFile::i_onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
[44863]729{
[45109]730 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
731 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
[44863]732
[50618]733 int vrc = i_setFileStatus(FileStatus_Down, VINF_SUCCESS);
[44863]734
735 LogFlowFuncLeaveRC(vrc);
736 return vrc;
737}
738
[49504]739/**
[77587]740 * @copydoc GuestObject::i_onUnregister
[49504]741 */
[77587]742int GuestFile::i_onUnregister(void)
[49504]743{
744 LogFlowThisFuncEnter();
745
746 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
747
748 int vrc = VINF_SUCCESS;
749
[49610]750 /*
[49504]751 * Note: The event source stuff holds references to this object,
752 * so make sure that this is cleaned up *before* calling uninit().
753 */
754 if (!mEventSource.isNull())
755 {
756 mEventSource->UnregisterListener(mLocalListener);
757
758 mLocalListener.setNull();
759 unconst(mEventSource).setNull();
760 }
761
762 LogFlowFuncLeaveRC(vrc);
763 return vrc;
764}
765
[77587]766/**
767 * @copydoc GuestObject::i_onSessionStatusChange
768 */
769int GuestFile::i_onSessionStatusChange(GuestSessionStatus_T enmSessionStatus)
770{
771 LogFlowThisFuncEnter();
772
773 int vrc = VINF_SUCCESS;
774
775 /* If the session now is in a terminated state, set the file status
776 * to "down", as there is not much else we can do now. */
777 if (GuestSession::i_isTerminated(enmSessionStatus))
778 vrc = i_setFileStatus(FileStatus_Down, 0 /* fileRc, ignored */);
779
780 LogFlowFuncLeaveRC(vrc);
781 return vrc;
782}
783
[92897]784/**
785 * Opens the file on the guest.
786 *
787 * @returns VBox status code.
788 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
789 * @param uTimeoutMS Timeout (in ms) to wait.
790 * @param prcGuest Where to return the guest error when VERR_GSTCTL_GUEST_ERROR
791 * was returned. Optional.
792 */
[104001]793int GuestFile::i_open(uint32_t uTimeoutMS, int *prcGuest)
[44863]794{
[75926]795 AssertReturn(mData.mOpenInfo.mFilename.isNotEmpty(), VERR_INVALID_PARAMETER);
[71782]796
[47817]797 LogFlowThisFuncEnter();
798
[49006]799 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
[47817]800
[79285]801 LogFlowThisFunc(("strFile=%s, enmAccessMode=%d, enmOpenAction=%d, uCreationMode=%o, mfOpenEx=%#x\n",
[75926]802 mData.mOpenInfo.mFilename.c_str(), mData.mOpenInfo.mAccessMode, mData.mOpenInfo.mOpenAction,
[71782]803 mData.mOpenInfo.mCreationMode, mData.mOpenInfo.mfOpenEx));
804
805 /* Validate and translate open action. */
806 const char *pszOpenAction = NULL;
807 switch (mData.mOpenInfo.mOpenAction)
808 {
[72980]809 case FileOpenAction_OpenExisting: pszOpenAction = "oe"; break;
810 case FileOpenAction_OpenOrCreate: pszOpenAction = "oc"; break;
811 case FileOpenAction_CreateNew: pszOpenAction = "ce"; break;
812 case FileOpenAction_CreateOrReplace: pszOpenAction = "ca"; break;
813 case FileOpenAction_OpenExistingTruncated: pszOpenAction = "ot"; break;
814 case FileOpenAction_AppendOrCreate:
[71782]815 pszOpenAction = "oa"; /** @todo get rid of this one and implement AppendOnly/AppendRead. */
816 break;
817 default:
818 return VERR_INVALID_PARAMETER;
819 }
820
821 /* Validate and translate access mode. */
822 const char *pszAccessMode = NULL;
823 switch (mData.mOpenInfo.mAccessMode)
824 {
[72980]825 case FileAccessMode_ReadOnly: pszAccessMode = "r"; break;
826 case FileAccessMode_WriteOnly: pszAccessMode = "w"; break;
827 case FileAccessMode_ReadWrite: pszAccessMode = "r+"; break;
[79285]828 case FileAccessMode_AppendOnly: pszAccessMode = "a"; break;
829 case FileAccessMode_AppendRead: pszAccessMode = "a+"; break;
[72980]830 default: return VERR_INVALID_PARAMETER;
[71782]831 }
832
833 /* Validate and translate sharing mode. */
834 const char *pszSharingMode = NULL;
835 switch (mData.mOpenInfo.mSharingMode)
836 {
[72980]837 case FileSharingMode_All: pszSharingMode = ""; break;
838 case FileSharingMode_Read: RT_FALL_THRU();
839 case FileSharingMode_Write: RT_FALL_THRU();
840 case FileSharingMode_ReadWrite: RT_FALL_THRU();
841 case FileSharingMode_Delete: RT_FALL_THRU();
842 case FileSharingMode_ReadDelete: RT_FALL_THRU();
843 case FileSharingMode_WriteDelete: return VERR_NOT_IMPLEMENTED;
844 default: return VERR_INVALID_PARAMETER;
[71782]845 }
846
[45780]847 int vrc;
[44863]848
[45780]849 GuestWaitEvent *pEvent = NULL;
[49349]850 GuestEventTypes eventTypes;
[45780]851 try
852 {
853 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
854
[47469]855 vrc = registerWaitEvent(eventTypes, &pEvent);
[45780]856 }
[73505]857 catch (std::bad_alloc &)
[45780]858 {
859 vrc = VERR_NO_MEMORY;
860 }
861
862 if (RT_FAILURE(vrc))
863 return vrc;
864
[45109]865 /* Prepare HGCM call. */
866 VBOXHGCMSVCPARM paParms[8];
[45415]867 int i = 0;
[75737]868 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
[75926]869 HGCMSvcSetPv(&paParms[i++], (void*)mData.mOpenInfo.mFilename.c_str(),
870 (ULONG)mData.mOpenInfo.mFilename.length() + 1);
[75737]871 HGCMSvcSetStr(&paParms[i++], pszAccessMode);
872 HGCMSvcSetStr(&paParms[i++], pszOpenAction);
873 HGCMSvcSetStr(&paParms[i++], pszSharingMode);
874 HGCMSvcSetU32(&paParms[i++], mData.mOpenInfo.mCreationMode);
[79285]875 HGCMSvcSetU64(&paParms[i++], 0 /*unused offset*/);
[55668]876 /** @todo Next protocol version: add flags, replace strings, remove initial offset. */
[45109]877
[49006]878 alock.release(); /* Drop write lock before sending. */
[47817]879
[76958]880 vrc = sendMessage(HOST_MSG_FILE_OPEN, i, paParms);
[45415]881 if (RT_SUCCESS(vrc))
[71406]882 vrc = i_waitForStatusChange(pEvent, uTimeoutMS, NULL /* FileStatus */, prcGuest);
[45109]883
[47469]884 unregisterWaitEvent(pEvent);
[45780]885
[45109]886 LogFlowFuncLeaveRC(vrc);
887 return vrc;
888}
889
[92897]890/**
891 * Queries file system information from a guest file.
892 *
893 * @returns VBox status code.
894 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
895 * @param objData Where to store the file system object data on success.
896 * @param prcGuest Where to return the guest error when VERR_GSTCTL_GUEST_ERROR
897 * was returned. Optional.
898 */
[71782]899int GuestFile::i_queryInfo(GuestFsObjData &objData, int *prcGuest)
900{
[98526]901 AssertPtrReturn(mSession, VERR_OBJECT_DESTROYED);
[99252]902 return mSession->i_fsObjQueryInfo(mData.mOpenInfo.mFilename, FALSE /* fFollowSymlinks */, objData, prcGuest);
[71782]903}
904
[92897]905/**
906 * Reads data from a guest file.
907 *
908 * @returns VBox status code.
909 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
910 * @param uSize Size (in bytes) to read.
911 * @param uTimeoutMS Timeout (in ms) to wait.
912 * @param pvData Where to store the read data on success.
913 * @param cbData Size (in bytes) of \a pvData on input.
914 * @param pcbRead Where to return to size (in bytes) read on success.
915 * Optional.
916 */
[50618]917int GuestFile::i_readData(uint32_t uSize, uint32_t uTimeoutMS,
918 void* pvData, uint32_t cbData, uint32_t* pcbRead)
[45109]919{
[45434]920 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
921 AssertReturn(cbData, VERR_INVALID_PARAMETER);
922
[45109]923 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
924 uSize, uTimeoutMS, pvData, cbData));
[49006]925
926 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
927
[45780]928 int vrc;
[45109]929
[45780]930 GuestWaitEvent *pEvent = NULL;
[49349]931 GuestEventTypes eventTypes;
[45780]932 try
[45109]933 {
[45780]934 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
935 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
[45109]936
[47469]937 vrc = registerWaitEvent(eventTypes, &pEvent);
[45780]938 }
[73505]939 catch (std::bad_alloc &)
[45780]940 {
941 vrc = VERR_NO_MEMORY;
942 }
[45109]943
[45780]944 if (RT_FAILURE(vrc))
945 return vrc;
[45415]946
[45780]947 /* Prepare HGCM call. */
948 VBOXHGCMSVCPARM paParms[4];
949 int i = 0;
[75737]950 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
951 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
952 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
[45780]953
[49006]954 alock.release(); /* Drop write lock before sending. */
955
[76958]956 vrc = sendMessage(HOST_MSG_FILE_READ, i, paParms);
[45780]957 if (RT_SUCCESS(vrc))
[63154]958 {
959 uint32_t cbRead = 0;
[50618]960 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
[63154]961 if (RT_SUCCESS(vrc))
962 {
963 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
964 if (pcbRead)
965 *pcbRead = cbRead;
966 }
[98278]967 else if (pEvent->HasGuestError()) /* Return guest vrc if available. */
[98666]968 vrc = pEvent->GuestResult();
[45109]969 }
970
[47469]971 unregisterWaitEvent(pEvent);
[45780]972
[45109]973 LogFlowFuncLeaveRC(vrc);
974 return vrc;
975}
976
[92897]977/**
978 * Reads data from a specific position from a guest file.
979 *
980 * @returns VBox status code.
981 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
982 * @param uOffset Offset (in bytes) to start reading from.
983 * @param uSize Size (in bytes) to read.
984 * @param uTimeoutMS Timeout (in ms) to wait.
985 * @param pvData Where to store the read data on success.
986 * @param cbData Size (in bytes) of \a pvData on input.
987 * @param pcbRead Where to return to size (in bytes) read on success.
988 * Optional.
989 */
[50618]990int GuestFile::i_readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
991 void* pvData, size_t cbData, size_t* pcbRead)
[45109]992{
993 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
994 uOffset, uSize, uTimeoutMS, pvData, cbData));
[49006]995
996 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
997
[45780]998 int vrc;
[45109]999
[45780]1000 GuestWaitEvent *pEvent = NULL;
[49349]1001 GuestEventTypes eventTypes;
[45780]1002 try
[45109]1003 {
[45780]1004 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1005 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
[45109]1006
[47469]1007 vrc = registerWaitEvent(eventTypes, &pEvent);
[45780]1008 }
[73505]1009 catch (std::bad_alloc &)
[45780]1010 {
1011 vrc = VERR_NO_MEMORY;
1012 }
[45109]1013
[45780]1014 if (RT_FAILURE(vrc))
1015 return vrc;
[45415]1016
[45780]1017 /* Prepare HGCM call. */
1018 VBOXHGCMSVCPARM paParms[4];
1019 int i = 0;
[75737]1020 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1021 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1022 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset (in bytes) to start reading */);
1023 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
[45415]1024
[49006]1025 alock.release(); /* Drop write lock before sending. */
1026
[76958]1027 vrc = sendMessage(HOST_MSG_FILE_READ_AT, i, paParms);
[45780]1028 if (RT_SUCCESS(vrc))
[63154]1029 {
1030 uint32_t cbRead = 0;
[50618]1031 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
[63154]1032 if (RT_SUCCESS(vrc))
1033 {
1034 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
[45780]1035
[63154]1036 if (pcbRead)
1037 *pcbRead = cbRead;
1038 }
[98278]1039 else if (pEvent->HasGuestError()) /* Return guest vrc if available. */
[98666]1040 vrc = pEvent->GuestResult();
[45109]1041 }
1042
[47469]1043 unregisterWaitEvent(pEvent);
[45780]1044
[45109]1045 LogFlowFuncLeaveRC(vrc);
1046 return vrc;
1047}
1048
[92897]1049/**
1050 * Seeks a guest file to a specific position.
1051 *
1052 * @returns VBox status code.
1053 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1054 * @param iOffset Offset (in bytes) to seek.
1055 * @param eSeekType Seek type to use.
1056 * @param uTimeoutMS Timeout (in ms) to wait.
1057 * @param puOffset Where to return the new current file position (in bytes) on success.
1058 */
[50618]1059int GuestFile::i_seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType,
1060 uint32_t uTimeoutMS, uint64_t *puOffset)
[45109]1061{
[48818]1062 LogFlowThisFunc(("iOffset=%RI64, uTimeoutMS=%RU32\n",
1063 iOffset, uTimeoutMS));
[49006]1064
1065 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1066
[45780]1067 int vrc;
[45109]1068
[45780]1069 GuestWaitEvent *pEvent = NULL;
[49349]1070 GuestEventTypes eventTypes;
[45780]1071 try
1072 {
1073 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1074 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
1075
[47469]1076 vrc = registerWaitEvent(eventTypes, &pEvent);
[45780]1077 }
[73505]1078 catch (std::bad_alloc &)
[45780]1079 {
1080 vrc = VERR_NO_MEMORY;
1081 }
1082
1083 if (RT_FAILURE(vrc))
1084 return vrc;
1085
[45109]1086 /* Prepare HGCM call. */
1087 VBOXHGCMSVCPARM paParms[4];
[45415]1088 int i = 0;
[75737]1089 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1090 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1091 HGCMSvcSetU32(&paParms[i++], eSeekType /* Seek method */);
[48818]1092 /** @todo uint64_t vs. int64_t! */
[75737]1093 HGCMSvcSetU64(&paParms[i++], (uint64_t)iOffset /* Offset (in bytes) to start reading */);
[45109]1094
[49006]1095 alock.release(); /* Drop write lock before sending. */
1096
[76958]1097 vrc = sendMessage(HOST_MSG_FILE_SEEK, i, paParms);
[45415]1098 if (RT_SUCCESS(vrc))
[72096]1099 {
1100 uint64_t uOffset;
1101 vrc = i_waitForOffsetChange(pEvent, uTimeoutMS, &uOffset);
1102 if (RT_SUCCESS(vrc))
1103 {
1104 LogFlowThisFunc(("uOffset=%RU64\n", uOffset));
[45109]1105
[72096]1106 if (puOffset)
1107 *puOffset = uOffset;
1108 }
[98278]1109 else if (pEvent->HasGuestError()) /* Return guest vrc if available. */
[98666]1110 vrc = pEvent->GuestResult();
[72096]1111 }
1112
[47469]1113 unregisterWaitEvent(pEvent);
[45780]1114
[45109]1115 LogFlowFuncLeaveRC(vrc);
1116 return vrc;
1117}
1118
[92897]1119/**
1120 * Sets the current internal file object status.
1121 *
1122 * @returns VBox status code.
1123 * @param fileStatus New file status to set.
[98278]1124 * @param vrcFile New result code to set.
[92897]1125 *
1126 * @note Takes the write lock.
1127 */
[98278]1128int GuestFile::i_setFileStatus(FileStatus_T fileStatus, int vrcFile)
[45415]1129{
[47817]1130 LogFlowThisFuncEnter();
1131
1132 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1133
[98278]1134 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, vrcFile=%Rrc\n", mData.mStatus, fileStatus, vrcFile));
[44863]1135
[45415]1136#ifdef VBOX_STRICT
1137 if (fileStatus == FileStatus_Error)
[98278]1138 AssertMsg(RT_FAILURE(vrcFile), ("Guest vrc must be an error (%Rrc)\n", vrcFile));
[45415]1139 else
[98278]1140 AssertMsg(RT_SUCCESS(vrcFile), ("Guest vrc must not be an error (%Rrc)\n", vrcFile));
[45415]1141#endif
1142
1143 if (mData.mStatus != fileStatus)
[44863]1144 {
[47817]1145 mData.mStatus = fileStatus;
[98278]1146 mData.mLastError = vrcFile;
[45415]1147
[45805]1148 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
[98278]1149 HRESULT hrc = errorInfo.createObject();
[98282]1150 ComAssertComRCRet(hrc, VERR_COM_UNEXPECTED);
[98278]1151 if (RT_FAILURE(vrcFile))
[45415]1152 {
[98282]1153 hrc = errorInfo->initEx(VBOX_E_GSTCTL_GUEST_ERROR, vrcFile,
[98278]1154 COM_IIDOF(IGuestFile), getComponentName(),
1155 i_guestErrorToString(vrcFile, mData.mOpenInfo.mFilename.c_str()));
[98282]1156 ComAssertComRCRet(hrc, VERR_COM_UNEXPECTED);
[45415]1157 }
[98282]1158 /* Note: On vrcFile success, errorInfo is set to S_OK and also sent via the event below. */
[45415]1159
[47817]1160 alock.release(); /* Release lock before firing off event. */
1161
[85300]1162 ::FireGuestFileStateChangedEvent(mEventSource, mSession, this, fileStatus, errorInfo);
[44863]1163 }
1164
[45415]1165 return VINF_SUCCESS;
1166}
1167
[92897]1168/**
1169 * Waits for a guest file offset change.
1170 *
1171 * @returns VBox status code.
1172 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1173 * @param pEvent Guest wait event to wait for.
1174 * @param uTimeoutMS Timeout (in ms) to wait.
1175 * @param puOffset Where to return the new offset (in bytes) on success.
1176 * Optional and can be NULL.
1177 */
[50618]1178int GuestFile::i_waitForOffsetChange(GuestWaitEvent *pEvent,
1179 uint32_t uTimeoutMS, uint64_t *puOffset)
[45415]1180{
[45780]1181 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
[45415]1182
[49440]1183 VBoxEventType_T evtType;
1184 ComPtr<IEvent> pIEvent;
[45780]1185 int vrc = waitForEvent(pEvent, uTimeoutMS,
[49440]1186 &evtType, pIEvent.asOutParam());
[45780]1187 if (RT_SUCCESS(vrc))
[44863]1188 {
[49440]1189 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
1190 {
1191 if (puOffset)
1192 {
1193 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
1194 Assert(!pFileEvent.isNull());
[45415]1195
[49440]1196 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
1197 ComAssertComRC(hr);
1198 }
1199 }
1200 else
1201 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
[44863]1202 }
1203
1204 return vrc;
1205}
1206
[92897]1207/**
1208 * Waits for reading from a guest file.
1209 *
1210 * @returns VBox status code.
1211 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1212 * @param pEvent Guest wait event to wait for.
1213 * @param uTimeoutMS Timeout (in ms) to wait.
1214 * @param pvData Where to store read file data on success.
1215 * @param cbData Size (in bytes) of \a pvData.
1216 * @param pcbRead Where to return the actual bytes read on success.
1217 * Optional and can be NULL.
1218 */
[50618]1219int GuestFile::i_waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1220 void *pvData, size_t cbData, uint32_t *pcbRead)
[45434]1221{
[45780]1222 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
[45434]1223
[49440]1224 VBoxEventType_T evtType;
1225 ComPtr<IEvent> pIEvent;
[45780]1226 int vrc = waitForEvent(pEvent, uTimeoutMS,
[49440]1227 &evtType, pIEvent.asOutParam());
[45780]1228 if (RT_SUCCESS(vrc))
[45434]1229 {
[49440]1230 if (evtType == VBoxEventType_OnGuestFileRead)
1231 {
[79253]1232 vrc = VINF_SUCCESS;
1233
[49440]1234 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
1235 Assert(!pFileEvent.isNull());
[49349]1236
[49440]1237 if (pvData)
1238 {
1239 com::SafeArray <BYTE> data;
[79253]1240 HRESULT hrc1 = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1241 ComAssertComRC(hrc1);
[71782]1242 const size_t cbRead = data.size();
1243 if (cbRead)
[49440]1244 {
[71782]1245 if (cbRead <= cbData)
1246 memcpy(pvData, data.raw(), cbRead);
1247 else
1248 vrc = VERR_BUFFER_OVERFLOW;
[49440]1249 }
[79253]1250 /* else: used to be VERR_NO_DATA, but that messes stuff up. */
1251
1252 if (pcbRead)
1253 {
1254 *pcbRead = (uint32_t)cbRead;
1255 Assert(*pcbRead == cbRead);
1256 }
[49440]1257 }
[79253]1258 else if (pcbRead)
[49440]1259 {
[79253]1260 *pcbRead = 0;
1261 HRESULT hrc2 = pFileEvent->COMGETTER(Processed)((ULONG *)pcbRead);
1262 ComAssertComRC(hrc2); NOREF(hrc2);
[49440]1263 }
[45434]1264 }
[45780]1265 else
[49440]1266 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
[45434]1267 }
1268
1269 return vrc;
1270}
1271
[78234]1272/**
[92897]1273 * Waits for a guest file status change.
[78234]1274 *
1275 * @note Similar code in GuestProcess::i_waitForStatusChange() and
1276 * GuestSession::i_waitForStatusChange().
[92897]1277 *
1278 * @returns VBox status code.
1279 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1280 * @param pEvent Guest wait event to wait for.
1281 * @param uTimeoutMS Timeout (in ms) to wait.
1282 * @param pFileStatus Where to return the file status on success.
1283 * @param prcGuest Where to return the guest error when VERR_GSTCTL_GUEST_ERROR
1284 * was returned.
[78234]1285 */
[50618]1286int GuestFile::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
[71299]1287 FileStatus_T *pFileStatus, int *prcGuest)
[45434]1288{
[45780]1289 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
[49440]1290 /* pFileStatus is optional. */
[45780]1291
[49440]1292 VBoxEventType_T evtType;
1293 ComPtr<IEvent> pIEvent;
[45780]1294 int vrc = waitForEvent(pEvent, uTimeoutMS,
[49440]1295 &evtType, pIEvent.asOutParam());
[45780]1296 if (RT_SUCCESS(vrc))
[45434]1297 {
[49440]1298 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
1299 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
1300 Assert(!pFileEvent.isNull());
[45434]1301
[49440]1302 HRESULT hr;
1303 if (pFileStatus)
1304 {
1305 hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1306 ComAssertComRC(hr);
1307 }
[47817]1308
[49440]1309 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1310 hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam());
1311 ComAssertComRC(hr);
[47817]1312
[49440]1313 LONG lGuestRc;
1314 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1315 ComAssertComRC(hr);
1316
1317 LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n",
1318 lGuestRc, lGuestRc));
1319
1320 if (RT_FAILURE((int)lGuestRc))
1321 vrc = VERR_GSTCTL_GUEST_ERROR;
1322
[71299]1323 if (prcGuest)
1324 *prcGuest = (int)lGuestRc;
[45434]1325 }
[78234]1326 /* waitForEvent may also return VERR_GSTCTL_GUEST_ERROR like we do above, so make prcGuest is set. */
1327 /** @todo r=bird: Andy, you seem to have forgotten this scenario. Showed up occasionally when
1328 * using the wrong password with a copyto command in a debug build on windows, error info
1329 * contained "Unknown Status -858993460 (0xcccccccc)". As you know windows fills the stack frames
1330 * with 0xcccccccc in debug builds to highlight use of uninitialized data, so that's what happened
1331 * here. It's actually good you didn't initialize lGuest, as it would be heck to find otherwise.
1332 *
1333 * I'm still not very impressed with the error managment or the usuefullness of the documentation
1334 * in this code, though the latter is getting better! */
1335 else if (vrc == VERR_GSTCTL_GUEST_ERROR && prcGuest)
1336 *prcGuest = pEvent->GuestResult();
1337 Assert(vrc != VERR_GSTCTL_GUEST_ERROR || !prcGuest || *prcGuest != (int)0xcccccccc);
[45434]1338
1339 return vrc;
1340}
1341
[50618]1342int GuestFile::i_waitForWrite(GuestWaitEvent *pEvent,
1343 uint32_t uTimeoutMS, uint32_t *pcbWritten)
[45109]1344{
[45780]1345 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1346
[49440]1347 VBoxEventType_T evtType;
1348 ComPtr<IEvent> pIEvent;
[45780]1349 int vrc = waitForEvent(pEvent, uTimeoutMS,
[49440]1350 &evtType, pIEvent.asOutParam());
[45780]1351 if (RT_SUCCESS(vrc))
[45434]1352 {
[49440]1353 if (evtType == VBoxEventType_OnGuestFileWrite)
1354 {
1355 if (pcbWritten)
1356 {
1357 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1358 Assert(!pFileEvent.isNull());
[45434]1359
[49440]1360 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1361 ComAssertComRC(hr);
1362 }
1363 }
1364 else
1365 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
[45434]1366 }
1367
1368 return vrc;
[45109]1369}
1370
[92897]1371/**
1372 * Writes data to a guest file.
1373 *
1374 * @returns VBox status code.
1375 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1376 * @param uTimeoutMS Timeout (in ms) to wait.
1377 * @param pvData Data to write.
1378 * @param cbData Size (in bytes) of \a pvData to write.
1379 * @param pcbWritten Where to return to size (in bytes) written on success.
1380 * Optional.
1381 */
[77387]1382int GuestFile::i_writeData(uint32_t uTimeoutMS, const void *pvData, uint32_t cbData,
[50618]1383 uint32_t *pcbWritten)
[45109]1384{
1385 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1386 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1387
1388 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1389 uTimeoutMS, pvData, cbData));
[49006]1390
1391 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1392
[45780]1393 int vrc;
[45109]1394
[45780]1395 GuestWaitEvent *pEvent = NULL;
[49349]1396 GuestEventTypes eventTypes;
[45780]1397 try
[45109]1398 {
[45780]1399 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1400 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
[45109]1401
[47469]1402 vrc = registerWaitEvent(eventTypes, &pEvent);
[45780]1403 }
[73505]1404 catch (std::bad_alloc &)
[45780]1405 {
1406 vrc = VERR_NO_MEMORY;
1407 }
[45109]1408
[45780]1409 if (RT_FAILURE(vrc))
1410 return vrc;
[45109]1411
[45780]1412 /* Prepare HGCM call. */
1413 VBOXHGCMSVCPARM paParms[8];
1414 int i = 0;
[75737]1415 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1416 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1417 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
[77387]1418 HGCMSvcSetPv (&paParms[i++], unconst(pvData), cbData);
[45780]1419
[49006]1420 alock.release(); /* Drop write lock before sending. */
1421
[76958]1422 vrc = sendMessage(HOST_MSG_FILE_WRITE, i, paParms);
[45780]1423 if (RT_SUCCESS(vrc))
[63154]1424 {
1425 uint32_t cbWritten = 0;
[50618]1426 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
[63154]1427 if (RT_SUCCESS(vrc))
1428 {
1429 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
[71816]1430 if (pcbWritten)
[63154]1431 *pcbWritten = cbWritten;
1432 }
[98278]1433 else if (pEvent->HasGuestError()) /* Return guest vrc if available. */
[98666]1434 vrc = pEvent->GuestResult();
[45109]1435 }
1436
[47469]1437 unregisterWaitEvent(pEvent);
[45780]1438
[45109]1439 LogFlowFuncLeaveRC(vrc);
1440 return vrc;
1441}
1442
[92897]1443
1444/**
1445 * Writes data to a specific position to a guest file.
1446 *
1447 * @returns VBox status code.
1448 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1449 * @param uOffset Offset (in bytes) to start writing at.
1450 * @param uTimeoutMS Timeout (in ms) to wait.
1451 * @param pvData Data to write.
1452 * @param cbData Size (in bytes) of \a pvData to write.
1453 * @param pcbWritten Where to return to size (in bytes) written on success.
1454 * Optional.
1455 */
[50618]1456int GuestFile::i_writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
[77387]1457 const void *pvData, uint32_t cbData, uint32_t *pcbWritten)
[45109]1458{
1459 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1460 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1461
1462 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1463 uOffset, uTimeoutMS, pvData, cbData));
[49006]1464
1465 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1466
[45780]1467 int vrc;
[45109]1468
[45780]1469 GuestWaitEvent *pEvent = NULL;
[49349]1470 GuestEventTypes eventTypes;
[45780]1471 try
[45109]1472 {
[45780]1473 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1474 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
[45109]1475
[47469]1476 vrc = registerWaitEvent(eventTypes, &pEvent);
[45780]1477 }
[73505]1478 catch (std::bad_alloc &)
[45780]1479 {
1480 vrc = VERR_NO_MEMORY;
1481 }
[45434]1482
[45780]1483 if (RT_FAILURE(vrc))
1484 return vrc;
[45109]1485
[45780]1486 /* Prepare HGCM call. */
1487 VBOXHGCMSVCPARM paParms[8];
1488 int i = 0;
[75737]1489 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1490 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1491 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset where to starting writing */);
1492 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
[77387]1493 HGCMSvcSetPv (&paParms[i++], unconst(pvData), cbData);
[45780]1494
[49006]1495 alock.release(); /* Drop write lock before sending. */
1496
[76958]1497 vrc = sendMessage(HOST_MSG_FILE_WRITE_AT, i, paParms);
[45780]1498 if (RT_SUCCESS(vrc))
[63154]1499 {
1500 uint32_t cbWritten = 0;
[50618]1501 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
[63154]1502 if (RT_SUCCESS(vrc))
1503 {
1504 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
[71816]1505 if (pcbWritten)
[63154]1506 *pcbWritten = cbWritten;
1507 }
[98278]1508 else if (pEvent->HasGuestError()) /* Return guest vrc if available. */
[98666]1509 vrc = pEvent->GuestResult();
[45109]1510 }
1511
[47469]1512 unregisterWaitEvent(pEvent);
[45780]1513
[45109]1514 LogFlowFuncLeaveRC(vrc);
1515 return vrc;
1516}
1517
[50618]1518// Wrapped IGuestFile methods
[42084]1519/////////////////////////////////////////////////////////////////////////////
[50618]1520HRESULT GuestFile::close()
[42084]1521{
[71560]1522 AutoCaller autoCaller(this);
[98262]1523 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71560]1524
[42846]1525 LogFlowThisFuncEnter();
[42084]1526
[45109]1527 /* Close file on guest. */
[94942]1528 int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
[104001]1529 int vrc = i_close(&vrcGuest);
[73003]1530 if (RT_FAILURE(vrc))
[45109]1531 {
[73003]1532 if (vrc == VERR_GSTCTL_GUEST_ERROR)
[91503]1533 {
[94942]1534 GuestErrorInfo ge(GuestErrorInfo::Type_File, vrcGuest, mData.mOpenInfo.mFilename.c_str());
1535 return setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Closing guest file failed: %s"),
[91516]1536 GuestBase::getErrorAsString(ge).c_str());
[91503]1537 }
[84648]1538 return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Closing guest file \"%s\" failed with %Rrc\n"),
1539 mData.mOpenInfo.mFilename.c_str(), vrc);
[45109]1540 }
1541
[73003]1542 LogFlowThisFunc(("Returning S_OK / vrc=%Rrc\n", vrc));
[42846]1543 return S_OK;
[42084]1544}
1545
[50618]1546HRESULT GuestFile::queryInfo(ComPtr<IFsObjInfo> &aObjInfo)
[42084]1547{
[71782]1548 AutoCaller autoCaller(this);
[98262]1549 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71782]1550
1551 LogFlowThisFuncEnter();
1552
[94942]1553 HRESULT hrc = S_OK;
[71782]1554
[79189]1555 GuestFsObjData fsObjData;
[94942]1556 int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1557 int vrc = i_queryInfo(fsObjData, &vrcGuest);
[71782]1558 if (RT_SUCCESS(vrc))
1559 {
1560 ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
[94942]1561 hrc = ptrFsObjInfo.createObject();
1562 if (SUCCEEDED(hrc))
[71782]1563 {
1564 vrc = ptrFsObjInfo->init(fsObjData);
1565 if (RT_SUCCESS(vrc))
[94942]1566 hrc = ptrFsObjInfo.queryInterfaceTo(aObjInfo.asOutParam());
[71782]1567 else
[94942]1568 hrc = setErrorVrc(vrc,
1569 tr("Initialization of guest file object for \"%s\" failed: %Rrc"),
1570 mData.mOpenInfo.mFilename.c_str(), vrc);
[71782]1571 }
1572 }
1573 else
1574 {
1575 if (GuestProcess::i_isGuestError(vrc))
[91503]1576 {
[98526]1577 GuestErrorInfo ge(
1578#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
1579 GuestErrorInfo::Type_ToolStat,
1580#else
1581 GuestErrorInfo::Type_File,
1582#endif
1583 vrcGuest, mData.mOpenInfo.mFilename.c_str());
[94942]1584 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Querying guest file information failed: %s"),
1585 GuestBase::getErrorAsString(ge).c_str());
[91503]1586 }
[71782]1587 else
[94942]1588 hrc = setErrorVrc(vrc,
1589 tr("Querying guest file information for \"%s\" failed: %Rrc"), mData.mOpenInfo.mFilename.c_str(), vrc);
[71782]1590 }
1591
1592 LogFlowFuncLeaveRC(vrc);
[94942]1593 return hrc;
[42084]1594}
1595
[55631]1596HRESULT GuestFile::querySize(LONG64 *aSize)
1597{
[71782]1598 AutoCaller autoCaller(this);
[98262]1599 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71782]1600
1601 LogFlowThisFuncEnter();
1602
[94942]1603 HRESULT hrc = S_OK;
[71782]1604
[79189]1605 GuestFsObjData fsObjData;
[94942]1606 int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1607 int vrc = i_queryInfo(fsObjData, &vrcGuest);
[71782]1608 if (RT_SUCCESS(vrc))
1609 {
1610 *aSize = fsObjData.mObjectSize;
1611 }
1612 else
1613 {
1614 if (GuestProcess::i_isGuestError(vrc))
[91503]1615 {
[98526]1616 GuestErrorInfo ge(
1617#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
1618 GuestErrorInfo::Type_ToolStat,
1619#else
1620 GuestErrorInfo::Type_File,
1621#endif
1622 vrcGuest, mData.mOpenInfo.mFilename.c_str());
[94942]1623 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Querying guest file size failed: %s"),
1624 GuestBase::getErrorAsString(ge).c_str());
[91503]1625 }
[71782]1626 else
[94942]1627 hrc = setErrorVrc(vrc, tr("Querying guest file size for \"%s\" failed: %Rrc"), mData.mOpenInfo.mFilename.c_str(), vrc);
[71782]1628 }
1629
1630 LogFlowFuncLeaveRC(vrc);
[94942]1631 return hrc;
[55631]1632}
1633
[50618]1634HRESULT GuestFile::read(ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
[42084]1635{
[71560]1636 AutoCaller autoCaller(this);
[98262]1637 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71560]1638
[45109]1639 if (aToRead == 0)
1640 return setError(E_INVALIDARG, tr("The size to read is zero"));
1641
[71560]1642 LogFlowThisFuncEnter();
1643
[79278]1644 /* Cap the read at 1MiB because that's all the guest will return anyway. */
1645 if (aToRead > _1M)
1646 aToRead = _1M;
1647
[94942]1648 HRESULT hrc = S_OK;
[45109]1649
[97609]1650 int vrc;
1651 try
1652 {
1653 aData.resize(aToRead);
1654
1655 uint32_t cbRead;
1656 vrc = i_readData(aToRead, aTimeoutMS,
[52934]1657 &aData.front(), aToRead, &cbRead);
[50618]1658
[97609]1659 if (RT_SUCCESS(vrc))
1660 {
1661 if (aData.size() != cbRead)
1662 aData.resize(cbRead);
1663 }
1664 else
1665 {
1666 aData.resize(0);
1667 }
1668 }
1669 catch (std::bad_alloc &)
[45109]1670 {
[97609]1671 vrc = VERR_NO_MEMORY;
[45109]1672 }
[52934]1673
[97609]1674 if (RT_FAILURE(vrc))
[94942]1675 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" failed: %Rrc"),
1676 mData.mOpenInfo.mFilename.c_str(), vrc);
[45109]1677
1678 LogFlowFuncLeaveRC(vrc);
[94942]1679 return hrc;
[42084]1680}
[71782]1681
[50618]1682HRESULT GuestFile::readAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
[42084]1683{
[71560]1684 AutoCaller autoCaller(this);
[98262]1685 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71560]1686
[45109]1687 if (aToRead == 0)
[84648]1688 return setError(E_INVALIDARG, tr("The size to read for guest file \"%s\" is zero"), mData.mOpenInfo.mFilename.c_str());
[45109]1689
[71560]1690 LogFlowThisFuncEnter();
1691
[79278]1692 /* Cap the read at 1MiB because that's all the guest will return anyway. */
1693 if (aToRead > _1M)
1694 aToRead = _1M;
1695
[94942]1696 HRESULT hrc = S_OK;
[45109]1697
[97609]1698 int vrc;
1699 try
1700 {
1701 aData.resize(aToRead);
1702
1703 size_t cbRead;
1704 vrc = i_readDataAt(aOffset, aToRead, aTimeoutMS,
[52934]1705 &aData.front(), aToRead, &cbRead);
[97609]1706 if (RT_SUCCESS(vrc))
1707 {
1708 if (aData.size() != cbRead)
1709 aData.resize(cbRead);
1710 }
1711 else
1712 {
1713 aData.resize(0);
1714 }
1715 }
1716 catch (std::bad_alloc &)
[45109]1717 {
[97609]1718 vrc = VERR_NO_MEMORY;
[45109]1719 }
[52934]1720
[97609]1721 if (RT_FAILURE(vrc))
[94942]1722 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1723 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
[45109]1724
1725 LogFlowFuncLeaveRC(vrc);
[94942]1726 return hrc;
[42084]1727}
1728
[55631]1729HRESULT GuestFile::seek(LONG64 aOffset, FileSeekOrigin_T aWhence, LONG64 *aNewOffset)
[42084]1730{
[71560]1731 AutoCaller autoCaller(this);
[98262]1732 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[45109]1733
[94942]1734 HRESULT hrc = S_OK;
[45109]1735
1736 GUEST_FILE_SEEKTYPE eSeekType;
[50618]1737 switch (aWhence)
[45109]1738 {
[55668]1739 case FileSeekOrigin_Begin:
[45109]1740 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1741 break;
1742
[55631]1743 case FileSeekOrigin_Current:
[45109]1744 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1745 break;
1746
[55631]1747 case FileSeekOrigin_End:
1748 eSeekType = GUEST_FILE_SEEKTYPE_END;
1749 break;
1750
[45109]1751 default:
[84648]1752 return setError(E_INVALIDARG, tr("Invalid seek type for guest file \"%s\" specified"),
1753 mData.mOpenInfo.mFilename.c_str());
[45109]1754 }
1755
[71560]1756 LogFlowThisFuncEnter();
1757
[55631]1758 uint64_t uNewOffset;
[104003]1759 int vrc = i_seekAt(aOffset, eSeekType, GSTCTL_DEFAULT_TIMEOUT_MS, &uNewOffset);
[55631]1760 if (RT_SUCCESS(vrc))
1761 *aNewOffset = RT_MIN(uNewOffset, (uint64_t)INT64_MAX);
1762 else
[94942]1763 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"),
1764 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
[45109]1765
1766 LogFlowFuncLeaveRC(vrc);
[94942]1767 return hrc;
[42084]1768}
1769
[55631]1770HRESULT GuestFile::setACL(const com::Utf8Str &aAcl, ULONG aMode)
[42084]1771{
[63244]1772 RT_NOREF(aAcl, aMode);
[42084]1773 ReturnComNotImplemented();
1774}
1775
[55631]1776HRESULT GuestFile::setSize(LONG64 aSize)
1777{
[79287]1778 LogFlowThisFuncEnter();
1779
1780 /*
1781 * Validate.
1782 */
1783 if (aSize < 0)
[84648]1784 return setError(E_INVALIDARG, tr("The size (%RI64) for guest file \"%s\" cannot be a negative value"),
1785 aSize, mData.mOpenInfo.mFilename.c_str());
[79287]1786
1787 /*
1788 * Register event callbacks.
1789 */
1790 int vrc;
1791 GuestWaitEvent *pWaitEvent = NULL;
1792 GuestEventTypes lstEventTypes;
1793 try
1794 {
1795 lstEventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1796 lstEventTypes.push_back(VBoxEventType_OnGuestFileSizeChanged);
1797 }
1798 catch (std::bad_alloc &)
1799 {
1800 return E_OUTOFMEMORY;
1801 }
1802
1803 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1804
1805 vrc = registerWaitEvent(lstEventTypes, &pWaitEvent);
1806 if (RT_SUCCESS(vrc))
1807 {
1808 /*
1809 * Send of the HGCM message.
1810 */
1811 VBOXHGCMSVCPARM aParms[3];
1812 HGCMSvcSetU32(&aParms[0], pWaitEvent->ContextID());
1813 HGCMSvcSetU32(&aParms[1], mObjectID /* File handle */);
1814 HGCMSvcSetU64(&aParms[2], aSize);
1815
1816 alock.release(); /* Drop write lock before sending. */
1817
1818 vrc = sendMessage(HOST_MSG_FILE_SET_SIZE, RT_ELEMENTS(aParms), aParms);
1819 if (RT_SUCCESS(vrc))
1820 {
1821 /*
1822 * Wait for the event.
1823 */
1824 VBoxEventType_T enmEvtType;
1825 ComPtr<IEvent> pIEvent;
1826 vrc = waitForEvent(pWaitEvent, RT_MS_1MIN / 2, &enmEvtType, pIEvent.asOutParam());
1827 if (RT_SUCCESS(vrc))
1828 {
1829 if (enmEvtType == VBoxEventType_OnGuestFileSizeChanged)
1830 vrc = VINF_SUCCESS;
1831 else
1832 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1833 }
[98666]1834
1835 if (pWaitEvent->HasGuestError()) /* Return guest vrc if available. */
1836 vrc = pWaitEvent->GuestResult();
[79287]1837 }
1838
1839 /*
1840 * Unregister the wait event and deal with error reporting if needed.
1841 */
1842 unregisterWaitEvent(pWaitEvent);
1843 }
1844 HRESULT hrc;
1845 if (RT_SUCCESS(vrc))
1846 hrc = S_OK;
1847 else
[91718]1848 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
1849 tr("Setting the guest file size of \"%s\" to %RU64 (%#RX64) bytes failed: %Rrc", "", aSize),
[79287]1850 mData.mOpenInfo.mFilename.c_str(), aSize, aSize, vrc);
1851 LogFlowFuncLeaveRC(vrc);
1852 return hrc;
[55631]1853}
1854
[50618]1855HRESULT GuestFile::write(const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
[42084]1856{
[71560]1857 AutoCaller autoCaller(this);
[98262]1858 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71560]1859
[77386]1860 if (aData.size() == 0)
[84648]1861 return setError(E_INVALIDARG, tr("No data to write specified"), mData.mOpenInfo.mFilename.c_str());
[77386]1862
[45109]1863 LogFlowThisFuncEnter();
1864
[94942]1865 HRESULT hrc = S_OK;
[45109]1866
[77387]1867 const uint32_t cbData = (uint32_t)aData.size();
1868 const void *pvData = (void *)&aData.front();
[71560]1869 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
[45109]1870 if (RT_FAILURE(vrc))
[94942]1871 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zu bytes to guest file \"%s\" failed: %Rrc", "", aData.size()),
1872 aData.size(), mData.mOpenInfo.mFilename.c_str(), vrc);
[45109]1873
1874 LogFlowFuncLeaveRC(vrc);
[94942]1875 return hrc;
[42084]1876}
1877
[50618]1878HRESULT GuestFile::writeAt(LONG64 aOffset, const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
[42084]1879{
[71560]1880 AutoCaller autoCaller(this);
[98262]1881 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
[71560]1882
[77386]1883 if (aData.size() == 0)
[84648]1884 return setError(E_INVALIDARG, tr("No data to write at for guest file \"%s\" specified"), mData.mOpenInfo.mFilename.c_str());
[77386]1885
[45109]1886 LogFlowThisFuncEnter();
1887
[94942]1888 HRESULT hrc = S_OK;
[45109]1889
[77387]1890 const uint32_t cbData = (uint32_t)aData.size();
1891 const void *pvData = (void *)&aData.front();
[79282]1892 int vrc = i_writeDataAt(aOffset, aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
[45109]1893 if (RT_FAILURE(vrc))
[94942]1894 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
1895 tr("Writing %zu bytes to file \"%s\" (at offset %RU64) failed: %Rrc", "", aData.size()),
1896 aData.size(), mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
[45109]1897
1898 LogFlowFuncLeaveRC(vrc);
[94942]1899 return hrc;
[42084]1900}
1901
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use