VirtualBox

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

Last change on this file since 77369 was 77112, checked in by vboxsync, 6 years ago

Guest Control/Main: Clarify GuestFile::getOffset().

  • 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 77112 2019-02-01 11:23:33Z 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 RT_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 /* mData.mOffCurrent gets updated on i_readData[At]() / i_writeData[At]() file notification callbacks.
298 * So no need to take another roundtrip into the guest asking for the current offset (using tell). */
299 *aOffset = mData.mOffCurrent;
300
301 return S_OK;
302}
303
304HRESULT GuestFile::getAccessMode(FileAccessMode_T *aAccessMode)
305{
306 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
307
308 *aAccessMode = mData.mOpenInfo.mAccessMode;
309
310 return S_OK;
311}
312
313HRESULT GuestFile::getStatus(FileStatus_T *aStatus)
314{
315 LogFlowThisFuncEnter();
316
317 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
318
319 *aStatus = mData.mStatus;
320
321 return S_OK;
322}
323
324// private methods
325/////////////////////////////////////////////////////////////////////////////
326
327int GuestFile::i_callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
328{
329 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
330 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
331
332 LogFlowThisFunc(("strName=%s, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
333 mData.mOpenInfo.mFilename.c_str(), pCbCtx->uContextID, pCbCtx->uMessage, pSvcCb));
334
335 int vrc;
336 switch (pCbCtx->uMessage)
337 {
338 case GUEST_MSG_DISCONNECTED:
339 vrc = i_onGuestDisconnected(pCbCtx, pSvcCb);
340 break;
341
342 case GUEST_MSG_FILE_NOTIFY:
343 vrc = i_onFileNotify(pCbCtx, pSvcCb);
344 break;
345
346 default:
347 /* Silently ignore not implemented functions. */
348 vrc = VERR_NOT_SUPPORTED;
349 break;
350 }
351
352#ifdef DEBUG
353 LogFlowFuncLeaveRC(vrc);
354#endif
355 return vrc;
356}
357
358int GuestFile::i_closeFile(int *prcGuest)
359{
360 LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFilename.c_str()));
361
362 int vrc;
363
364 GuestWaitEvent *pEvent = NULL;
365 GuestEventTypes eventTypes;
366 try
367 {
368 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
369
370 vrc = registerWaitEvent(eventTypes, &pEvent);
371 }
372 catch (std::bad_alloc &)
373 {
374 vrc = VERR_NO_MEMORY;
375 }
376
377 if (RT_FAILURE(vrc))
378 return vrc;
379
380 /* Prepare HGCM call. */
381 VBOXHGCMSVCPARM paParms[4];
382 int i = 0;
383 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
384 HGCMSvcSetU32(&paParms[i++], mObjectID /* Guest file ID */);
385
386 vrc = sendMessage(HOST_MSG_FILE_CLOSE, i, paParms);
387 if (RT_SUCCESS(vrc))
388 vrc = i_waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */,
389 NULL /* FileStatus */, prcGuest);
390 unregisterWaitEvent(pEvent);
391
392 LogFlowFuncLeaveRC(vrc);
393 return vrc;
394}
395
396/* static */
397Utf8Str GuestFile::i_guestErrorToString(int rcGuest)
398{
399 Utf8Str strError;
400
401 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
402 switch (rcGuest)
403 {
404 case VERR_ACCESS_DENIED:
405 strError += Utf8StrFmt(tr("Access denied"));
406 break;
407
408 case VERR_ALREADY_EXISTS:
409 strError += Utf8StrFmt(tr("File already exists"));
410 break;
411
412 case VERR_FILE_NOT_FOUND:
413 strError += Utf8StrFmt(tr("File not found"));
414 break;
415
416 case VERR_NET_HOST_NOT_FOUND:
417 strError += Utf8StrFmt(tr("Host name not found"));
418 break;
419
420 case VERR_SHARING_VIOLATION:
421 strError += Utf8StrFmt(tr("Sharing violation"));
422 break;
423
424 default:
425 strError += Utf8StrFmt("%Rrc", rcGuest);
426 break;
427 }
428
429 return strError;
430}
431
432int GuestFile::i_onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
433{
434 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
435 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
436
437 LogFlowThisFuncEnter();
438
439 if (pSvcCbData->mParms < 3)
440 return VERR_INVALID_PARAMETER;
441
442 int idx = 1; /* Current parameter index. */
443 CALLBACKDATA_FILE_NOTIFY dataCb;
444 /* pSvcCb->mpaParms[0] always contains the context ID. */
445 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.uType);
446 HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.rc);
447
448 int rcGuest = (int)dataCb.rc; /* uint32_t vs. int. */
449
450 LogFlowThisFunc(("uType=%RU32, rcGuest=%Rrc\n", dataCb.uType, rcGuest));
451
452 if (RT_FAILURE(rcGuest))
453 {
454 int rc2 = i_setFileStatus(FileStatus_Error, rcGuest);
455 AssertRC(rc2);
456
457 /* Ignore rc, as the event to signal might not be there (anymore). */
458 signalWaitEventInternal(pCbCtx, rcGuest, NULL /* pPayload */);
459 return VINF_SUCCESS; /* Report to the guest. */
460 }
461
462 AssertMsg(mObjectID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID),
463 ("File ID %RU32 does not match object ID %RU32\n", mObjectID,
464 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));
465
466 int rc = VERR_NOT_SUPPORTED; /* Play safe by default. */
467
468 switch (dataCb.uType)
469 {
470 case GUEST_FILE_NOTIFYTYPE_ERROR:
471 {
472 rc = i_setFileStatus(FileStatus_Error, rcGuest);
473 break;
474 }
475
476 case GUEST_FILE_NOTIFYTYPE_OPEN:
477 {
478 if (pSvcCbData->mParms == 4)
479 {
480 rc = HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.u.open.uHandle);
481 if (RT_FAILURE(rc))
482 break;
483
484 /* Set the process status. */
485 rc = i_setFileStatus(FileStatus_Open, rcGuest);
486 }
487 break;
488 }
489
490 case GUEST_FILE_NOTIFYTYPE_CLOSE:
491 {
492 rc = i_setFileStatus(FileStatus_Closed, rcGuest);
493 break;
494 }
495
496 case GUEST_FILE_NOTIFYTYPE_READ:
497 {
498 if (pSvcCbData->mParms == 4)
499 {
500 rc = HGCMSvcGetPv(&pSvcCbData->mpaParms[idx++], &dataCb.u.read.pvData,
501 &dataCb.u.read.cbData);
502 if (RT_FAILURE(rc))
503 break;
504
505 const uint32_t cbRead = dataCb.u.read.cbData;
506
507 Log3ThisFunc(("cbRead=%RU32\n", cbRead));
508
509 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
510
511 mData.mOffCurrent += cbRead;
512
513 alock.release();
514
515 com::SafeArray<BYTE> data((size_t)cbRead);
516 data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead);
517
518 fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent,
519 cbRead, ComSafeArrayAsInParam(data));
520 }
521 break;
522 }
523
524 case GUEST_FILE_NOTIFYTYPE_WRITE:
525 {
526 if (pSvcCbData->mParms == 4)
527 {
528 rc = HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.u.write.cbWritten);
529 if (RT_FAILURE(rc))
530 break;
531
532 const uint32_t cbWritten = dataCb.u.write.cbWritten;
533
534 Log3ThisFunc(("cbWritten=%RU32\n", cbWritten));
535
536 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
537
538 mData.mOffCurrent += cbWritten;
539
540 alock.release();
541
542 fireGuestFileWriteEvent(mEventSource, mSession, this, mData.mOffCurrent, cbWritten);
543 }
544 break;
545 }
546
547 case GUEST_FILE_NOTIFYTYPE_SEEK:
548 {
549 if (pSvcCbData->mParms == 4)
550 {
551 rc = HGCMSvcGetU64(&pSvcCbData->mpaParms[idx++], &dataCb.u.seek.uOffActual);
552 if (RT_FAILURE(rc))
553 break;
554
555 Log3ThisFunc(("uOffActual=%RU64\n", dataCb.u.seek.uOffActual));
556
557 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
558
559 mData.mOffCurrent = dataCb.u.seek.uOffActual;
560
561 alock.release();
562
563 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, mData.mOffCurrent, 0 /* Processed */);
564 }
565 break;
566 }
567
568 case GUEST_FILE_NOTIFYTYPE_TELL:
569 {
570 if (pSvcCbData->mParms == 4)
571 {
572 rc = HGCMSvcGetU64(&pSvcCbData->mpaParms[idx++], &dataCb.u.tell.uOffActual);
573 if (RT_FAILURE(rc))
574 break;
575
576 Log3ThisFunc(("uOffActual=%RU64\n", dataCb.u.tell.uOffActual));
577
578 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
579
580 mData.mOffCurrent = dataCb.u.tell.uOffActual;
581
582 alock.release();
583
584 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, mData.mOffCurrent, 0 /* Processed */);
585 }
586 break;
587 }
588
589 default:
590 break;
591 }
592
593 if (RT_SUCCESS(rc))
594 {
595 GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb));
596
597 /* Ignore rc, as the event to signal might not be there (anymore). */
598 signalWaitEventInternal(pCbCtx, rcGuest, &payload);
599 }
600
601 LogFlowThisFunc(("uType=%RU32, rcGuest=%Rrc, rc=%Rrc\n", dataCb.uType, rcGuest, rc));
602 return rc;
603}
604
605int GuestFile::i_onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
606{
607 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
608 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
609
610 int vrc = i_setFileStatus(FileStatus_Down, VINF_SUCCESS);
611
612 LogFlowFuncLeaveRC(vrc);
613 return vrc;
614}
615
616/**
617 * Called by IGuestSession right before this file gets removed
618 * from the public file list.
619 */
620int GuestFile::i_onRemove(void)
621{
622 LogFlowThisFuncEnter();
623
624 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
625
626 int vrc = VINF_SUCCESS;
627
628 /*
629 * Note: The event source stuff holds references to this object,
630 * so make sure that this is cleaned up *before* calling uninit().
631 */
632 if (!mEventSource.isNull())
633 {
634 mEventSource->UnregisterListener(mLocalListener);
635
636 mLocalListener.setNull();
637 unconst(mEventSource).setNull();
638 }
639
640 LogFlowFuncLeaveRC(vrc);
641 return vrc;
642}
643
644int GuestFile::i_openFile(uint32_t uTimeoutMS, int *prcGuest)
645{
646 AssertReturn(mData.mOpenInfo.mFilename.isNotEmpty(), VERR_INVALID_PARAMETER);
647
648 LogFlowThisFuncEnter();
649
650 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
651
652 LogFlowThisFunc(("strFile=%s, enmAccessMode=0x%x, enmOpenAction=0x%x, uCreationMode=%RU32, mfOpenEx=%RU32\n",
653 mData.mOpenInfo.mFilename.c_str(), mData.mOpenInfo.mAccessMode, mData.mOpenInfo.mOpenAction,
654 mData.mOpenInfo.mCreationMode, mData.mOpenInfo.mfOpenEx));
655
656 /* Validate and translate open action. */
657 const char *pszOpenAction = NULL;
658 switch (mData.mOpenInfo.mOpenAction)
659 {
660 case FileOpenAction_OpenExisting: pszOpenAction = "oe"; break;
661 case FileOpenAction_OpenOrCreate: pszOpenAction = "oc"; break;
662 case FileOpenAction_CreateNew: pszOpenAction = "ce"; break;
663 case FileOpenAction_CreateOrReplace: pszOpenAction = "ca"; break;
664 case FileOpenAction_OpenExistingTruncated: pszOpenAction = "ot"; break;
665 case FileOpenAction_AppendOrCreate:
666 pszOpenAction = "oa"; /** @todo get rid of this one and implement AppendOnly/AppendRead. */
667 break;
668 default:
669 return VERR_INVALID_PARAMETER;
670 }
671
672 /* Validate and translate access mode. */
673 const char *pszAccessMode = NULL;
674 switch (mData.mOpenInfo.mAccessMode)
675 {
676 case FileAccessMode_ReadOnly: pszAccessMode = "r"; break;
677 case FileAccessMode_WriteOnly: pszAccessMode = "w"; break;
678 case FileAccessMode_ReadWrite: pszAccessMode = "r+"; break;
679 case FileAccessMode_AppendOnly: RT_FALL_THRU();
680 case FileAccessMode_AppendRead: return VERR_NOT_IMPLEMENTED;
681 default: return VERR_INVALID_PARAMETER;
682 }
683
684 /* Validate and translate sharing mode. */
685 const char *pszSharingMode = NULL;
686 switch (mData.mOpenInfo.mSharingMode)
687 {
688 case FileSharingMode_All: pszSharingMode = ""; break;
689 case FileSharingMode_Read: RT_FALL_THRU();
690 case FileSharingMode_Write: RT_FALL_THRU();
691 case FileSharingMode_ReadWrite: RT_FALL_THRU();
692 case FileSharingMode_Delete: RT_FALL_THRU();
693 case FileSharingMode_ReadDelete: RT_FALL_THRU();
694 case FileSharingMode_WriteDelete: return VERR_NOT_IMPLEMENTED;
695 default: return VERR_INVALID_PARAMETER;
696 }
697
698 int vrc;
699
700 GuestWaitEvent *pEvent = NULL;
701 GuestEventTypes eventTypes;
702 try
703 {
704 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
705
706 vrc = registerWaitEvent(eventTypes, &pEvent);
707 }
708 catch (std::bad_alloc &)
709 {
710 vrc = VERR_NO_MEMORY;
711 }
712
713 if (RT_FAILURE(vrc))
714 return vrc;
715
716 /* Prepare HGCM call. */
717 VBOXHGCMSVCPARM paParms[8];
718 int i = 0;
719 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
720 HGCMSvcSetPv(&paParms[i++], (void*)mData.mOpenInfo.mFilename.c_str(),
721 (ULONG)mData.mOpenInfo.mFilename.length() + 1);
722 HGCMSvcSetStr(&paParms[i++], pszAccessMode);
723 HGCMSvcSetStr(&paParms[i++], pszOpenAction);
724 HGCMSvcSetStr(&paParms[i++], pszSharingMode);
725 HGCMSvcSetU32(&paParms[i++], mData.mOpenInfo.mCreationMode);
726 HGCMSvcSetU64(&paParms[i++], mData.mOpenInfo.muOffset);
727 /** @todo Next protocol version: add flags, replace strings, remove initial offset. */
728
729 alock.release(); /* Drop write lock before sending. */
730
731 vrc = sendMessage(HOST_MSG_FILE_OPEN, i, paParms);
732 if (RT_SUCCESS(vrc))
733 vrc = i_waitForStatusChange(pEvent, uTimeoutMS, NULL /* FileStatus */, prcGuest);
734
735 unregisterWaitEvent(pEvent);
736
737 LogFlowFuncLeaveRC(vrc);
738 return vrc;
739}
740
741int GuestFile::i_queryInfo(GuestFsObjData &objData, int *prcGuest)
742{
743 AssertPtr(mSession);
744 return mSession->i_fsQueryInfo(mData.mOpenInfo.mFilename, FALSE /* fFollowSymlinks */, objData, prcGuest);
745}
746
747int GuestFile::i_readData(uint32_t uSize, uint32_t uTimeoutMS,
748 void* pvData, uint32_t cbData, uint32_t* pcbRead)
749{
750 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
751 AssertReturn(cbData, VERR_INVALID_PARAMETER);
752
753 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
754 uSize, uTimeoutMS, pvData, cbData));
755
756 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
757
758 int vrc;
759
760 GuestWaitEvent *pEvent = NULL;
761 GuestEventTypes eventTypes;
762 try
763 {
764 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
765 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
766
767 vrc = registerWaitEvent(eventTypes, &pEvent);
768 }
769 catch (std::bad_alloc &)
770 {
771 vrc = VERR_NO_MEMORY;
772 }
773
774 if (RT_FAILURE(vrc))
775 return vrc;
776
777 /* Prepare HGCM call. */
778 VBOXHGCMSVCPARM paParms[4];
779 int i = 0;
780 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
781 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
782 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
783
784 alock.release(); /* Drop write lock before sending. */
785
786 vrc = sendMessage(HOST_MSG_FILE_READ, i, paParms);
787 if (RT_SUCCESS(vrc))
788 {
789 uint32_t cbRead = 0;
790 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
791 if (RT_SUCCESS(vrc))
792 {
793 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
794 if (pcbRead)
795 *pcbRead = cbRead;
796 }
797 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
798 {
799 vrc = pEvent->GetGuestError();
800 }
801 }
802
803 unregisterWaitEvent(pEvent);
804
805 LogFlowFuncLeaveRC(vrc);
806 return vrc;
807}
808
809int GuestFile::i_readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
810 void* pvData, size_t cbData, size_t* pcbRead)
811{
812 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
813 uOffset, uSize, uTimeoutMS, pvData, cbData));
814
815 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
816
817 int vrc;
818
819 GuestWaitEvent *pEvent = NULL;
820 GuestEventTypes eventTypes;
821 try
822 {
823 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
824 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
825
826 vrc = registerWaitEvent(eventTypes, &pEvent);
827 }
828 catch (std::bad_alloc &)
829 {
830 vrc = VERR_NO_MEMORY;
831 }
832
833 if (RT_FAILURE(vrc))
834 return vrc;
835
836 /* Prepare HGCM call. */
837 VBOXHGCMSVCPARM paParms[4];
838 int i = 0;
839 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
840 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
841 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset (in bytes) to start reading */);
842 HGCMSvcSetU32(&paParms[i++], uSize /* Size (in bytes) to read */);
843
844 alock.release(); /* Drop write lock before sending. */
845
846 vrc = sendMessage(HOST_MSG_FILE_READ_AT, i, paParms);
847 if (RT_SUCCESS(vrc))
848 {
849 uint32_t cbRead = 0;
850 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
851 if (RT_SUCCESS(vrc))
852 {
853 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
854
855 if (pcbRead)
856 *pcbRead = cbRead;
857 }
858 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
859 {
860 vrc = pEvent->GetGuestError();
861 }
862 }
863
864 unregisterWaitEvent(pEvent);
865
866 LogFlowFuncLeaveRC(vrc);
867 return vrc;
868}
869
870int GuestFile::i_seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType,
871 uint32_t uTimeoutMS, uint64_t *puOffset)
872{
873 LogFlowThisFunc(("iOffset=%RI64, uTimeoutMS=%RU32\n",
874 iOffset, uTimeoutMS));
875
876 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
877
878 int vrc;
879
880 GuestWaitEvent *pEvent = NULL;
881 GuestEventTypes eventTypes;
882 try
883 {
884 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
885 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
886
887 vrc = registerWaitEvent(eventTypes, &pEvent);
888 }
889 catch (std::bad_alloc &)
890 {
891 vrc = VERR_NO_MEMORY;
892 }
893
894 if (RT_FAILURE(vrc))
895 return vrc;
896
897 /* Prepare HGCM call. */
898 VBOXHGCMSVCPARM paParms[4];
899 int i = 0;
900 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
901 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
902 HGCMSvcSetU32(&paParms[i++], eSeekType /* Seek method */);
903 /** @todo uint64_t vs. int64_t! */
904 HGCMSvcSetU64(&paParms[i++], (uint64_t)iOffset /* Offset (in bytes) to start reading */);
905
906 alock.release(); /* Drop write lock before sending. */
907
908 vrc = sendMessage(HOST_MSG_FILE_SEEK, i, paParms);
909 if (RT_SUCCESS(vrc))
910 {
911 uint64_t uOffset;
912 vrc = i_waitForOffsetChange(pEvent, uTimeoutMS, &uOffset);
913 if (RT_SUCCESS(vrc))
914 {
915 LogFlowThisFunc(("uOffset=%RU64\n", uOffset));
916
917 if (puOffset)
918 *puOffset = uOffset;
919 }
920 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
921 {
922 vrc = pEvent->GetGuestError();
923 }
924 }
925
926 unregisterWaitEvent(pEvent);
927
928 LogFlowFuncLeaveRC(vrc);
929 return vrc;
930}
931
932/* static */
933HRESULT GuestFile::i_setErrorExternal(VirtualBoxBase *pInterface, int rcGuest)
934{
935 AssertPtr(pInterface);
936 AssertMsg(RT_FAILURE(rcGuest), ("Guest rc does not indicate a failure when setting error\n"));
937
938 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestFile::i_guestErrorToString(rcGuest).c_str());
939}
940
941int GuestFile::i_setFileStatus(FileStatus_T fileStatus, int fileRc)
942{
943 LogFlowThisFuncEnter();
944
945 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
946
947 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, fileRc=%Rrc\n",
948 mData.mStatus, fileStatus, fileRc));
949
950#ifdef VBOX_STRICT
951 if (fileStatus == FileStatus_Error)
952 {
953 AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc));
954 }
955 else
956 AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc));
957#endif
958
959 if (mData.mStatus != fileStatus)
960 {
961 mData.mStatus = fileStatus;
962 mData.mLastError = fileRc;
963
964 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
965 HRESULT hr = errorInfo.createObject();
966 ComAssertComRC(hr);
967 if (RT_FAILURE(fileRc))
968 {
969 hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, fileRc,
970 COM_IIDOF(IGuestFile), getComponentName(),
971 i_guestErrorToString(fileRc));
972 ComAssertComRC(hr);
973 }
974
975 alock.release(); /* Release lock before firing off event. */
976
977 fireGuestFileStateChangedEvent(mEventSource, mSession,
978 this, fileStatus, errorInfo);
979 }
980
981 return VINF_SUCCESS;
982}
983
984int GuestFile::i_waitForOffsetChange(GuestWaitEvent *pEvent,
985 uint32_t uTimeoutMS, uint64_t *puOffset)
986{
987 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
988
989 VBoxEventType_T evtType;
990 ComPtr<IEvent> pIEvent;
991 int vrc = waitForEvent(pEvent, uTimeoutMS,
992 &evtType, pIEvent.asOutParam());
993 if (RT_SUCCESS(vrc))
994 {
995 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
996 {
997 if (puOffset)
998 {
999 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
1000 Assert(!pFileEvent.isNull());
1001
1002 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
1003 ComAssertComRC(hr);
1004 }
1005 }
1006 else
1007 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1008 }
1009
1010 return vrc;
1011}
1012
1013int GuestFile::i_waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1014 void *pvData, size_t cbData, uint32_t *pcbRead)
1015{
1016 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1017
1018 VBoxEventType_T evtType;
1019 ComPtr<IEvent> pIEvent;
1020 int vrc = waitForEvent(pEvent, uTimeoutMS,
1021 &evtType, pIEvent.asOutParam());
1022 if (RT_SUCCESS(vrc))
1023 {
1024 if (evtType == VBoxEventType_OnGuestFileRead)
1025 {
1026 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
1027 Assert(!pFileEvent.isNull());
1028
1029 HRESULT hr;
1030 if (pvData)
1031 {
1032 com::SafeArray <BYTE> data;
1033 hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1034 ComAssertComRC(hr);
1035 const size_t cbRead = data.size();
1036 if (cbRead)
1037 {
1038 if (cbRead <= cbData)
1039 memcpy(pvData, data.raw(), cbRead);
1040 else
1041 vrc = VERR_BUFFER_OVERFLOW;
1042 }
1043 else
1044 vrc = VERR_NO_DATA;
1045 }
1046 if (pcbRead)
1047 {
1048 hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
1049 ComAssertComRC(hr);
1050 }
1051 }
1052 else
1053 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1054 }
1055
1056 return vrc;
1057}
1058
1059int GuestFile::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1060 FileStatus_T *pFileStatus, int *prcGuest)
1061{
1062 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1063 /* pFileStatus is optional. */
1064
1065 VBoxEventType_T evtType;
1066 ComPtr<IEvent> pIEvent;
1067 int vrc = waitForEvent(pEvent, uTimeoutMS,
1068 &evtType, pIEvent.asOutParam());
1069 if (RT_SUCCESS(vrc))
1070 {
1071 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
1072 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
1073 Assert(!pFileEvent.isNull());
1074
1075 HRESULT hr;
1076 if (pFileStatus)
1077 {
1078 hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1079 ComAssertComRC(hr);
1080 }
1081
1082 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1083 hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam());
1084 ComAssertComRC(hr);
1085
1086 LONG lGuestRc;
1087 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1088 ComAssertComRC(hr);
1089
1090 LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n",
1091 lGuestRc, lGuestRc));
1092
1093 if (RT_FAILURE((int)lGuestRc))
1094 vrc = VERR_GSTCTL_GUEST_ERROR;
1095
1096 if (prcGuest)
1097 *prcGuest = (int)lGuestRc;
1098 }
1099
1100 return vrc;
1101}
1102
1103int GuestFile::i_waitForWrite(GuestWaitEvent *pEvent,
1104 uint32_t uTimeoutMS, uint32_t *pcbWritten)
1105{
1106 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1107
1108 VBoxEventType_T evtType;
1109 ComPtr<IEvent> pIEvent;
1110 int vrc = waitForEvent(pEvent, uTimeoutMS,
1111 &evtType, pIEvent.asOutParam());
1112 if (RT_SUCCESS(vrc))
1113 {
1114 if (evtType == VBoxEventType_OnGuestFileWrite)
1115 {
1116 if (pcbWritten)
1117 {
1118 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1119 Assert(!pFileEvent.isNull());
1120
1121 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1122 ComAssertComRC(hr);
1123 }
1124 }
1125 else
1126 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1127 }
1128
1129 return vrc;
1130}
1131
1132int GuestFile::i_writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData,
1133 uint32_t *pcbWritten)
1134{
1135 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1136 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1137
1138 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1139 uTimeoutMS, pvData, cbData));
1140
1141 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1142
1143 int vrc;
1144
1145 GuestWaitEvent *pEvent = NULL;
1146 GuestEventTypes eventTypes;
1147 try
1148 {
1149 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1150 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1151
1152 vrc = registerWaitEvent(eventTypes, &pEvent);
1153 }
1154 catch (std::bad_alloc &)
1155 {
1156 vrc = VERR_NO_MEMORY;
1157 }
1158
1159 if (RT_FAILURE(vrc))
1160 return vrc;
1161
1162 /* Prepare HGCM call. */
1163 VBOXHGCMSVCPARM paParms[8];
1164 int i = 0;
1165 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1166 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1167 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
1168 HGCMSvcSetPv(&paParms[i++], pvData, cbData);
1169
1170 alock.release(); /* Drop write lock before sending. */
1171
1172 vrc = sendMessage(HOST_MSG_FILE_WRITE, i, paParms);
1173 if (RT_SUCCESS(vrc))
1174 {
1175 uint32_t cbWritten = 0;
1176 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1177 if (RT_SUCCESS(vrc))
1178 {
1179 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1180 if (pcbWritten)
1181 *pcbWritten = cbWritten;
1182 }
1183 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1184 {
1185 vrc = pEvent->GetGuestError();
1186 }
1187 }
1188
1189 unregisterWaitEvent(pEvent);
1190
1191 LogFlowFuncLeaveRC(vrc);
1192 return vrc;
1193}
1194
1195int GuestFile::i_writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
1196 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1197{
1198 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1199 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1200
1201 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1202 uOffset, uTimeoutMS, pvData, cbData));
1203
1204 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1205
1206 int vrc;
1207
1208 GuestWaitEvent *pEvent = NULL;
1209 GuestEventTypes eventTypes;
1210 try
1211 {
1212 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1213 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1214
1215 vrc = registerWaitEvent(eventTypes, &pEvent);
1216 }
1217 catch (std::bad_alloc &)
1218 {
1219 vrc = VERR_NO_MEMORY;
1220 }
1221
1222 if (RT_FAILURE(vrc))
1223 return vrc;
1224
1225 /* Prepare HGCM call. */
1226 VBOXHGCMSVCPARM paParms[8];
1227 int i = 0;
1228 HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
1229 HGCMSvcSetU32(&paParms[i++], mObjectID /* File handle */);
1230 HGCMSvcSetU64(&paParms[i++], uOffset /* Offset where to starting writing */);
1231 HGCMSvcSetU32(&paParms[i++], cbData /* Size (in bytes) to write */);
1232 HGCMSvcSetPv(&paParms[i++], pvData, cbData);
1233
1234 alock.release(); /* Drop write lock before sending. */
1235
1236 vrc = sendMessage(HOST_MSG_FILE_WRITE_AT, i, paParms);
1237 if (RT_SUCCESS(vrc))
1238 {
1239 uint32_t cbWritten = 0;
1240 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1241 if (RT_SUCCESS(vrc))
1242 {
1243 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1244 if (pcbWritten)
1245 *pcbWritten = cbWritten;
1246 }
1247 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1248 {
1249 vrc = pEvent->GetGuestError();
1250 }
1251 }
1252
1253 unregisterWaitEvent(pEvent);
1254
1255 LogFlowFuncLeaveRC(vrc);
1256 return vrc;
1257}
1258
1259// Wrapped IGuestFile methods
1260/////////////////////////////////////////////////////////////////////////////
1261HRESULT GuestFile::close()
1262{
1263 AutoCaller autoCaller(this);
1264 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1265
1266 LogFlowThisFuncEnter();
1267
1268 /* Close file on guest. */
1269 int rcGuest;
1270 int vrc = i_closeFile(&rcGuest);
1271 /* On failure don't return here, instead do all the cleanup
1272 * work first and then return an error. */
1273
1274 AssertPtr(mSession);
1275 int vrc2 = mSession->i_fileUnregister(this);
1276 if (RT_SUCCESS(vrc))
1277 vrc = vrc2;
1278
1279 if (RT_FAILURE(vrc))
1280 {
1281 if (vrc == VERR_GSTCTL_GUEST_ERROR)
1282 return GuestFile::i_setErrorExternal(this, rcGuest);
1283 return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Closing guest file failed with %Rrc\n"), vrc);
1284 }
1285
1286 LogFlowThisFunc(("Returning S_OK / vrc=%Rrc\n", vrc));
1287 return S_OK;
1288}
1289
1290HRESULT GuestFile::queryInfo(ComPtr<IFsObjInfo> &aObjInfo)
1291{
1292 AutoCaller autoCaller(this);
1293 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1294
1295 LogFlowThisFuncEnter();
1296
1297 HRESULT hr = S_OK;
1298
1299 GuestFsObjData fsObjData; int rcGuest;
1300 int vrc = i_queryInfo(fsObjData, &rcGuest);
1301 if (RT_SUCCESS(vrc))
1302 {
1303 ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
1304 hr = ptrFsObjInfo.createObject();
1305 if (SUCCEEDED(hr))
1306 {
1307 vrc = ptrFsObjInfo->init(fsObjData);
1308 if (RT_SUCCESS(vrc))
1309 hr = ptrFsObjInfo.queryInterfaceTo(aObjInfo.asOutParam());
1310 else
1311 hr = setErrorVrc(vrc);
1312 }
1313 }
1314 else
1315 {
1316 if (GuestProcess::i_isGuestError(vrc))
1317 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1318 else
1319 hr = setErrorVrc(vrc, tr("Querying file information failed: %Rrc"), vrc);
1320 }
1321
1322 LogFlowFuncLeaveRC(vrc);
1323 return hr;
1324}
1325
1326HRESULT GuestFile::querySize(LONG64 *aSize)
1327{
1328 AutoCaller autoCaller(this);
1329 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1330
1331 LogFlowThisFuncEnter();
1332
1333 HRESULT hr = S_OK;
1334
1335 GuestFsObjData fsObjData; int rcGuest;
1336 int vrc = i_queryInfo(fsObjData, &rcGuest);
1337 if (RT_SUCCESS(vrc))
1338 {
1339 *aSize = fsObjData.mObjectSize;
1340 }
1341 else
1342 {
1343 if (GuestProcess::i_isGuestError(vrc))
1344 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1345 else
1346 hr = setErrorVrc(vrc, tr("Querying file size failed: %Rrc"), vrc);
1347 }
1348
1349 LogFlowFuncLeaveRC(vrc);
1350 return hr;
1351}
1352
1353HRESULT GuestFile::read(ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1354{
1355 AutoCaller autoCaller(this);
1356 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1357
1358 if (aToRead == 0)
1359 return setError(E_INVALIDARG, tr("The size to read is zero"));
1360
1361 LogFlowThisFuncEnter();
1362
1363 aData.resize(aToRead);
1364
1365 HRESULT hr = S_OK;
1366
1367 uint32_t cbRead;
1368 int vrc = i_readData(aToRead, aTimeoutMS,
1369 &aData.front(), aToRead, &cbRead);
1370
1371 if (RT_SUCCESS(vrc))
1372 {
1373 if (aData.size() != cbRead)
1374 aData.resize(cbRead);
1375 }
1376 else
1377 {
1378 aData.resize(0);
1379
1380 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" failed: %Rrc"),
1381 mData.mOpenInfo.mFilename.c_str(), vrc);
1382 }
1383
1384 LogFlowFuncLeaveRC(vrc);
1385 return hr;
1386}
1387
1388HRESULT GuestFile::readAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1389{
1390 AutoCaller autoCaller(this);
1391 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1392
1393 if (aToRead == 0)
1394 return setError(E_INVALIDARG, tr("The size to read is zero"));
1395
1396 LogFlowThisFuncEnter();
1397
1398 aData.resize(aToRead);
1399
1400 HRESULT hr = S_OK;
1401
1402 size_t cbRead;
1403 int vrc = i_readDataAt(aOffset, aToRead, aTimeoutMS,
1404 &aData.front(), aToRead, &cbRead);
1405 if (RT_SUCCESS(vrc))
1406 {
1407 if (aData.size() != cbRead)
1408 aData.resize(cbRead);
1409 }
1410 else
1411 {
1412 aData.resize(0);
1413
1414 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1415 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1416 }
1417
1418 LogFlowFuncLeaveRC(vrc);
1419 return hr;
1420}
1421
1422HRESULT GuestFile::seek(LONG64 aOffset, FileSeekOrigin_T aWhence, LONG64 *aNewOffset)
1423{
1424 AutoCaller autoCaller(this);
1425 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1426
1427 HRESULT hr = S_OK;
1428
1429 GUEST_FILE_SEEKTYPE eSeekType;
1430 switch (aWhence)
1431 {
1432 case FileSeekOrigin_Begin:
1433 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1434 break;
1435
1436 case FileSeekOrigin_Current:
1437 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1438 break;
1439
1440 case FileSeekOrigin_End:
1441 eSeekType = GUEST_FILE_SEEKTYPE_END;
1442 break;
1443
1444 default:
1445 return setError(E_INVALIDARG, tr("Invalid seek type specified"));
1446 }
1447
1448 LogFlowThisFuncEnter();
1449
1450 uint64_t uNewOffset;
1451 int vrc = i_seekAt(aOffset, eSeekType,
1452 30 * 1000 /* 30s timeout */, &uNewOffset);
1453 if (RT_SUCCESS(vrc))
1454 *aNewOffset = RT_MIN(uNewOffset, (uint64_t)INT64_MAX);
1455 else
1456 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"),
1457 mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1458
1459 LogFlowFuncLeaveRC(vrc);
1460 return hr;
1461}
1462
1463HRESULT GuestFile::setACL(const com::Utf8Str &aAcl, ULONG aMode)
1464{
1465 RT_NOREF(aAcl, aMode);
1466 ReturnComNotImplemented();
1467}
1468
1469HRESULT GuestFile::setSize(LONG64 aSize)
1470{
1471 RT_NOREF(aSize);
1472 ReturnComNotImplemented();
1473}
1474
1475HRESULT GuestFile::write(const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1476{
1477 AutoCaller autoCaller(this);
1478 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1479
1480 LogFlowThisFuncEnter();
1481
1482 HRESULT hr = S_OK;
1483
1484 uint32_t cbData = (uint32_t)aData.size();
1485 void *pvData = cbData > 0? (void *)&aData.front(): NULL;
1486 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1487 if (RT_FAILURE(vrc))
1488 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
1489 aData.size(), mData.mOpenInfo.mFilename.c_str(), vrc);
1490
1491 LogFlowFuncLeaveRC(vrc);
1492 return hr;
1493}
1494
1495HRESULT GuestFile::writeAt(LONG64 aOffset, const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1496{
1497 AutoCaller autoCaller(this);
1498 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1499
1500 LogFlowThisFuncEnter();
1501
1502 HRESULT hr = S_OK;
1503
1504 uint32_t cbData = (uint32_t)aData.size();
1505 void *pvData = cbData > 0? (void *)&aData.front(): NULL;
1506 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1507 if (RT_FAILURE(vrc))
1508 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
1509 aData.size(), mData.mOpenInfo.mFilename.c_str(), aOffset, vrc);
1510
1511 LogFlowFuncLeaveRC(vrc);
1512 return hr;
1513}
1514
Note: See TracBrowser for help on using the repository browser.

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