VirtualBox

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

Last change on this file since 72088 was 71816, checked in by vboxsync, 7 years ago

Guest Control/Main: Fixed returning written bytes in GuestFile::i_writeData() / GuestFile::i_writeDataAt().

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