VirtualBox

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

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

Guest Control/Main: Added lots of missing docs.

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

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