[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 | */
|
---|
| 60 | class GuestFileListener
|
---|
| 61 | {
|
---|
| 62 | public:
|
---|
| 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 |
|
---|
| 111 | private:
|
---|
| 112 |
|
---|
[92897] | 113 | /** Weak pointer to the guest file object to listen for. */
|
---|
[49610] | 114 | GuestFile *mFile;
|
---|
[45780] | 115 | };
|
---|
| 116 | typedef ListenerImpl<GuestFileListener, GuestFile*> GuestFileListenerImpl;
|
---|
| 117 |
|
---|
| 118 | VBOX_LISTENER_DECLARE(GuestFileListenerImpl)
|
---|
| 119 |
|
---|
[42084] | 120 | // constructor / destructor
|
---|
| 121 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 122 |
|
---|
| 123 | DEFINE_EMPTY_CTOR_DTOR(GuestFile)
|
---|
| 124 |
|
---|
[42897] | 125 | HRESULT GuestFile::FinalConstruct(void)
|
---|
[42084] | 126 | {
|
---|
[49389] | 127 | LogFlowThisFuncEnter();
|
---|
[42084] | 128 | return BaseFinalConstruct();
|
---|
| 129 | }
|
---|
| 130 |
|
---|
| 131 | void 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] | 152 | int 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 | */
|
---|
| 238 | void 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] | 254 | HRESULT 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] | 263 | HRESULT 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] | 272 | HRESULT 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] | 280 | HRESULT 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] | 289 | HRESULT 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] | 298 | HRESULT 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] | 307 | HRESULT 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] | 324 | HRESULT 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] | 333 | HRESULT 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] | 354 | int 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] | 393 | int 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 */
|
---|
| 445 | Utf8Str 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] | 475 | int 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] | 729 | int 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] | 743 | int 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 | */
|
---|
| 770 | int 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] | 794 | int 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] | 900 | int 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] | 918 | int 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] | 991 | int 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] | 1060 | int 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] | 1129 | int 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] | 1179 | int 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] | 1220 | int 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] | 1287 | int 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] | 1343 | int 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] | 1383 | int 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] | 1457 | int 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] | 1521 | HRESULT 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] | 1547 | HRESULT 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] | 1597 | HRESULT 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] | 1635 | HRESULT 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] | 1683 | HRESULT 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] | 1730 | HRESULT 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] | 1772 | HRESULT GuestFile::setACL(const com::Utf8Str &aAcl, ULONG aMode)
|
---|
[42084] | 1773 | {
|
---|
[63244] | 1774 | RT_NOREF(aAcl, aMode);
|
---|
[42084] | 1775 | ReturnComNotImplemented();
|
---|
| 1776 | }
|
---|
| 1777 |
|
---|
[55631] | 1778 | HRESULT 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] | 1857 | HRESULT 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] | 1880 | HRESULT 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 |
|
---|