VirtualBox

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

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

HGCM: Replace C++-style inline members on VBOXHGCMSVCPARM with simple functions.
bugref:9172: Shared folder performance tuning
Changes in bugref:9172 caused a build regression on Ubuntu 18.10 due to the
use of RT_ZERO on a structure containing an embedded VBOXHGCMSVCPARM, as
VBOXHGCMSVCPARM had member functions and was therefore not a simple plain-
old-data structure. Rather than just doing the sensible thing and zeroing
it in a different way, I converted the inline member getters and setters to
standard inline C functions, including fixing callers. Actually I had planned
this for some time, as the member function use seemed a bit gratuitous in
hindsight.

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