VirtualBox

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

Last change on this file since 94521 was 93115, checked in by vboxsync, 2 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.0 KB
Line 
1/* $Id: GuestFileImpl.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Guest file handling.
4 */
5
6/*
7 * Copyright (C) 2012-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.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 pSvcCb 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 uSize Size (in bytes) to read.
886 * @param uTimeoutMS Timeout (in ms) to wait.
887 * @param pvData Where to store the read data on success.
888 * @param cbData Size (in bytes) of \a pvData on input.
889 * @param pcbRead Where to return to size (in bytes) read on success.
890 * Optional.
891 */
892int GuestFile::i_readData(uint32_t uSize, uint32_t uTimeoutMS,
893 void* pvData, uint32_t cbData, uint32_t* pcbRead)
894{
895 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
896 AssertReturn(cbData, VERR_INVALID_PARAMETER);
897
898 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
899 uSize, uTimeoutMS, pvData, cbData));
900
901 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
902
903 int vrc;
904
905 GuestWaitEvent *pEvent = NULL;
906 GuestEventTypes eventTypes;
907 try
908 {
909 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
910 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
911
912 vrc = registerWaitEvent(eventTypes, &pEvent);
913 }
914 catch (std::bad_alloc &)
915 {
916 vrc = VERR_NO_MEMORY;
917 }
918
919 if (RT_FAILURE(vrc))
920 return vrc;
921
922 /* Prepare HGCM call. */
923 VBOXHGCMSVCPARM paParms[4];
924 int i = 0;
925 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
926 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
927 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
928
929 alock.release(); /* Drop write lock before sending. */
930
931 vrc = sendMessage(HOST_MSG_FILE_READ, i, paParms);
932 if (RT_SUCCESS(vrc))
933 {
934 uint32_t cbRead = 0;
935 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
936 if (RT_SUCCESS(vrc))
937 {
938 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
939 if (pcbRead)
940 *pcbRead = cbRead;
941 }
942 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
943 {
944 vrc = pEvent->GetGuestError();
945 }
946 }
947
948 unregisterWaitEvent(pEvent);
949
950 LogFlowFuncLeaveRC(vrc);
951 return vrc;
952}
953
954/**
955 * Reads data from a specific position from a guest file.
956 *
957 * @returns VBox status code.
958 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
959 * @param uOffset Offset (in bytes) to start reading from.
960 * @param uSize Size (in bytes) to read.
961 * @param uTimeoutMS Timeout (in ms) to wait.
962 * @param pvData Where to store the read data on success.
963 * @param cbData Size (in bytes) of \a pvData on input.
964 * @param pcbRead Where to return to size (in bytes) read on success.
965 * Optional.
966 */
967int GuestFile::i_readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
968 void* pvData, size_t cbData, size_t* pcbRead)
969{
970 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
971 uOffset, uSize, uTimeoutMS, pvData, cbData));
972
973 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
974
975 int vrc;
976
977 GuestWaitEvent *pEvent = NULL;
978 GuestEventTypes eventTypes;
979 try
980 {
981 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
982 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
983
984 vrc = registerWaitEvent(eventTypes, &pEvent);
985 }
986 catch (std::bad_alloc &)
987 {
988 vrc = VERR_NO_MEMORY;
989 }
990
991 if (RT_FAILURE(vrc))
992 return vrc;
993
994 /* Prepare HGCM call. */
995 VBOXHGCMSVCPARM paParms[4];
996 int i = 0;
997 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
998 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
999 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset (in bytes) to start reading */);
1000 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
1001
1002 alock.release(); /* Drop write lock before sending. */
1003
1004 vrc = sendMessage(HOST_MSG_FILE_READ_AT, i, paParms);
1005 if (RT_SUCCESS(vrc))
1006 {
1007 uint32_t cbRead = 0;
1008 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
1009 if (RT_SUCCESS(vrc))
1010 {
1011 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
1012
1013 if (pcbRead)
1014 *pcbRead = cbRead;
1015 }
1016 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1017 {
1018 vrc = pEvent->GetGuestError();
1019 }
1020 }
1021
1022 unregisterWaitEvent(pEvent);
1023
1024 LogFlowFuncLeaveRC(vrc);
1025 return vrc;
1026}
1027
1028/**
1029 * Seeks a guest file to a specific position.
1030 *
1031 * @returns VBox status code.
1032 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1033 * @param iOffset Offset (in bytes) to seek.
1034 * @param eSeekType Seek type to use.
1035 * @param uTimeoutMS Timeout (in ms) to wait.
1036 * @param puOffset Where to return the new current file position (in bytes) on success.
1037 */
1038int GuestFile::i_seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType,
1039 uint32_t uTimeoutMS, uint64_t *puOffset)
1040{
1041 LogFlowThisFunc(("iOffset=%RI64, uTimeoutMS=%RU32\n",
1042 iOffset, uTimeoutMS));
1043
1044 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1045
1046 int vrc;
1047
1048 GuestWaitEvent *pEvent = NULL;
1049 GuestEventTypes eventTypes;
1050 try
1051 {
1052 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1053 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
1054
1055 vrc = registerWaitEvent(eventTypes, &pEvent);
1056 }
1057 catch (std::bad_alloc &)
1058 {
1059 vrc = VERR_NO_MEMORY;
1060 }
1061
1062 if (RT_FAILURE(vrc))
1063 return vrc;
1064
1065 /* Prepare HGCM call. */
1066 VBOXHGCMSVCPARM paParms[4];
1067 int i = 0;
1068 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1069 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1070 HGCMSvcSetU32(&paParms[i++], eSeekType /* Seek method */);
1071 /** @todo uint64_t vs. int64_t! */
1072 HGCMSvcSetU64(&paParms[i++], (uint64_t)iOffset /* Offset (in bytes) to start reading */);
1073
1074 alock.release(); /* Drop write lock before sending. */
1075
1076 vrc = sendMessage(HOST_MSG_FILE_SEEK, i, paParms);
1077 if (RT_SUCCESS(vrc))
1078 {
1079 uint64_t uOffset;
1080 vrc = i_waitForOffsetChange(pEvent, uTimeoutMS, &uOffset);
1081 if (RT_SUCCESS(vrc))
1082 {
1083 LogFlowThisFunc(("uOffset=%RU64\n", uOffset));
1084
1085 if (puOffset)
1086 *puOffset = uOffset;
1087 }
1088 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1089 {
1090 vrc = pEvent->GetGuestError();
1091 }
1092 }
1093
1094 unregisterWaitEvent(pEvent);
1095
1096 LogFlowFuncLeaveRC(vrc);
1097 return vrc;
1098}
1099
1100/**
1101 * Sets the current internal file object status.
1102 *
1103 * @returns VBox status code.
1104 * @param fileStatus New file status to set.
1105 * @param fileRc New result code to set.
1106 *
1107 * @note Takes the write lock.
1108 */
1109int GuestFile::i_setFileStatus(FileStatus_T fileStatus, int fileRc)
1110{
1111 LogFlowThisFuncEnter();
1112
1113 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1114
1115 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, fileRc=%Rrc\n",
1116 mData.mStatus, fileStatus, fileRc));
1117
1118#ifdef VBOX_STRICT
1119 if (fileStatus == FileStatus_Error)
1120 {
1121 AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc));
1122 }
1123 else
1124 AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc));
1125#endif
1126
1127 if (mData.mStatus != fileStatus)
1128 {
1129 mData.mStatus = fileStatus;
1130 mData.mLastError = fileRc;
1131
1132 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
1133 HRESULT hr = errorInfo.createObject();
1134 ComAssertComRC(hr);
1135 if (RT_FAILURE(fileRc))
1136 {
1137 hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, fileRc,
1138 COM_IIDOF(IGuestFile), getComponentName(),
1139 i_guestErrorToString(fileRc, mData.mOpenInfo.mFilename.c_str()));
1140 ComAssertComRC(hr);
1141 }
1142
1143 alock.release(); /* Release lock before firing off event. */
1144
1145 ::FireGuestFileStateChangedEvent(mEventSource, mSession, this, fileStatus, errorInfo);
1146 }
1147
1148 return VINF_SUCCESS;
1149}
1150
1151/**
1152 * Waits for a guest file offset change.
1153 *
1154 * @returns VBox status code.
1155 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1156 * @param pEvent Guest wait event to wait for.
1157 * @param uTimeoutMS Timeout (in ms) to wait.
1158 * @param puOffset Where to return the new offset (in bytes) on success.
1159 * Optional and can be NULL.
1160 */
1161int GuestFile::i_waitForOffsetChange(GuestWaitEvent *pEvent,
1162 uint32_t uTimeoutMS, uint64_t *puOffset)
1163{
1164 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1165
1166 VBoxEventType_T evtType;
1167 ComPtr<IEvent> pIEvent;
1168 int vrc = waitForEvent(pEvent, uTimeoutMS,
1169 &evtType, pIEvent.asOutParam());
1170 if (RT_SUCCESS(vrc))
1171 {
1172 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
1173 {
1174 if (puOffset)
1175 {
1176 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
1177 Assert(!pFileEvent.isNull());
1178
1179 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
1180 ComAssertComRC(hr);
1181 }
1182 }
1183 else
1184 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1185 }
1186
1187 return vrc;
1188}
1189
1190/**
1191 * Waits for reading from a guest file.
1192 *
1193 * @returns VBox status code.
1194 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1195 * @param pEvent Guest wait event to wait for.
1196 * @param uTimeoutMS Timeout (in ms) to wait.
1197 * @param pvData Where to store read file data on success.
1198 * @param cbData Size (in bytes) of \a pvData.
1199 * @param pcbRead Where to return the actual bytes read on success.
1200 * Optional and can be NULL.
1201 */
1202int GuestFile::i_waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1203 void *pvData, size_t cbData, uint32_t *pcbRead)
1204{
1205 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1206
1207 VBoxEventType_T evtType;
1208 ComPtr<IEvent> pIEvent;
1209 int vrc = waitForEvent(pEvent, uTimeoutMS,
1210 &evtType, pIEvent.asOutParam());
1211 if (RT_SUCCESS(vrc))
1212 {
1213 if (evtType == VBoxEventType_OnGuestFileRead)
1214 {
1215 vrc = VINF_SUCCESS;
1216
1217 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
1218 Assert(!pFileEvent.isNull());
1219
1220 if (pvData)
1221 {
1222 com::SafeArray <BYTE> data;
1223 HRESULT hrc1 = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1224 ComAssertComRC(hrc1);
1225 const size_t cbRead = data.size();
1226 if (cbRead)
1227 {
1228 if (cbRead <= cbData)
1229 memcpy(pvData, data.raw(), cbRead);
1230 else
1231 vrc = VERR_BUFFER_OVERFLOW;
1232 }
1233 /* else: used to be VERR_NO_DATA, but that messes stuff up. */
1234
1235 if (pcbRead)
1236 {
1237 *pcbRead = (uint32_t)cbRead;
1238 Assert(*pcbRead == cbRead);
1239 }
1240 }
1241 else if (pcbRead)
1242 {
1243 *pcbRead = 0;
1244 HRESULT hrc2 = pFileEvent->COMGETTER(Processed)((ULONG *)pcbRead);
1245 ComAssertComRC(hrc2); NOREF(hrc2);
1246 }
1247 }
1248 else
1249 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1250 }
1251
1252 return vrc;
1253}
1254
1255/**
1256 * Waits for a guest file status change.
1257 *
1258 * @note Similar code in GuestProcess::i_waitForStatusChange() and
1259 * GuestSession::i_waitForStatusChange().
1260 *
1261 * @returns VBox status code.
1262 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1263 * @param pEvent Guest wait event to wait for.
1264 * @param uTimeoutMS Timeout (in ms) to wait.
1265 * @param pFileStatus Where to return the file status on success.
1266 * @param prcGuest Where to return the guest error when VERR_GSTCTL_GUEST_ERROR
1267 * was returned.
1268 */
1269int GuestFile::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1270 FileStatus_T *pFileStatus, int *prcGuest)
1271{
1272 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1273 /* pFileStatus is optional. */
1274
1275 VBoxEventType_T evtType;
1276 ComPtr<IEvent> pIEvent;
1277 int vrc = waitForEvent(pEvent, uTimeoutMS,
1278 &evtType, pIEvent.asOutParam());
1279 if (RT_SUCCESS(vrc))
1280 {
1281 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
1282 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
1283 Assert(!pFileEvent.isNull());
1284
1285 HRESULT hr;
1286 if (pFileStatus)
1287 {
1288 hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1289 ComAssertComRC(hr);
1290 }
1291
1292 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1293 hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam());
1294 ComAssertComRC(hr);
1295
1296 LONG lGuestRc;
1297 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1298 ComAssertComRC(hr);
1299
1300 LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n",
1301 lGuestRc, lGuestRc));
1302
1303 if (RT_FAILURE((int)lGuestRc))
1304 vrc = VERR_GSTCTL_GUEST_ERROR;
1305
1306 if (prcGuest)
1307 *prcGuest = (int)lGuestRc;
1308 }
1309 /* waitForEvent may also return VERR_GSTCTL_GUEST_ERROR like we do above, so make prcGuest is set. */
1310 /** @todo r=bird: Andy, you seem to have forgotten this scenario. Showed up occasionally when
1311 * using the wrong password with a copyto command in a debug build on windows, error info
1312 * contained "Unknown Status -858993460 (0xcccccccc)". As you know windows fills the stack frames
1313 * with 0xcccccccc in debug builds to highlight use of uninitialized data, so that's what happened
1314 * here. It's actually good you didn't initialize lGuest, as it would be heck to find otherwise.
1315 *
1316 * I'm still not very impressed with the error managment or the usuefullness of the documentation
1317 * in this code, though the latter is getting better! */
1318 else if (vrc == VERR_GSTCTL_GUEST_ERROR && prcGuest)
1319 *prcGuest = pEvent->GuestResult();
1320 Assert(vrc != VERR_GSTCTL_GUEST_ERROR || !prcGuest || *prcGuest != (int)0xcccccccc);
1321
1322 return vrc;
1323}
1324
1325int GuestFile::i_waitForWrite(GuestWaitEvent *pEvent,
1326 uint32_t uTimeoutMS, uint32_t *pcbWritten)
1327{
1328 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1329
1330 VBoxEventType_T evtType;
1331 ComPtr<IEvent> pIEvent;
1332 int vrc = waitForEvent(pEvent, uTimeoutMS,
1333 &evtType, pIEvent.asOutParam());
1334 if (RT_SUCCESS(vrc))
1335 {
1336 if (evtType == VBoxEventType_OnGuestFileWrite)
1337 {
1338 if (pcbWritten)
1339 {
1340 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1341 Assert(!pFileEvent.isNull());
1342
1343 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1344 ComAssertComRC(hr);
1345 }
1346 }
1347 else
1348 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1349 }
1350
1351 return vrc;
1352}
1353
1354/**
1355 * Writes data to a guest file.
1356 *
1357 * @returns VBox status code.
1358 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1359 * @param uTimeoutMS Timeout (in ms) to wait.
1360 * @param pvData Data to write.
1361 * @param cbData Size (in bytes) of \a pvData to write.
1362 * @param pcbWritten Where to return to size (in bytes) written on success.
1363 * Optional.
1364 */
1365int GuestFile::i_writeData(uint32_t uTimeoutMS, const void *pvData, uint32_t cbData,
1366 uint32_t *pcbWritten)
1367{
1368 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1369 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1370
1371 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1372 uTimeoutMS, pvData, cbData));
1373
1374 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1375
1376 int vrc;
1377
1378 GuestWaitEvent *pEvent = NULL;
1379 GuestEventTypes eventTypes;
1380 try
1381 {
1382 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1383 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1384
1385 vrc = registerWaitEvent(eventTypes, &pEvent);
1386 }
1387 catch (std::bad_alloc &)
1388 {
1389 vrc = VERR_NO_MEMORY;
1390 }
1391
1392 if (RT_FAILURE(vrc))
1393 return vrc;
1394
1395 /* Prepare HGCM call. */
1396 VBOXHGCMSVCPARM paParms[8];
1397 int i = 0;
1398 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1399 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1400 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
1401 HGCMSvcSetPv (&paParms[i++], unconst(pvData), cbData);
1402
1403 alock.release(); /* Drop write lock before sending. */
1404
1405 vrc = sendMessage(HOST_MSG_FILE_WRITE, i, paParms);
1406 if (RT_SUCCESS(vrc))
1407 {
1408 uint32_t cbWritten = 0;
1409 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1410 if (RT_SUCCESS(vrc))
1411 {
1412 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1413 if (pcbWritten)
1414 *pcbWritten = cbWritten;
1415 }
1416 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1417 {
1418 vrc = pEvent->GetGuestError();
1419 }
1420 }
1421
1422 unregisterWaitEvent(pEvent);
1423
1424 LogFlowFuncLeaveRC(vrc);
1425 return vrc;
1426}
1427
1428
1429/**
1430 * Writes data to a specific position to a guest file.
1431 *
1432 * @returns VBox status code.
1433 * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
1434 * @param uOffset Offset (in bytes) to start writing at.
1435 * @param uTimeoutMS Timeout (in ms) to wait.
1436 * @param pvData Data to write.
1437 * @param cbData Size (in bytes) of \a pvData to write.
1438 * @param pcbWritten Where to return to size (in bytes) written on success.
1439 * Optional.
1440 */
1441int GuestFile::i_writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
1442 const void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1443{
1444 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1445 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1446
1447 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1448 uOffset, uTimeoutMS, pvData, cbData));
1449
1450 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1451
1452 int vrc;
1453
1454 GuestWaitEvent *pEvent = NULL;
1455 GuestEventTypes eventTypes;
1456 try
1457 {
1458 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1459 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1460
1461 vrc = registerWaitEvent(eventTypes, &pEvent);
1462 }
1463 catch (std::bad_alloc &)
1464 {
1465 vrc = VERR_NO_MEMORY;
1466 }
1467
1468 if (RT_FAILURE(vrc))
1469 return vrc;
1470
1471 /* Prepare HGCM call. */
1472 VBOXHGCMSVCPARM paParms[8];
1473 int i = 0;
1474 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1475 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1476 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset where to starting writing */);
1477 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
1478 HGCMSvcSetPv (&paParms[i++], unconst(pvData), cbData);
1479
1480 alock.release(); /* Drop write lock before sending. */
1481
1482 vrc = sendMessage(HOST_MSG_FILE_WRITE_AT, i, paParms);
1483 if (RT_SUCCESS(vrc))
1484 {
1485 uint32_t cbWritten = 0;
1486 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1487 if (RT_SUCCESS(vrc))
1488 {
1489 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1490 if (pcbWritten)
1491 *pcbWritten = cbWritten;
1492 }
1493 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1494 {
1495 vrc = pEvent->GetGuestError();
1496 }
1497 }
1498
1499 unregisterWaitEvent(pEvent);
1500
1501 LogFlowFuncLeaveRC(vrc);
1502 return vrc;
1503}
1504
1505// Wrapped IGuestFile methods
1506/////////////////////////////////////////////////////////////////////////////
1507HRESULT GuestFile::close()
1508{
1509 AutoCaller autoCaller(this);
1510 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1511
1512 LogFlowThisFuncEnter();
1513
1514 /* Close file on guest. */
1515 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1516 int vrc = i_closeFile(&rcGuest);
1517 /* On failure don't return here, instead do all the cleanup
1518 * work first and then return an error. */
1519
1520 AssertPtr(mSession);
1521 int vrc2 = mSession->i_fileUnregister(this);
1522 if (RT_SUCCESS(vrc))
1523 vrc = vrc2;
1524
1525 if (RT_FAILURE(vrc))
1526 {
1527 if (vrc == VERR_GSTCTL_GUEST_ERROR)
1528 {
1529 GuestErrorInfo ge(GuestErrorInfo::Type_File, rcGuest, mData.mOpenInfo.mFilename.c_str());
1530 return setErrorBoth(VBOX_E_IPRT_ERROR, rcGuest, tr("Closing guest file failed: %s"),
1531 GuestBase::getErrorAsString(ge).c_str());
1532 }
1533 return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Closing guest file \"%s\" failed with %Rrc\n"),
1534 mData.mOpenInfo.mFilename.c_str(), vrc);
1535 }
1536
1537 LogFlowThisFunc(("Returning S_OK / vrc=%Rrc\n", vrc));
1538 return S_OK;
1539}
1540
1541HRESULT GuestFile::queryInfo(ComPtr<IFsObjInfo> &aObjInfo)
1542{
1543 AutoCaller autoCaller(this);
1544 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1545
1546 LogFlowThisFuncEnter();
1547
1548 HRESULT hr = S_OK;
1549
1550 GuestFsObjData fsObjData;
1551 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1552 int vrc = i_queryInfo(fsObjData, &rcGuest);
1553 if (RT_SUCCESS(vrc))
1554 {
1555 ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
1556 hr = ptrFsObjInfo.createObject();
1557 if (SUCCEEDED(hr))
1558 {
1559 vrc = ptrFsObjInfo->init(fsObjData);
1560 if (RT_SUCCESS(vrc))
1561 hr = ptrFsObjInfo.queryInterfaceTo(aObjInfo.asOutParam());
1562 else
1563 hr = setErrorVrc(vrc,
1564 tr("Initialization of guest file object for \"%s\" failed: %Rrc"),
1565 mData.mOpenInfo.mFilename.c_str(), vrc);
1566 }
1567 }
1568 else
1569 {
1570 if (GuestProcess::i_isGuestError(vrc))
1571 {
1572 GuestErrorInfo ge(GuestErrorInfo::Type_ToolStat, rcGuest, mData.mOpenInfo.mFilename.c_str());
1573 hr = setErrorBoth(VBOX_E_IPRT_ERROR, rcGuest, tr("Querying guest file information failed: %s"),
1574 GuestBase::getErrorAsString(ge).c_str());
1575 }
1576 else
1577 hr = setErrorVrc(vrc,
1578 tr("Querying guest file information for \"%s\" failed: %Rrc"), mData.mOpenInfo.mFilename.c_str(), vrc);
1579 }
1580
1581 LogFlowFuncLeaveRC(vrc);
1582 return hr;
1583}
1584
1585HRESULT GuestFile::querySize(LONG64 *aSize)
1586{
1587 AutoCaller autoCaller(this);
1588 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1589
1590 LogFlowThisFuncEnter();
1591
1592 HRESULT hr = S_OK;
1593
1594 GuestFsObjData fsObjData;
1595 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
1596 int vrc = i_queryInfo(fsObjData, &rcGuest);
1597 if (RT_SUCCESS(vrc))
1598 {
1599 *aSize = fsObjData.mObjectSize;
1600 }
1601 else
1602 {
1603 if (GuestProcess::i_isGuestError(vrc))
1604 {
1605 GuestErrorInfo ge(GuestErrorInfo::Type_ToolStat, rcGuest, mData.mOpenInfo.mFilename.c_str());
1606 hr = setErrorBoth(VBOX_E_IPRT_ERROR, rcGuest, tr("Querying guest file size failed: %s"),
1607 GuestBase::getErrorAsString(ge).c_str());
1608 }
1609 else
1610 hr = setErrorVrc(vrc, tr("Querying guest file size for \"%s\" failed: %Rrc"), mData.mOpenInfo.mFilename.c_str(), vrc);
1611 }
1612
1613 LogFlowFuncLeaveRC(vrc);
1614 return hr;
1615}
1616
1617HRESULT GuestFile::read(ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1618{
1619 AutoCaller autoCaller(this);
1620 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1621
1622 if (aToRead == 0)
1623 return setError(E_INVALIDARG, tr("The size to read is zero"));
1624
1625 LogFlowThisFuncEnter();
1626
1627 /* Cap the read at 1MiB because that's all the guest will return anyway. */
1628 if (aToRead > _1M)
1629 aToRead = _1M;
1630
1631 aData.resize(aToRead);
1632
1633 HRESULT hr = S_OK;
1634
1635 uint32_t cbRead;
1636 int vrc = i_readData(aToRead, aTimeoutMS,
1637 &aData.front(), aToRead, &cbRead);
1638
1639 if (RT_SUCCESS(vrc))
1640 {
1641 if (aData.size() != cbRead)
1642 aData.resize(cbRead);
1643 }
1644 else
1645 {
1646 aData.resize(0);
1647
1648 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" failed: %Rrc"),
1649 mData.mOpenInfo.mFilename.c_str(), vrc);
1650 }
1651
1652 LogFlowFuncLeaveRC(vrc);
1653 return hr;
1654}
1655
1656HRESULT GuestFile::readAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1657{
1658 AutoCaller autoCaller(this);
1659 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1660
1661 if (aToRead == 0)
1662 return setError(E_INVALIDARG, tr("The size to read for guest file \"%s\" is zero"), mData.mOpenInfo.mFilename.c_str());
1663
1664 LogFlowThisFuncEnter();
1665
1666 /* Cap the read at 1MiB because that's all the guest will return anyway. */
1667 if (aToRead > _1M)
1668 aToRead = _1M;
1669
1670 aData.resize(aToRead);
1671
1672 HRESULT hr = S_OK;
1673
1674 size_t cbRead;
1675 int vrc = i_readDataAt(aOffset, aToRead, aTimeoutMS,
1676 &aData.front(), aToRead, &cbRead);
1677 if (RT_SUCCESS(vrc))
1678 {
1679 if (aData.size() != cbRead)
1680 aData.resize(cbRead);
1681 }
1682 else
1683 {
1684 aData.resize(0);
1685
1686 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1687 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1688 }
1689
1690 LogFlowFuncLeaveRC(vrc);
1691 return hr;
1692}
1693
1694HRESULT GuestFile::seek(LONG64 aOffset, FileSeekOrigin_T aWhence, LONG64 *aNewOffset)
1695{
1696 AutoCaller autoCaller(this);
1697 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1698
1699 HRESULT hr = S_OK;
1700
1701 GUEST_FILE_SEEKTYPE eSeekType;
1702 switch (aWhence)
1703 {
1704 case FileSeekOrigin_Begin:
1705 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1706 break;
1707
1708 case FileSeekOrigin_Current:
1709 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1710 break;
1711
1712 case FileSeekOrigin_End:
1713 eSeekType = GUEST_FILE_SEEKTYPE_END;
1714 break;
1715
1716 default:
1717 return setError(E_INVALIDARG, tr("Invalid seek type for guest file \"%s\" specified"),
1718 mData.mOpenInfo.mFilename.c_str());
1719 }
1720
1721 LogFlowThisFuncEnter();
1722
1723 uint64_t uNewOffset;
1724 int vrc = i_seekAt(aOffset, eSeekType,
1725 30 * 1000 /* 30s timeout */, &uNewOffset);
1726 if (RT_SUCCESS(vrc))
1727 *aNewOffset = RT_MIN(uNewOffset, (uint64_t)INT64_MAX);
1728 else
1729 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"),
1730 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1731
1732 LogFlowFuncLeaveRC(vrc);
1733 return hr;
1734}
1735
1736HRESULT GuestFile::setACL(const com::Utf8Str &aAcl, ULONG aMode)
1737{
1738 RT_NOREF(aAcl, aMode);
1739 ReturnComNotImplemented();
1740}
1741
1742HRESULT GuestFile::setSize(LONG64 aSize)
1743{
1744 LogFlowThisFuncEnter();
1745
1746 /*
1747 * Validate.
1748 */
1749 if (aSize < 0)
1750 return setError(E_INVALIDARG, tr("The size (%RI64) for guest file \"%s\" cannot be a negative value"),
1751 aSize, mData.mOpenInfo.mFilename.c_str());
1752
1753 /*
1754 * Register event callbacks.
1755 */
1756 int vrc;
1757 GuestWaitEvent *pWaitEvent = NULL;
1758 GuestEventTypes lstEventTypes;
1759 try
1760 {
1761 lstEventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1762 lstEventTypes.push_back(VBoxEventType_OnGuestFileSizeChanged);
1763 }
1764 catch (std::bad_alloc &)
1765 {
1766 return E_OUTOFMEMORY;
1767 }
1768
1769 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1770
1771 vrc = registerWaitEvent(lstEventTypes, &pWaitEvent);
1772 if (RT_SUCCESS(vrc))
1773 {
1774 /*
1775 * Send of the HGCM message.
1776 */
1777 VBOXHGCMSVCPARM aParms[3];
1778 HGCMSvcSetU32(&aParms[0], pWaitEvent->ContextID());
1779 HGCMSvcSetU32(&aParms[1], mObjectID /* File handle */);
1780 HGCMSvcSetU64(&aParms[2], aSize);
1781
1782 alock.release(); /* Drop write lock before sending. */
1783
1784 vrc = sendMessage(HOST_MSG_FILE_SET_SIZE, RT_ELEMENTS(aParms), aParms);
1785 if (RT_SUCCESS(vrc))
1786 {
1787 /*
1788 * Wait for the event.
1789 */
1790 VBoxEventType_T enmEvtType;
1791 ComPtr<IEvent> pIEvent;
1792 vrc = waitForEvent(pWaitEvent, RT_MS_1MIN / 2, &enmEvtType, pIEvent.asOutParam());
1793 if (RT_SUCCESS(vrc))
1794 {
1795 if (enmEvtType == VBoxEventType_OnGuestFileSizeChanged)
1796 vrc = VINF_SUCCESS;
1797 else
1798 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1799 }
1800 if (RT_FAILURE(vrc) && pWaitEvent->HasGuestError()) /* Return guest rc if available. */
1801 vrc = pWaitEvent->GetGuestError();
1802 }
1803
1804 /*
1805 * Unregister the wait event and deal with error reporting if needed.
1806 */
1807 unregisterWaitEvent(pWaitEvent);
1808 }
1809 HRESULT hrc;
1810 if (RT_SUCCESS(vrc))
1811 hrc = S_OK;
1812 else
1813 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
1814 tr("Setting the guest file size of \"%s\" to %RU64 (%#RX64) bytes failed: %Rrc", "", aSize),
1815 mData.mOpenInfo.mFilename.c_str(), aSize, aSize, vrc);
1816 LogFlowFuncLeaveRC(vrc);
1817 return hrc;
1818}
1819
1820HRESULT GuestFile::write(const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1821{
1822 AutoCaller autoCaller(this);
1823 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1824
1825 if (aData.size() == 0)
1826 return setError(E_INVALIDARG, tr("No data to write specified"), mData.mOpenInfo.mFilename.c_str());
1827
1828 LogFlowThisFuncEnter();
1829
1830 HRESULT hr = S_OK;
1831
1832 const uint32_t cbData = (uint32_t)aData.size();
1833 const void *pvData = (void *)&aData.front();
1834 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1835 if (RT_FAILURE(vrc))
1836 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zu bytes to guest file \"%s\" failed: %Rrc", "", aData.size()),
1837 aData.size(), mData.mOpenInfo.mFilename.c_str(), vrc);
1838
1839 LogFlowFuncLeaveRC(vrc);
1840 return hr;
1841}
1842
1843HRESULT GuestFile::writeAt(LONG64 aOffset, const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1844{
1845 AutoCaller autoCaller(this);
1846 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1847
1848 if (aData.size() == 0)
1849 return setError(E_INVALIDARG, tr("No data to write at for guest file \"%s\" specified"), mData.mOpenInfo.mFilename.c_str());
1850
1851 LogFlowThisFuncEnter();
1852
1853 HRESULT hr = S_OK;
1854
1855 const uint32_t cbData = (uint32_t)aData.size();
1856 const void *pvData = (void *)&aData.front();
1857 int vrc = i_writeDataAt(aOffset, aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1858 if (RT_FAILURE(vrc))
1859 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
1860 tr("Writing %zu bytes to file \"%s\" (at offset %RU64) failed: %Rrc", "", aData.size()),
1861 aData.size(), mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1862
1863 LogFlowFuncLeaveRC(vrc);
1864 return hr;
1865}
1866
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use