VirtualBox

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

最後變更 在這個檔案從97610是 97610,由 vboxsync 提交於 2 年 前

Guest Control/Main: Also catch (and handle) OOM situations in GuestFile notification callbacks better.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette