VirtualBox

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

Last change on this file since 76690 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.1 KB
Line 
1/* $Id: GuestFileImpl.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Guest file handling.
4 */
5
6/*
7 * Copyright (C) 2012-2019 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
44
45/**
46 * Internal listener class to serve events in an
47 * active manner, e.g. without polling delays.
48 */
49class GuestFileListener
50{
51public:
52
53 GuestFileListener(void)
54 {
55 }
56
57 virtual ~GuestFileListener()
58 {
59 }
60
61 HRESULT init(GuestFile *pFile)
62 {
63 AssertPtrReturn(pFile, E_POINTER);
64 mFile = pFile;
65 return S_OK;
66 }
67
68 void uninit(void)
69 {
70 mFile = NULL;
71 }
72
73 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
74 {
75 switch (aType)
76 {
77 case VBoxEventType_OnGuestFileStateChanged:
78 case VBoxEventType_OnGuestFileOffsetChanged:
79 case VBoxEventType_OnGuestFileRead:
80 case VBoxEventType_OnGuestFileWrite:
81 {
82 AssertPtrReturn(mFile, E_POINTER);
83 int rc2 = mFile->signalWaitEvent(aType, aEvent);
84 NOREF(rc2);
85#ifdef DEBUG_andy
86 LogFlowFunc(("Signalling events of type=%RU32, file=%p resulted in rc=%Rrc\n",
87 aType, mFile, rc2));
88#endif
89 break;
90 }
91
92 default:
93 AssertMsgFailed(("Unhandled event %RU32\n", aType));
94 break;
95 }
96
97 return S_OK;
98 }
99
100private:
101
102 GuestFile *mFile;
103};
104typedef ListenerImpl<GuestFileListener, GuestFile*> GuestFileListenerImpl;
105
106VBOX_LISTENER_DECLARE(GuestFileListenerImpl)
107
108// constructor / destructor
109/////////////////////////////////////////////////////////////////////////////
110
111DEFINE_EMPTY_CTOR_DTOR(GuestFile)
112
113HRESULT GuestFile::FinalConstruct(void)
114{
115 LogFlowThisFuncEnter();
116 return BaseFinalConstruct();
117}
118
119void GuestFile::FinalRelease(void)
120{
121 LogFlowThisFuncEnter();
122 uninit();
123 BaseFinalRelease();
124 LogFlowThisFuncLeave();
125}
126
127// public initializer/uninitializer for internal purposes only
128/////////////////////////////////////////////////////////////////////////////
129
130/**
131 * Initializes a file object but does *not* open the file on the guest
132 * yet. This is done in the dedidcated openFile call.
133 *
134 * @return IPRT status code.
135 * @param pConsole Pointer to console object.
136 * @param pSession Pointer to session object.
137 * @param aObjectID The object's ID.
138 * @param openInfo File opening information.
139 */
140int GuestFile::init(Console *pConsole, GuestSession *pSession,
141 ULONG aObjectID, const GuestFileOpenInfo &openInfo)
142{
143 LogFlowThisFunc(("pConsole=%p, pSession=%p, aObjectID=%RU32, strPath=%s\n",
144 pConsole, pSession, aObjectID, openInfo.mFilename.c_str()));
145
146 AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
147 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
148
149 /* Enclose the state transition NotReady->InInit->Ready. */
150 AutoInitSpan autoInitSpan(this);
151 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
152
153 int vrc = bindToSession(pConsole, pSession, aObjectID);
154 if (RT_SUCCESS(vrc))
155 {
156 mSession = pSession;
157
158 mData.mInitialSize = 0;
159 mData.mStatus = FileStatus_Undefined;
160 mData.mOpenInfo = openInfo;
161
162 unconst(mEventSource).createObject();
163 HRESULT hr = mEventSource->init();
164 if (FAILED(hr))
165 vrc = VERR_COM_UNEXPECTED;
166 }
167
168 if (RT_SUCCESS(vrc))
169 {
170 try
171 {
172 GuestFileListener *pListener = new GuestFileListener();
173 ComObjPtr<GuestFileListenerImpl> thisListener;
174 HRESULT hr = thisListener.createObject();
175 if (SUCCEEDED(hr))
176 hr = thisListener->init(pListener, this);
177
178 if (SUCCEEDED(hr))
179 {
180 com::SafeArray <VBoxEventType_T> eventTypes;
181 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
182 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
183 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
184 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
185 hr = mEventSource->RegisterListener(thisListener,
186 ComSafeArrayAsInParam(eventTypes),
187 TRUE /* Active listener */);
188 if (SUCCEEDED(hr))
189 {
190 vrc = baseInit();
191 if (RT_SUCCESS(vrc))
192 {
193 mLocalListener = thisListener;
194 }
195 }
196 else
197 vrc = VERR_COM_UNEXPECTED;
198 }
199 else
200 vrc = VERR_COM_UNEXPECTED;
201 }
202 catch(std::bad_alloc &)
203 {
204 vrc = VERR_NO_MEMORY;
205 }
206 }
207
208 if (RT_SUCCESS(vrc))
209 {
210 /* Confirm a successful initialization when it's the case. */
211 autoInitSpan.setSucceeded();
212 }
213 else
214 autoInitSpan.setFailed();
215
216 LogFlowFuncLeaveRC(vrc);
217 return vrc;
218}
219
220/**
221 * Uninitializes the instance.
222 * Called from FinalRelease().
223 */
224void GuestFile::uninit(void)
225{
226 /* Enclose the state transition Ready->InUninit->NotReady. */
227 AutoUninitSpan autoUninitSpan(this);
228 if (autoUninitSpan.uninitDone())
229 return;
230
231 LogFlowThisFuncEnter();
232
233 baseUninit();
234 LogFlowThisFuncLeave();
235}
236
237// implementation of public getters/setters for attributes
238/////////////////////////////////////////////////////////////////////////////
239
240HRESULT GuestFile::getCreationMode(ULONG *aCreationMode)
241{
242 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
243
244 *aCreationMode = mData.mOpenInfo.mCreationMode;
245
246 return S_OK;
247}
248
249HRESULT GuestFile::getOpenAction(FileOpenAction_T *aOpenAction)
250{
251 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
252
253 *aOpenAction = mData.mOpenInfo.mOpenAction;
254
255 return S_OK;
256}
257
258HRESULT GuestFile::getEventSource(ComPtr<IEventSource> &aEventSource)
259{
260 /* No need to lock - lifetime constant. */
261 mEventSource.queryInterfaceTo(aEventSource.asOutParam());
262
263 return S_OK;
264}
265
266HRESULT GuestFile::getFilename(com::Utf8Str &aFilename)
267{
268 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
269
270 aFilename = mData.mOpenInfo.mFilename;
271
272 return S_OK;
273}
274
275HRESULT GuestFile::getId(ULONG *aId)
276{
277 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
278
279 *aId = mObjectID;
280
281 return S_OK;
282}
283
284HRESULT GuestFile::getInitialSize(LONG64 *aInitialSize)
285{
286 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
287
288 *aInitialSize = mData.mInitialSize;
289
290 return S_OK;
291}
292
293HRESULT GuestFile::getOffset(LONG64 *aOffset)
294{
295 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
296
297/** @todo r=bird: Why do you have both a offset and a tell() function?
298 * After a ReadAt or WriteAt with a non-current offset, the tell() result will
299 * differ from this value, because mOffCurrent is only ever incremented with
300 * data read or written. */
301 *aOffset = mData.mOffCurrent;
302
303 return S_OK;
304}
305
306HRESULT GuestFile::getAccessMode(FileAccessMode_T *aAccessMode)
307{
308 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
309
310 *aAccessMode = mData.mOpenInfo.mAccessMode;
311
312 return S_OK;
313}
314
315HRESULT GuestFile::getStatus(FileStatus_T *aStatus)
316{
317 LogFlowThisFuncEnter();
318
319 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
320
321 *aStatus = mData.mStatus;
322
323 return S_OK;
324}
325
326// private methods
327/////////////////////////////////////////////////////////////////////////////
328
329int GuestFile::i_callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
330{
331 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
332 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
333
334 LogFlowThisFunc(("strName=%s, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
335 mData.mOpenInfo.mFilename.c_str(), pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
336
337 int vrc;
338 switch (pCbCtx->uFunction)
339 {
340 case GUEST_DISCONNECTED:
341 vrc = i_onGuestDisconnected(pCbCtx, pSvcCb);
342 break;
343
344 case GUEST_FILE_NOTIFY:
345 vrc = i_onFileNotify(pCbCtx, pSvcCb);
346 break;
347
348 default:
349 /* Silently ignore not implemented functions. */
350 vrc = VERR_NOT_SUPPORTED;
351 break;
352 }
353
354#ifdef DEBUG
355 LogFlowFuncLeaveRC(vrc);
356#endif
357 return vrc;
358}
359
360int GuestFile::i_closeFile(int *prcGuest)
361{
362 LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFilename.c_str()));
363
364 int vrc;
365
366 GuestWaitEvent *pEvent = NULL;
367 GuestEventTypes eventTypes;
368 try
369 {
370 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
371
372 vrc = registerWaitEvent(eventTypes, &pEvent);
373 }
374 catch (std::bad_alloc &)
375 {
376 vrc = VERR_NO_MEMORY;
377 }
378
379 if (RT_FAILURE(vrc))
380 return vrc;
381
382 /* Prepare HGCM call. */
383 VBOXHGCMSVCPARM paParms[4];
384 int i = 0;
385 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
386 HGCMSvcSetU32(&paParms[i++], mObjectID /* Guest file ID */);
387
388 vrc = sendCommand(HOST_FILE_CLOSE, i, paParms);
389 if (RT_SUCCESS(vrc))
390 vrc = i_waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */,
391 NULL /* FileStatus */, prcGuest);
392 unregisterWaitEvent(pEvent);
393
394 LogFlowFuncLeaveRC(vrc);
395 return vrc;
396}
397
398/* static */
399Utf8Str GuestFile::i_guestErrorToString(int rcGuest)
400{
401 Utf8Str strError;
402
403 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
404 switch (rcGuest)
405 {
406 case VERR_ACCESS_DENIED:
407 strError += Utf8StrFmt(tr("Access denied"));
408 break;
409
410 case VERR_ALREADY_EXISTS:
411 strError += Utf8StrFmt(tr("File already exists"));
412 break;
413
414 case VERR_FILE_NOT_FOUND:
415 strError += Utf8StrFmt(tr("File not found"));
416 break;
417
418 case VERR_NET_HOST_NOT_FOUND:
419 strError += Utf8StrFmt(tr("Host name not found"));
420 break;
421
422 case VERR_SHARING_VIOLATION:
423 strError += Utf8StrFmt(tr("Sharing violation"));
424 break;
425
426 default:
427 strError += Utf8StrFmt("%Rrc", rcGuest);
428 break;
429 }
430
431 return strError;
432}
433
434int GuestFile::i_onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
435{
436 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
437 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
438
439 LogFlowThisFuncEnter();
440
441 if (pSvcCbData->mParms < 3)
442 return VERR_INVALID_PARAMETER;
443
444 int idx = 1; /* Current parameter index. */
445 CALLBACKDATA_FILE_NOTIFY dataCb;
446 /* pSvcCb->mpaParms[0] always contains the context ID. */
447 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.uType);
448 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.rc);
449
450 int rcGuest = (int)dataCb.rc; /* uint32_t vs. int. */
451
452 LogFlowThisFunc(("uType=%RU32, rcGuest=%Rrc\n", dataCb.uType, rcGuest));
453
454 if (RT_FAILURE(rcGuest))
455 {
456 int rc2 = i_setFileStatus(FileStatus_Error, rcGuest);
457 AssertRC(rc2);
458
459 /* Ignore rc, as the event to signal might not be there (anymore). */
460 signalWaitEventInternal(pCbCtx, rcGuest, NULL /* pPayload */);
461 return VINF_SUCCESS; /* Report to the guest. */
462 }
463
464 AssertMsg(mObjectID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID),
465 ("File ID %RU32 does not match object ID %RU32\n", mObjectID,
466 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));
467
468 int rc = VERR_NOT_SUPPORTED; /* Play safe by default. */
469
470 switch (dataCb.uType)
471 {
472 case GUEST_FILE_NOTIFYTYPE_ERROR:
473 {
474 rc = i_setFileStatus(FileStatus_Error, rcGuest);
475 break;
476 }
477
478 case GUEST_FILE_NOTIFYTYPE_OPEN:
479 {
480 if (pSvcCbData->mParms == 4)
481 {
482 rc = HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.u.open.uHandle);
483 if (RT_FAILURE(rc))
484 break;
485
486 /* Set the process status. */
487 rc = i_setFileStatus(FileStatus_Open, rcGuest);
488 }
489 break;
490 }
491
492 case GUEST_FILE_NOTIFYTYPE_CLOSE:
493 {
494 rc = i_setFileStatus(FileStatus_Closed, rcGuest);
495 break;
496 }
497
498 case GUEST_FILE_NOTIFYTYPE_READ:
499 {
500 if (pSvcCbData->mParms == 4)
501 {
502 rc = HGCMSvcGetPv(&pSvcCbData->mpaParms[idx++], &dataCb.u.read.pvData,
503 &dataCb.u.read.cbData);
504 if (RT_FAILURE(rc))
505 break;
506
507 const uint32_t cbRead = dataCb.u.read.cbData;
508
509 Log3ThisFunc(("cbRead=%RU32\n", cbRead));
510
511 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
512
513 mData.mOffCurrent += cbRead;
514
515 alock.release();
516
517 com::SafeArray<BYTE> data((size_t)cbRead);
518 data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead);
519
520 fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent,
521 cbRead, ComSafeArrayAsInParam(data));
522 }
523 break;
524 }
525
526 case GUEST_FILE_NOTIFYTYPE_WRITE:
527 {
528 if (pSvcCbData->mParms == 4)
529 {
530 rc = HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.u.write.cbWritten);
531 if (RT_FAILURE(rc))
532 break;
533
534 Log3ThisFunc(("cbWritten=%RU32\n", dataCb.u.write.cbWritten));
535
536 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
537
538 mData.mOffCurrent += dataCb.u.write.cbWritten;
539
540 alock.release();
541
542 fireGuestFileWriteEvent(mEventSource, mSession, this, mData.mOffCurrent,
543 dataCb.u.write.cbWritten);
544 }
545 break;
546 }
547
548 case GUEST_FILE_NOTIFYTYPE_SEEK:
549 {
550 if (pSvcCbData->mParms == 4)
551 {
552 rc = HGCMSvcGetU64(&pSvcCbData->mpaParms[idx++], &dataCb.u.seek.uOffActual);
553 if (RT_FAILURE(rc))
554 break;
555
556 Log3ThisFunc(("uOffActual=%RU64\n", dataCb.u.seek.uOffActual));
557
558 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
559
560 mData.mOffCurrent = dataCb.u.seek.uOffActual;
561
562 alock.release();
563
564 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, mData.mOffCurrent, 0 /* Processed */);
565 }
566 break;
567 }
568
569 case GUEST_FILE_NOTIFYTYPE_TELL:
570 {
571 if (pSvcCbData->mParms == 4)
572 {
573 rc = HGCMSvcGetU64(&pSvcCbData->mpaParms[idx++], &dataCb.u.tell.uOffActual);
574 if (RT_FAILURE(rc))
575 break;
576
577 Log3ThisFunc(("uOffActual=%RU64\n", dataCb.u.tell.uOffActual));
578
579 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
580
581 mData.mOffCurrent = dataCb.u.tell.uOffActual;
582
583 alock.release();
584
585 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, mData.mOffCurrent, 0 /* Processed */);
586 }
587 break;
588 }
589
590 default:
591 break;
592 }
593
594 if (RT_SUCCESS(rc))
595 {
596 GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb));
597
598 /* Ignore rc, as the event to signal might not be there (anymore). */
599 signalWaitEventInternal(pCbCtx, rcGuest, &payload);
600 }
601
602 LogFlowThisFunc(("uType=%RU32, rcGuest=%Rrc, rc=%Rrc\n", dataCb.uType, rcGuest, rc));
603 return rc;
604}
605
606int GuestFile::i_onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
607{
608 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
609 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
610
611 int vrc = i_setFileStatus(FileStatus_Down, VINF_SUCCESS);
612
613 LogFlowFuncLeaveRC(vrc);
614 return vrc;
615}
616
617/**
618 * Called by IGuestSession right before this file gets removed
619 * from the public file list.
620 */
621int GuestFile::i_onRemove(void)
622{
623 LogFlowThisFuncEnter();
624
625 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
626
627 int vrc = VINF_SUCCESS;
628
629 /*
630 * Note: The event source stuff holds references to this object,
631 * so make sure that this is cleaned up *before* calling uninit().
632 */
633 if (!mEventSource.isNull())
634 {
635 mEventSource->UnregisterListener(mLocalListener);
636
637 mLocalListener.setNull();
638 unconst(mEventSource).setNull();
639 }
640
641 LogFlowFuncLeaveRC(vrc);
642 return vrc;
643}
644
645int GuestFile::i_openFile(uint32_t uTimeoutMS, int *prcGuest)
646{
647 AssertReturn(mData.mOpenInfo.mFilename.isNotEmpty(), VERR_INVALID_PARAMETER);
648
649 LogFlowThisFuncEnter();
650
651 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
652
653 LogFlowThisFunc(("strFile=%s, enmAccessMode=0x%x, enmOpenAction=0x%x, uCreationMode=%RU32, mfOpenEx=%RU32\n",
654 mData.mOpenInfo.mFilename.c_str(), mData.mOpenInfo.mAccessMode, mData.mOpenInfo.mOpenAction,
655 mData.mOpenInfo.mCreationMode, mData.mOpenInfo.mfOpenEx));
656
657 /* Validate and translate open action. */
658 const char *pszOpenAction = NULL;
659 switch (mData.mOpenInfo.mOpenAction)
660 {
661 case FileOpenAction_OpenExisting: pszOpenAction = "oe"; break;
662 case FileOpenAction_OpenOrCreate: pszOpenAction = "oc"; break;
663 case FileOpenAction_CreateNew: pszOpenAction = "ce"; break;
664 case FileOpenAction_CreateOrReplace: pszOpenAction = "ca"; break;
665 case FileOpenAction_OpenExistingTruncated: pszOpenAction = "ot"; break;
666 case FileOpenAction_AppendOrCreate:
667 pszOpenAction = "oa"; /** @todo get rid of this one and implement AppendOnly/AppendRead. */
668 break;
669 default:
670 return VERR_INVALID_PARAMETER;
671 }
672
673 /* Validate and translate access mode. */
674 const char *pszAccessMode = NULL;
675 switch (mData.mOpenInfo.mAccessMode)
676 {
677 case FileAccessMode_ReadOnly: pszAccessMode = "r"; break;
678 case FileAccessMode_WriteOnly: pszAccessMode = "w"; break;
679 case FileAccessMode_ReadWrite: pszAccessMode = "r+"; break;
680 case FileAccessMode_AppendOnly: RT_FALL_THRU();
681 case FileAccessMode_AppendRead: return VERR_NOT_IMPLEMENTED;
682 default: return VERR_INVALID_PARAMETER;
683 }
684
685 /* Validate and translate sharing mode. */
686 const char *pszSharingMode = NULL;
687 switch (mData.mOpenInfo.mSharingMode)
688 {
689 case FileSharingMode_All: pszSharingMode = ""; break;
690 case FileSharingMode_Read: RT_FALL_THRU();
691 case FileSharingMode_Write: RT_FALL_THRU();
692 case FileSharingMode_ReadWrite: RT_FALL_THRU();
693 case FileSharingMode_Delete: RT_FALL_THRU();
694 case FileSharingMode_ReadDelete: RT_FALL_THRU();
695 case FileSharingMode_WriteDelete: return VERR_NOT_IMPLEMENTED;
696 default: return VERR_INVALID_PARAMETER;
697 }
698
699 int vrc;
700
701 GuestWaitEvent *pEvent = NULL;
702 GuestEventTypes eventTypes;
703 try
704 {
705 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
706
707 vrc = registerWaitEvent(eventTypes, &pEvent);
708 }
709 catch (std::bad_alloc &)
710 {
711 vrc = VERR_NO_MEMORY;
712 }
713
714 if (RT_FAILURE(vrc))
715 return vrc;
716
717 /* Prepare HGCM call. */
718 VBOXHGCMSVCPARM paParms[8];
719 int i = 0;
720 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
721 HGCMSvcSetPv(&paParms[i++], (void*)mData.mOpenInfo.mFilename.c_str(),
722 (ULONG)mData.mOpenInfo.mFilename.length() + 1);
723 HGCMSvcSetStr(&paParms[i++], pszAccessMode);
724 HGCMSvcSetStr(&paParms[i++], pszOpenAction);
725 HGCMSvcSetStr(&paParms[i++], pszSharingMode);
726 HGCMSvcSetU32(&paParms[i++], mData.mOpenInfo.mCreationMode);
727 HGCMSvcSetU64(&paParms[i++], mData.mOpenInfo.muOffset);
728 /** @todo Next protocol version: add flags, replace strings, remove initial offset. */
729
730 alock.release(); /* Drop write lock before sending. */
731
732 vrc = sendCommand(HOST_FILE_OPEN, i, paParms);
733 if (RT_SUCCESS(vrc))
734 vrc = i_waitForStatusChange(pEvent, uTimeoutMS, NULL /* FileStatus */, prcGuest);
735
736 unregisterWaitEvent(pEvent);
737
738 LogFlowFuncLeaveRC(vrc);
739 return vrc;
740}
741
742int GuestFile::i_queryInfo(GuestFsObjData &objData, int *prcGuest)
743{
744 AssertPtr(mSession);
745 return mSession->i_fsQueryInfo(mData.mOpenInfo.mFilename, FALSE /* fFollowSymlinks */, objData, prcGuest);
746}
747
748int GuestFile::i_readData(uint32_t uSize, uint32_t uTimeoutMS,
749 void* pvData, uint32_t cbData, uint32_t* pcbRead)
750{
751 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
752 AssertReturn(cbData, VERR_INVALID_PARAMETER);
753
754 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
755 uSize, uTimeoutMS, pvData, cbData));
756
757 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
758
759 int vrc;
760
761 GuestWaitEvent *pEvent = NULL;
762 GuestEventTypes eventTypes;
763 try
764 {
765 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
766 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
767
768 vrc = registerWaitEvent(eventTypes, &pEvent);
769 }
770 catch (std::bad_alloc &)
771 {
772 vrc = VERR_NO_MEMORY;
773 }
774
775 if (RT_FAILURE(vrc))
776 return vrc;
777
778 /* Prepare HGCM call. */
779 VBOXHGCMSVCPARM paParms[4];
780 int i = 0;
781 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
782 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
783 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
784
785 alock.release(); /* Drop write lock before sending. */
786
787 vrc = sendCommand(HOST_FILE_READ, i, paParms);
788 if (RT_SUCCESS(vrc))
789 {
790 uint32_t cbRead = 0;
791 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
792 if (RT_SUCCESS(vrc))
793 {
794 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
795 if (pcbRead)
796 *pcbRead = cbRead;
797 }
798 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
799 {
800 vrc = pEvent->GetGuestError();
801 }
802 }
803
804 unregisterWaitEvent(pEvent);
805
806 LogFlowFuncLeaveRC(vrc);
807 return vrc;
808}
809
810int GuestFile::i_readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
811 void* pvData, size_t cbData, size_t* pcbRead)
812{
813 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
814 uOffset, uSize, uTimeoutMS, pvData, cbData));
815
816 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
817
818 int vrc;
819
820 GuestWaitEvent *pEvent = NULL;
821 GuestEventTypes eventTypes;
822 try
823 {
824 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
825 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
826
827 vrc = registerWaitEvent(eventTypes, &pEvent);
828 }
829 catch (std::bad_alloc &)
830 {
831 vrc = VERR_NO_MEMORY;
832 }
833
834 if (RT_FAILURE(vrc))
835 return vrc;
836
837 /* Prepare HGCM call. */
838 VBOXHGCMSVCPARM paParms[4];
839 int i = 0;
840 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
841 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
842 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset (in bytes) to start reading */);
843 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
844
845 alock.release(); /* Drop write lock before sending. */
846
847 vrc = sendCommand(HOST_FILE_READ_AT, i, paParms);
848 if (RT_SUCCESS(vrc))
849 {
850 uint32_t cbRead = 0;
851 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
852 if (RT_SUCCESS(vrc))
853 {
854 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
855
856 if (pcbRead)
857 *pcbRead = cbRead;
858 }
859 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
860 {
861 vrc = pEvent->GetGuestError();
862 }
863 }
864
865 unregisterWaitEvent(pEvent);
866
867 LogFlowFuncLeaveRC(vrc);
868 return vrc;
869}
870
871int GuestFile::i_seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType,
872 uint32_t uTimeoutMS, uint64_t *puOffset)
873{
874 LogFlowThisFunc(("iOffset=%RI64, uTimeoutMS=%RU32\n",
875 iOffset, uTimeoutMS));
876
877 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
878
879 int vrc;
880
881 GuestWaitEvent *pEvent = NULL;
882 GuestEventTypes eventTypes;
883 try
884 {
885 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
886 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
887
888 vrc = registerWaitEvent(eventTypes, &pEvent);
889 }
890 catch (std::bad_alloc &)
891 {
892 vrc = VERR_NO_MEMORY;
893 }
894
895 if (RT_FAILURE(vrc))
896 return vrc;
897
898 /* Prepare HGCM call. */
899 VBOXHGCMSVCPARM paParms[4];
900 int i = 0;
901 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
902 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
903 HGCMSvcSetU32(&paParms[i++], eSeekType /* Seek method */);
904 /** @todo uint64_t vs. int64_t! */
905 HGCMSvcSetU64(&paParms[i++], (uint64_t)iOffset /* Offset (in bytes) to start reading */);
906
907 alock.release(); /* Drop write lock before sending. */
908
909 vrc = sendCommand(HOST_FILE_SEEK, i, paParms);
910 if (RT_SUCCESS(vrc))
911 {
912 uint64_t uOffset;
913 vrc = i_waitForOffsetChange(pEvent, uTimeoutMS, &uOffset);
914 if (RT_SUCCESS(vrc))
915 {
916 LogFlowThisFunc(("uOffset=%RU64\n", uOffset));
917
918 if (puOffset)
919 *puOffset = uOffset;
920 }
921 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
922 {
923 vrc = pEvent->GetGuestError();
924 }
925 }
926
927 unregisterWaitEvent(pEvent);
928
929 LogFlowFuncLeaveRC(vrc);
930 return vrc;
931}
932
933/* static */
934HRESULT GuestFile::i_setErrorExternal(VirtualBoxBase *pInterface, int rcGuest)
935{
936 AssertPtr(pInterface);
937 AssertMsg(RT_FAILURE(rcGuest), ("Guest rc does not indicate a failure when setting error\n"));
938
939 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestFile::i_guestErrorToString(rcGuest).c_str());
940}
941
942int GuestFile::i_setFileStatus(FileStatus_T fileStatus, int fileRc)
943{
944 LogFlowThisFuncEnter();
945
946 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
947
948 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, fileRc=%Rrc\n",
949 mData.mStatus, fileStatus, fileRc));
950
951#ifdef VBOX_STRICT
952 if (fileStatus == FileStatus_Error)
953 {
954 AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc));
955 }
956 else
957 AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc));
958#endif
959
960 if (mData.mStatus != fileStatus)
961 {
962 mData.mStatus = fileStatus;
963 mData.mLastError = fileRc;
964
965 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
966 HRESULT hr = errorInfo.createObject();
967 ComAssertComRC(hr);
968 if (RT_FAILURE(fileRc))
969 {
970 hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, fileRc,
971 COM_IIDOF(IGuestFile), getComponentName(),
972 i_guestErrorToString(fileRc));
973 ComAssertComRC(hr);
974 }
975
976 alock.release(); /* Release lock before firing off event. */
977
978 fireGuestFileStateChangedEvent(mEventSource, mSession,
979 this, fileStatus, errorInfo);
980 }
981
982 return VINF_SUCCESS;
983}
984
985int GuestFile::i_waitForOffsetChange(GuestWaitEvent *pEvent,
986 uint32_t uTimeoutMS, uint64_t *puOffset)
987{
988 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
989
990 VBoxEventType_T evtType;
991 ComPtr<IEvent> pIEvent;
992 int vrc = waitForEvent(pEvent, uTimeoutMS,
993 &evtType, pIEvent.asOutParam());
994 if (RT_SUCCESS(vrc))
995 {
996 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
997 {
998 if (puOffset)
999 {
1000 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
1001 Assert(!pFileEvent.isNull());
1002
1003 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
1004 ComAssertComRC(hr);
1005 }
1006 }
1007 else
1008 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1009 }
1010
1011 return vrc;
1012}
1013
1014int GuestFile::i_waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1015 void *pvData, size_t cbData, uint32_t *pcbRead)
1016{
1017 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1018
1019 VBoxEventType_T evtType;
1020 ComPtr<IEvent> pIEvent;
1021 int vrc = waitForEvent(pEvent, uTimeoutMS,
1022 &evtType, pIEvent.asOutParam());
1023 if (RT_SUCCESS(vrc))
1024 {
1025 if (evtType == VBoxEventType_OnGuestFileRead)
1026 {
1027 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
1028 Assert(!pFileEvent.isNull());
1029
1030 HRESULT hr;
1031 if (pvData)
1032 {
1033 com::SafeArray <BYTE> data;
1034 hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1035 ComAssertComRC(hr);
1036 const size_t cbRead = data.size();
1037 if (cbRead)
1038 {
1039 if (cbRead <= cbData)
1040 memcpy(pvData, data.raw(), cbRead);
1041 else
1042 vrc = VERR_BUFFER_OVERFLOW;
1043 }
1044 else
1045 vrc = VERR_NO_DATA;
1046 }
1047 if (pcbRead)
1048 {
1049 hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
1050 ComAssertComRC(hr);
1051 }
1052 }
1053 else
1054 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1055 }
1056
1057 return vrc;
1058}
1059
1060int GuestFile::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1061 FileStatus_T *pFileStatus, int *prcGuest)
1062{
1063 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1064 /* pFileStatus is optional. */
1065
1066 VBoxEventType_T evtType;
1067 ComPtr<IEvent> pIEvent;
1068 int vrc = waitForEvent(pEvent, uTimeoutMS,
1069 &evtType, pIEvent.asOutParam());
1070 if (RT_SUCCESS(vrc))
1071 {
1072 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
1073 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
1074 Assert(!pFileEvent.isNull());
1075
1076 HRESULT hr;
1077 if (pFileStatus)
1078 {
1079 hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1080 ComAssertComRC(hr);
1081 }
1082
1083 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1084 hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam());
1085 ComAssertComRC(hr);
1086
1087 LONG lGuestRc;
1088 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1089 ComAssertComRC(hr);
1090
1091 LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n",
1092 lGuestRc, lGuestRc));
1093
1094 if (RT_FAILURE((int)lGuestRc))
1095 vrc = VERR_GSTCTL_GUEST_ERROR;
1096
1097 if (prcGuest)
1098 *prcGuest = (int)lGuestRc;
1099 }
1100
1101 return vrc;
1102}
1103
1104int GuestFile::i_waitForWrite(GuestWaitEvent *pEvent,
1105 uint32_t uTimeoutMS, uint32_t *pcbWritten)
1106{
1107 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1108
1109 VBoxEventType_T evtType;
1110 ComPtr<IEvent> pIEvent;
1111 int vrc = waitForEvent(pEvent, uTimeoutMS,
1112 &evtType, pIEvent.asOutParam());
1113 if (RT_SUCCESS(vrc))
1114 {
1115 if (evtType == VBoxEventType_OnGuestFileWrite)
1116 {
1117 if (pcbWritten)
1118 {
1119 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1120 Assert(!pFileEvent.isNull());
1121
1122 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1123 ComAssertComRC(hr);
1124 }
1125 }
1126 else
1127 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1128 }
1129
1130 return vrc;
1131}
1132
1133int GuestFile::i_writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData,
1134 uint32_t *pcbWritten)
1135{
1136 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1137 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1138
1139 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1140 uTimeoutMS, pvData, cbData));
1141
1142 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1143
1144 int vrc;
1145
1146 GuestWaitEvent *pEvent = NULL;
1147 GuestEventTypes eventTypes;
1148 try
1149 {
1150 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1151 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1152
1153 vrc = registerWaitEvent(eventTypes, &pEvent);
1154 }
1155 catch (std::bad_alloc &)
1156 {
1157 vrc = VERR_NO_MEMORY;
1158 }
1159
1160 if (RT_FAILURE(vrc))
1161 return vrc;
1162
1163 /* Prepare HGCM call. */
1164 VBOXHGCMSVCPARM paParms[8];
1165 int i = 0;
1166 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1167 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1168 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
1169 HGCMSvcSetPv(&paParms[i++], pvData, cbData);
1170
1171 alock.release(); /* Drop write lock before sending. */
1172
1173 vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
1174 if (RT_SUCCESS(vrc))
1175 {
1176 uint32_t cbWritten = 0;
1177 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1178 if (RT_SUCCESS(vrc))
1179 {
1180 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1181 if (pcbWritten)
1182 *pcbWritten = cbWritten;
1183 }
1184 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1185 {
1186 vrc = pEvent->GetGuestError();
1187 }
1188 }
1189
1190 unregisterWaitEvent(pEvent);
1191
1192 LogFlowFuncLeaveRC(vrc);
1193 return vrc;
1194}
1195
1196int GuestFile::i_writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
1197 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1198{
1199 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1200 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1201
1202 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1203 uOffset, uTimeoutMS, pvData, cbData));
1204
1205 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1206
1207 int vrc;
1208
1209 GuestWaitEvent *pEvent = NULL;
1210 GuestEventTypes eventTypes;
1211 try
1212 {
1213 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1214 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1215
1216 vrc = registerWaitEvent(eventTypes, &pEvent);
1217 }
1218 catch (std::bad_alloc &)
1219 {
1220 vrc = VERR_NO_MEMORY;
1221 }
1222
1223 if (RT_FAILURE(vrc))
1224 return vrc;
1225
1226 /* Prepare HGCM call. */
1227 VBOXHGCMSVCPARM paParms[8];
1228 int i = 0;
1229 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1230 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1231 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset where to starting writing */);
1232 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
1233 HGCMSvcSetPv(&paParms[i++], pvData, cbData);
1234
1235 alock.release(); /* Drop write lock before sending. */
1236
1237 vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
1238 if (RT_SUCCESS(vrc))
1239 {
1240 uint32_t cbWritten = 0;
1241 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1242 if (RT_SUCCESS(vrc))
1243 {
1244 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1245 if (pcbWritten)
1246 *pcbWritten = cbWritten;
1247 }
1248 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1249 {
1250 vrc = pEvent->GetGuestError();
1251 }
1252 }
1253
1254 unregisterWaitEvent(pEvent);
1255
1256 LogFlowFuncLeaveRC(vrc);
1257 return vrc;
1258}
1259
1260// Wrapped IGuestFile methods
1261/////////////////////////////////////////////////////////////////////////////
1262HRESULT GuestFile::close()
1263{
1264 AutoCaller autoCaller(this);
1265 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1266
1267 LogFlowThisFuncEnter();
1268
1269 /* Close file on guest. */
1270 int rcGuest;
1271 int vrc = i_closeFile(&rcGuest);
1272 /* On failure don't return here, instead do all the cleanup
1273 * work first and then return an error. */
1274
1275 AssertPtr(mSession);
1276 int vrc2 = mSession->i_fileUnregister(this);
1277 if (RT_SUCCESS(vrc))
1278 vrc = vrc2;
1279
1280 if (RT_FAILURE(vrc))
1281 {
1282 if (vrc == VERR_GSTCTL_GUEST_ERROR)
1283 return GuestFile::i_setErrorExternal(this, rcGuest);
1284 return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Closing guest file failed with %Rrc\n"), vrc);
1285 }
1286
1287 LogFlowThisFunc(("Returning S_OK / vrc=%Rrc\n", vrc));
1288 return S_OK;
1289}
1290
1291HRESULT GuestFile::queryInfo(ComPtr<IFsObjInfo> &aObjInfo)
1292{
1293 AutoCaller autoCaller(this);
1294 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1295
1296 LogFlowThisFuncEnter();
1297
1298 HRESULT hr = S_OK;
1299
1300 GuestFsObjData fsObjData; int rcGuest;
1301 int vrc = i_queryInfo(fsObjData, &rcGuest);
1302 if (RT_SUCCESS(vrc))
1303 {
1304 ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
1305 hr = ptrFsObjInfo.createObject();
1306 if (SUCCEEDED(hr))
1307 {
1308 vrc = ptrFsObjInfo->init(fsObjData);
1309 if (RT_SUCCESS(vrc))
1310 hr = ptrFsObjInfo.queryInterfaceTo(aObjInfo.asOutParam());
1311 else
1312 hr = setErrorVrc(vrc);
1313 }
1314 }
1315 else
1316 {
1317 if (GuestProcess::i_isGuestError(vrc))
1318 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1319 else
1320 hr = setErrorVrc(vrc, tr("Querying file information failed: %Rrc"), vrc);
1321 }
1322
1323 LogFlowFuncLeaveRC(vrc);
1324 return hr;
1325}
1326
1327HRESULT GuestFile::querySize(LONG64 *aSize)
1328{
1329 AutoCaller autoCaller(this);
1330 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1331
1332 LogFlowThisFuncEnter();
1333
1334 HRESULT hr = S_OK;
1335
1336 GuestFsObjData fsObjData; int rcGuest;
1337 int vrc = i_queryInfo(fsObjData, &rcGuest);
1338 if (RT_SUCCESS(vrc))
1339 {
1340 *aSize = fsObjData.mObjectSize;
1341 }
1342 else
1343 {
1344 if (GuestProcess::i_isGuestError(vrc))
1345 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1346 else
1347 hr = setErrorVrc(vrc, tr("Querying file size failed: %Rrc"), vrc);
1348 }
1349
1350 LogFlowFuncLeaveRC(vrc);
1351 return hr;
1352}
1353
1354HRESULT GuestFile::read(ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1355{
1356 AutoCaller autoCaller(this);
1357 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1358
1359 if (aToRead == 0)
1360 return setError(E_INVALIDARG, tr("The size to read is zero"));
1361
1362 LogFlowThisFuncEnter();
1363
1364 aData.resize(aToRead);
1365
1366 HRESULT hr = S_OK;
1367
1368 uint32_t cbRead;
1369 int vrc = i_readData(aToRead, aTimeoutMS,
1370 &aData.front(), aToRead, &cbRead);
1371
1372 if (RT_SUCCESS(vrc))
1373 {
1374 if (aData.size() != cbRead)
1375 aData.resize(cbRead);
1376 }
1377 else
1378 {
1379 aData.resize(0);
1380
1381 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" failed: %Rrc"),
1382 mData.mOpenInfo.mFilename.c_str(), vrc);
1383 }
1384
1385 LogFlowFuncLeaveRC(vrc);
1386 return hr;
1387}
1388
1389HRESULT GuestFile::readAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1390{
1391 AutoCaller autoCaller(this);
1392 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1393
1394 if (aToRead == 0)
1395 return setError(E_INVALIDARG, tr("The size to read is zero"));
1396
1397 LogFlowThisFuncEnter();
1398
1399 aData.resize(aToRead);
1400
1401 HRESULT hr = S_OK;
1402
1403 size_t cbRead;
1404 int vrc = i_readDataAt(aOffset, aToRead, aTimeoutMS,
1405 &aData.front(), aToRead, &cbRead);
1406 if (RT_SUCCESS(vrc))
1407 {
1408 if (aData.size() != cbRead)
1409 aData.resize(cbRead);
1410 }
1411 else
1412 {
1413 aData.resize(0);
1414
1415 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1416 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1417 }
1418
1419 LogFlowFuncLeaveRC(vrc);
1420 return hr;
1421}
1422
1423HRESULT GuestFile::seek(LONG64 aOffset, FileSeekOrigin_T aWhence, LONG64 *aNewOffset)
1424{
1425 AutoCaller autoCaller(this);
1426 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1427
1428 HRESULT hr = S_OK;
1429
1430 GUEST_FILE_SEEKTYPE eSeekType;
1431 switch (aWhence)
1432 {
1433 case FileSeekOrigin_Begin:
1434 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1435 break;
1436
1437 case FileSeekOrigin_Current:
1438 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1439 break;
1440
1441 case FileSeekOrigin_End:
1442 eSeekType = GUEST_FILE_SEEKTYPE_END;
1443 break;
1444
1445 default:
1446 return setError(E_INVALIDARG, tr("Invalid seek type specified"));
1447 }
1448
1449 LogFlowThisFuncEnter();
1450
1451 uint64_t uNewOffset;
1452 int vrc = i_seekAt(aOffset, eSeekType,
1453 30 * 1000 /* 30s timeout */, &uNewOffset);
1454 if (RT_SUCCESS(vrc))
1455 *aNewOffset = RT_MIN(uNewOffset, (uint64_t)INT64_MAX);
1456 else
1457 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"),
1458 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1459
1460 LogFlowFuncLeaveRC(vrc);
1461 return hr;
1462}
1463
1464HRESULT GuestFile::setACL(const com::Utf8Str &aAcl, ULONG aMode)
1465{
1466 RT_NOREF(aAcl, aMode);
1467 ReturnComNotImplemented();
1468}
1469
1470HRESULT GuestFile::setSize(LONG64 aSize)
1471{
1472 RT_NOREF(aSize);
1473 ReturnComNotImplemented();
1474}
1475
1476HRESULT GuestFile::write(const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1477{
1478 AutoCaller autoCaller(this);
1479 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1480
1481 LogFlowThisFuncEnter();
1482
1483 HRESULT hr = S_OK;
1484
1485 uint32_t cbData = (uint32_t)aData.size();
1486 void *pvData = cbData > 0? (void *)&aData.front(): NULL;
1487 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1488 if (RT_FAILURE(vrc))
1489 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
1490 aData.size(), mData.mOpenInfo.mFilename.c_str(), vrc);
1491
1492 LogFlowFuncLeaveRC(vrc);
1493 return hr;
1494}
1495
1496HRESULT GuestFile::writeAt(LONG64 aOffset, const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1497{
1498 AutoCaller autoCaller(this);
1499 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1500
1501 LogFlowThisFuncEnter();
1502
1503 HRESULT hr = S_OK;
1504
1505 uint32_t cbData = (uint32_t)aData.size();
1506 void *pvData = cbData > 0? (void *)&aData.front(): NULL;
1507 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1508 if (RT_FAILURE(vrc))
1509 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
1510 aData.size(), mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1511
1512 LogFlowFuncLeaveRC(vrc);
1513 return hr;
1514}
1515
Note: See TracBrowser for help on using the repository browser.

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