VirtualBox

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

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

Main: Use setErrorBoth when we've got a VBox status code handy. (The COM status codes aren't too specfic and this may help us decode error messages and provide an alternative to strstr for API clients. setErrorBoth isn't new, btw.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.5 KB
Line 
1/* $Id: GuestFileImpl.cpp 73003 2018-07-09 11:09:32Z 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_OpenExisting: pszOpenAction = "oe"; break;
653 case FileOpenAction_OpenOrCreate: pszOpenAction = "oc"; break;
654 case FileOpenAction_CreateNew: pszOpenAction = "ce"; break;
655 case FileOpenAction_CreateOrReplace: pszOpenAction = "ca"; break;
656 case FileOpenAction_OpenExistingTruncated: pszOpenAction = "ot"; break;
657 case 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_ReadOnly: pszAccessMode = "r"; break;
669 case FileAccessMode_WriteOnly: pszAccessMode = "w"; break;
670 case FileAccessMode_ReadWrite: pszAccessMode = "r+"; break;
671 case FileAccessMode_AppendOnly: RT_FALL_THRU();
672 case FileAccessMode_AppendRead: return VERR_NOT_IMPLEMENTED;
673 default: return VERR_INVALID_PARAMETER;
674 }
675
676 /* Validate and translate sharing mode. */
677 const char *pszSharingMode = NULL;
678 switch (mData.mOpenInfo.mSharingMode)
679 {
680 case FileSharingMode_All: pszSharingMode = ""; break;
681 case FileSharingMode_Read: RT_FALL_THRU();
682 case FileSharingMode_Write: RT_FALL_THRU();
683 case FileSharingMode_ReadWrite: RT_FALL_THRU();
684 case FileSharingMode_Delete: RT_FALL_THRU();
685 case FileSharingMode_ReadDelete: RT_FALL_THRU();
686 case FileSharingMode_WriteDelete: return VERR_NOT_IMPLEMENTED;
687 default: return VERR_INVALID_PARAMETER;
688 }
689
690 int vrc;
691
692 GuestWaitEvent *pEvent = NULL;
693 GuestEventTypes eventTypes;
694 try
695 {
696 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
697
698 vrc = registerWaitEvent(eventTypes, &pEvent);
699 }
700 catch (std::bad_alloc)
701 {
702 vrc = VERR_NO_MEMORY;
703 }
704
705 if (RT_FAILURE(vrc))
706 return vrc;
707
708 /* Prepare HGCM call. */
709 VBOXHGCMSVCPARM paParms[8];
710 int i = 0;
711 paParms[i++].setUInt32(pEvent->ContextID());
712 paParms[i++].setPointer((void*)mData.mOpenInfo.mFileName.c_str(),
713 (ULONG)mData.mOpenInfo.mFileName.length() + 1);
714 paParms[i++].setString(pszAccessMode);
715 paParms[i++].setString(pszOpenAction);
716 paParms[i++].setString(pszSharingMode);
717 paParms[i++].setUInt32(mData.mOpenInfo.mCreationMode);
718 paParms[i++].setUInt64(mData.mOpenInfo.muOffset);
719 /** @todo Next protocol version: add flags, replace strings, remove initial offset. */
720
721 alock.release(); /* Drop write lock before sending. */
722
723 vrc = sendCommand(HOST_FILE_OPEN, i, paParms);
724 if (RT_SUCCESS(vrc))
725 vrc = i_waitForStatusChange(pEvent, uTimeoutMS, NULL /* FileStatus */, prcGuest);
726
727 unregisterWaitEvent(pEvent);
728
729 LogFlowFuncLeaveRC(vrc);
730 return vrc;
731}
732
733int GuestFile::i_queryInfo(GuestFsObjData &objData, int *prcGuest)
734{
735 AssertPtr(mSession);
736 return mSession->i_fsQueryInfo(mData.mOpenInfo.mFileName, FALSE /* fFollowSymlinks */, objData, prcGuest);
737}
738
739int GuestFile::i_readData(uint32_t uSize, uint32_t uTimeoutMS,
740 void* pvData, uint32_t cbData, uint32_t* pcbRead)
741{
742 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
743 AssertReturn(cbData, VERR_INVALID_PARAMETER);
744
745 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
746 uSize, uTimeoutMS, pvData, cbData));
747
748 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
749
750 int vrc;
751
752 GuestWaitEvent *pEvent = NULL;
753 GuestEventTypes eventTypes;
754 try
755 {
756 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
757 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
758
759 vrc = registerWaitEvent(eventTypes, &pEvent);
760 }
761 catch (std::bad_alloc)
762 {
763 vrc = VERR_NO_MEMORY;
764 }
765
766 if (RT_FAILURE(vrc))
767 return vrc;
768
769 /* Prepare HGCM call. */
770 VBOXHGCMSVCPARM paParms[4];
771 int i = 0;
772 paParms[i++].setUInt32(pEvent->ContextID());
773 paParms[i++].setUInt32(mObjectID /* File handle */);
774 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
775
776 alock.release(); /* Drop write lock before sending. */
777
778 vrc = sendCommand(HOST_FILE_READ, i, paParms);
779 if (RT_SUCCESS(vrc))
780 {
781 uint32_t cbRead = 0;
782 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
783 if (RT_SUCCESS(vrc))
784 {
785 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
786 if (pcbRead)
787 *pcbRead = cbRead;
788 }
789 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
790 {
791 vrc = pEvent->GetGuestError();
792 }
793 }
794
795 unregisterWaitEvent(pEvent);
796
797 LogFlowFuncLeaveRC(vrc);
798 return vrc;
799}
800
801int GuestFile::i_readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
802 void* pvData, size_t cbData, size_t* pcbRead)
803{
804 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
805 uOffset, uSize, uTimeoutMS, pvData, cbData));
806
807 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
808
809 int vrc;
810
811 GuestWaitEvent *pEvent = NULL;
812 GuestEventTypes eventTypes;
813 try
814 {
815 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
816 eventTypes.push_back(VBoxEventType_OnGuestFileRead);
817
818 vrc = registerWaitEvent(eventTypes, &pEvent);
819 }
820 catch (std::bad_alloc)
821 {
822 vrc = VERR_NO_MEMORY;
823 }
824
825 if (RT_FAILURE(vrc))
826 return vrc;
827
828 /* Prepare HGCM call. */
829 VBOXHGCMSVCPARM paParms[4];
830 int i = 0;
831 paParms[i++].setUInt32(pEvent->ContextID());
832 paParms[i++].setUInt32(mObjectID /* File handle */);
833 paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
834 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
835
836 alock.release(); /* Drop write lock before sending. */
837
838 vrc = sendCommand(HOST_FILE_READ_AT, i, paParms);
839 if (RT_SUCCESS(vrc))
840 {
841 uint32_t cbRead = 0;
842 vrc = i_waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
843 if (RT_SUCCESS(vrc))
844 {
845 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
846
847 if (pcbRead)
848 *pcbRead = cbRead;
849 }
850 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
851 {
852 vrc = pEvent->GetGuestError();
853 }
854 }
855
856 unregisterWaitEvent(pEvent);
857
858 LogFlowFuncLeaveRC(vrc);
859 return vrc;
860}
861
862int GuestFile::i_seekAt(int64_t iOffset, GUEST_FILE_SEEKTYPE eSeekType,
863 uint32_t uTimeoutMS, uint64_t *puOffset)
864{
865 LogFlowThisFunc(("iOffset=%RI64, uTimeoutMS=%RU32\n",
866 iOffset, uTimeoutMS));
867
868 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
869
870 int vrc;
871
872 GuestWaitEvent *pEvent = NULL;
873 GuestEventTypes eventTypes;
874 try
875 {
876 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
877 eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
878
879 vrc = registerWaitEvent(eventTypes, &pEvent);
880 }
881 catch (std::bad_alloc)
882 {
883 vrc = VERR_NO_MEMORY;
884 }
885
886 if (RT_FAILURE(vrc))
887 return vrc;
888
889 /* Prepare HGCM call. */
890 VBOXHGCMSVCPARM paParms[4];
891 int i = 0;
892 paParms[i++].setUInt32(pEvent->ContextID());
893 paParms[i++].setUInt32(mObjectID /* File handle */);
894 paParms[i++].setUInt32(eSeekType /* Seek method */);
895 /** @todo uint64_t vs. int64_t! */
896 paParms[i++].setUInt64((uint64_t)iOffset /* Offset (in bytes) to start reading */);
897
898 alock.release(); /* Drop write lock before sending. */
899
900 vrc = sendCommand(HOST_FILE_SEEK, i, paParms);
901 if (RT_SUCCESS(vrc))
902 {
903 uint64_t uOffset;
904 vrc = i_waitForOffsetChange(pEvent, uTimeoutMS, &uOffset);
905 if (RT_SUCCESS(vrc))
906 {
907 LogFlowThisFunc(("uOffset=%RU64\n", uOffset));
908
909 if (puOffset)
910 *puOffset = uOffset;
911 }
912 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
913 {
914 vrc = pEvent->GetGuestError();
915 }
916 }
917
918 unregisterWaitEvent(pEvent);
919
920 LogFlowFuncLeaveRC(vrc);
921 return vrc;
922}
923
924/* static */
925HRESULT GuestFile::i_setErrorExternal(VirtualBoxBase *pInterface, int rcGuest)
926{
927 AssertPtr(pInterface);
928 AssertMsg(RT_FAILURE(rcGuest), ("Guest rc does not indicate a failure when setting error\n"));
929
930 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestFile::i_guestErrorToString(rcGuest).c_str());
931}
932
933int GuestFile::i_setFileStatus(FileStatus_T fileStatus, int fileRc)
934{
935 LogFlowThisFuncEnter();
936
937 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
938
939 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, fileRc=%Rrc\n",
940 mData.mStatus, fileStatus, fileRc));
941
942#ifdef VBOX_STRICT
943 if (fileStatus == FileStatus_Error)
944 {
945 AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc));
946 }
947 else
948 AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc));
949#endif
950
951 if (mData.mStatus != fileStatus)
952 {
953 mData.mStatus = fileStatus;
954 mData.mLastError = fileRc;
955
956 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
957 HRESULT hr = errorInfo.createObject();
958 ComAssertComRC(hr);
959 if (RT_FAILURE(fileRc))
960 {
961 hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, fileRc,
962 COM_IIDOF(IGuestFile), getComponentName(),
963 i_guestErrorToString(fileRc));
964 ComAssertComRC(hr);
965 }
966
967 alock.release(); /* Release lock before firing off event. */
968
969 fireGuestFileStateChangedEvent(mEventSource, mSession,
970 this, fileStatus, errorInfo);
971 }
972
973 return VINF_SUCCESS;
974}
975
976int GuestFile::i_waitForOffsetChange(GuestWaitEvent *pEvent,
977 uint32_t uTimeoutMS, uint64_t *puOffset)
978{
979 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
980
981 VBoxEventType_T evtType;
982 ComPtr<IEvent> pIEvent;
983 int vrc = waitForEvent(pEvent, uTimeoutMS,
984 &evtType, pIEvent.asOutParam());
985 if (RT_SUCCESS(vrc))
986 {
987 if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
988 {
989 if (puOffset)
990 {
991 ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
992 Assert(!pFileEvent.isNull());
993
994 HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
995 ComAssertComRC(hr);
996 }
997 }
998 else
999 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1000 }
1001
1002 return vrc;
1003}
1004
1005int GuestFile::i_waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1006 void *pvData, size_t cbData, uint32_t *pcbRead)
1007{
1008 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1009
1010 VBoxEventType_T evtType;
1011 ComPtr<IEvent> pIEvent;
1012 int vrc = waitForEvent(pEvent, uTimeoutMS,
1013 &evtType, pIEvent.asOutParam());
1014 if (RT_SUCCESS(vrc))
1015 {
1016 if (evtType == VBoxEventType_OnGuestFileRead)
1017 {
1018 ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
1019 Assert(!pFileEvent.isNull());
1020
1021 HRESULT hr;
1022 if (pvData)
1023 {
1024 com::SafeArray <BYTE> data;
1025 hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1026 ComAssertComRC(hr);
1027 const size_t cbRead = data.size();
1028 if (cbRead)
1029 {
1030 if (cbRead <= cbData)
1031 memcpy(pvData, data.raw(), cbRead);
1032 else
1033 vrc = VERR_BUFFER_OVERFLOW;
1034 }
1035 else
1036 vrc = VERR_NO_DATA;
1037 }
1038 if (pcbRead)
1039 {
1040 hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
1041 ComAssertComRC(hr);
1042 }
1043 }
1044 else
1045 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1046 }
1047
1048 return vrc;
1049}
1050
1051int GuestFile::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1052 FileStatus_T *pFileStatus, int *prcGuest)
1053{
1054 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1055 /* pFileStatus is optional. */
1056
1057 VBoxEventType_T evtType;
1058 ComPtr<IEvent> pIEvent;
1059 int vrc = waitForEvent(pEvent, uTimeoutMS,
1060 &evtType, pIEvent.asOutParam());
1061 if (RT_SUCCESS(vrc))
1062 {
1063 Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
1064 ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
1065 Assert(!pFileEvent.isNull());
1066
1067 HRESULT hr;
1068 if (pFileStatus)
1069 {
1070 hr = pFileEvent->COMGETTER(Status)(pFileStatus);
1071 ComAssertComRC(hr);
1072 }
1073
1074 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1075 hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam());
1076 ComAssertComRC(hr);
1077
1078 LONG lGuestRc;
1079 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1080 ComAssertComRC(hr);
1081
1082 LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n",
1083 lGuestRc, lGuestRc));
1084
1085 if (RT_FAILURE((int)lGuestRc))
1086 vrc = VERR_GSTCTL_GUEST_ERROR;
1087
1088 if (prcGuest)
1089 *prcGuest = (int)lGuestRc;
1090 }
1091
1092 return vrc;
1093}
1094
1095int GuestFile::i_waitForWrite(GuestWaitEvent *pEvent,
1096 uint32_t uTimeoutMS, uint32_t *pcbWritten)
1097{
1098 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1099
1100 VBoxEventType_T evtType;
1101 ComPtr<IEvent> pIEvent;
1102 int vrc = waitForEvent(pEvent, uTimeoutMS,
1103 &evtType, pIEvent.asOutParam());
1104 if (RT_SUCCESS(vrc))
1105 {
1106 if (evtType == VBoxEventType_OnGuestFileWrite)
1107 {
1108 if (pcbWritten)
1109 {
1110 ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
1111 Assert(!pFileEvent.isNull());
1112
1113 HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
1114 ComAssertComRC(hr);
1115 }
1116 }
1117 else
1118 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1119 }
1120
1121 return vrc;
1122}
1123
1124int GuestFile::i_writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData,
1125 uint32_t *pcbWritten)
1126{
1127 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1128 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1129
1130 LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1131 uTimeoutMS, pvData, cbData));
1132
1133 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1134
1135 int vrc;
1136
1137 GuestWaitEvent *pEvent = NULL;
1138 GuestEventTypes eventTypes;
1139 try
1140 {
1141 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1142 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1143
1144 vrc = registerWaitEvent(eventTypes, &pEvent);
1145 }
1146 catch (std::bad_alloc)
1147 {
1148 vrc = VERR_NO_MEMORY;
1149 }
1150
1151 if (RT_FAILURE(vrc))
1152 return vrc;
1153
1154 /* Prepare HGCM call. */
1155 VBOXHGCMSVCPARM paParms[8];
1156 int i = 0;
1157 paParms[i++].setUInt32(pEvent->ContextID());
1158 paParms[i++].setUInt32(mObjectID /* File handle */);
1159 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
1160 paParms[i++].setPointer(pvData, cbData);
1161
1162 alock.release(); /* Drop write lock before sending. */
1163
1164 vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
1165 if (RT_SUCCESS(vrc))
1166 {
1167 uint32_t cbWritten = 0;
1168 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1169 if (RT_SUCCESS(vrc))
1170 {
1171 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1172 if (pcbWritten)
1173 *pcbWritten = cbWritten;
1174 }
1175 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1176 {
1177 vrc = pEvent->GetGuestError();
1178 }
1179 }
1180
1181 unregisterWaitEvent(pEvent);
1182
1183 LogFlowFuncLeaveRC(vrc);
1184 return vrc;
1185}
1186
1187int GuestFile::i_writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
1188 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1189{
1190 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1191 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1192
1193 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
1194 uOffset, uTimeoutMS, pvData, cbData));
1195
1196 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1197
1198 int vrc;
1199
1200 GuestWaitEvent *pEvent = NULL;
1201 GuestEventTypes eventTypes;
1202 try
1203 {
1204 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
1205 eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
1206
1207 vrc = registerWaitEvent(eventTypes, &pEvent);
1208 }
1209 catch (std::bad_alloc)
1210 {
1211 vrc = VERR_NO_MEMORY;
1212 }
1213
1214 if (RT_FAILURE(vrc))
1215 return vrc;
1216
1217 /* Prepare HGCM call. */
1218 VBOXHGCMSVCPARM paParms[8];
1219 int i = 0;
1220 paParms[i++].setUInt32(pEvent->ContextID());
1221 paParms[i++].setUInt32(mObjectID /* File handle */);
1222 paParms[i++].setUInt64(uOffset /* Offset where to starting writing */);
1223 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
1224 paParms[i++].setPointer(pvData, cbData);
1225
1226 alock.release(); /* Drop write lock before sending. */
1227
1228 vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
1229 if (RT_SUCCESS(vrc))
1230 {
1231 uint32_t cbWritten = 0;
1232 vrc = i_waitForWrite(pEvent, uTimeoutMS, &cbWritten);
1233 if (RT_SUCCESS(vrc))
1234 {
1235 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1236 if (pcbWritten)
1237 *pcbWritten = cbWritten;
1238 }
1239 else if (pEvent->HasGuestError()) /* Return guest rc if available. */
1240 {
1241 vrc = pEvent->GetGuestError();
1242 }
1243 }
1244
1245 unregisterWaitEvent(pEvent);
1246
1247 LogFlowFuncLeaveRC(vrc);
1248 return vrc;
1249}
1250
1251// Wrapped IGuestFile methods
1252/////////////////////////////////////////////////////////////////////////////
1253HRESULT GuestFile::close()
1254{
1255 AutoCaller autoCaller(this);
1256 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1257
1258 LogFlowThisFuncEnter();
1259
1260 /* Close file on guest. */
1261 int rcGuest;
1262 int vrc = i_closeFile(&rcGuest);
1263 /* On failure don't return here, instead do all the cleanup
1264 * work first and then return an error. */
1265
1266 AssertPtr(mSession);
1267 int vrc2 = mSession->i_fileUnregister(this);
1268 if (RT_SUCCESS(vrc))
1269 vrc = vrc2;
1270
1271 if (RT_FAILURE(vrc))
1272 {
1273 if (vrc == VERR_GSTCTL_GUEST_ERROR)
1274 return GuestFile::i_setErrorExternal(this, rcGuest);
1275 return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Closing guest file failed with %Rrc\n"), vrc);
1276 }
1277
1278 LogFlowThisFunc(("Returning S_OK / vrc=%Rrc\n", vrc));
1279 return S_OK;
1280}
1281
1282HRESULT GuestFile::queryInfo(ComPtr<IFsObjInfo> &aObjInfo)
1283{
1284 AutoCaller autoCaller(this);
1285 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1286
1287 LogFlowThisFuncEnter();
1288
1289 HRESULT hr = S_OK;
1290
1291 GuestFsObjData fsObjData; int rcGuest;
1292 int vrc = i_queryInfo(fsObjData, &rcGuest);
1293 if (RT_SUCCESS(vrc))
1294 {
1295 ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
1296 hr = ptrFsObjInfo.createObject();
1297 if (SUCCEEDED(hr))
1298 {
1299 vrc = ptrFsObjInfo->init(fsObjData);
1300 if (RT_SUCCESS(vrc))
1301 hr = ptrFsObjInfo.queryInterfaceTo(aObjInfo.asOutParam());
1302 else
1303 hr = setErrorVrc(vrc);
1304 }
1305 }
1306 else
1307 {
1308 if (GuestProcess::i_isGuestError(vrc))
1309 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1310 else
1311 hr = setErrorVrc(vrc, tr("Querying file information failed: %Rrc"), vrc);
1312 }
1313
1314 LogFlowFuncLeaveRC(vrc);
1315 return hr;
1316}
1317
1318HRESULT GuestFile::querySize(LONG64 *aSize)
1319{
1320 AutoCaller autoCaller(this);
1321 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1322
1323 LogFlowThisFuncEnter();
1324
1325 HRESULT hr = S_OK;
1326
1327 GuestFsObjData fsObjData; int rcGuest;
1328 int vrc = i_queryInfo(fsObjData, &rcGuest);
1329 if (RT_SUCCESS(vrc))
1330 {
1331 *aSize = fsObjData.mObjectSize;
1332 }
1333 else
1334 {
1335 if (GuestProcess::i_isGuestError(vrc))
1336 hr = GuestProcess::i_setErrorExternal(this, rcGuest);
1337 else
1338 hr = setErrorVrc(vrc, tr("Querying file size failed: %Rrc"), vrc);
1339 }
1340
1341 LogFlowFuncLeaveRC(vrc);
1342 return hr;
1343}
1344
1345HRESULT GuestFile::read(ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1346{
1347 AutoCaller autoCaller(this);
1348 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1349
1350 if (aToRead == 0)
1351 return setError(E_INVALIDARG, tr("The size to read is zero"));
1352
1353 LogFlowThisFuncEnter();
1354
1355 aData.resize(aToRead);
1356
1357 HRESULT hr = S_OK;
1358
1359 uint32_t cbRead;
1360 int vrc = i_readData(aToRead, aTimeoutMS,
1361 &aData.front(), aToRead, &cbRead);
1362
1363 if (RT_SUCCESS(vrc))
1364 {
1365 if (aData.size() != cbRead)
1366 aData.resize(cbRead);
1367 }
1368 else
1369 {
1370 aData.resize(0);
1371
1372 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" failed: %Rrc"),
1373 mData.mOpenInfo.mFileName.c_str(), vrc);
1374 }
1375
1376 LogFlowFuncLeaveRC(vrc);
1377 return hr;
1378}
1379
1380HRESULT GuestFile::readAt(LONG64 aOffset, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1381{
1382 AutoCaller autoCaller(this);
1383 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1384
1385 if (aToRead == 0)
1386 return setError(E_INVALIDARG, tr("The size to read is zero"));
1387
1388 LogFlowThisFuncEnter();
1389
1390 aData.resize(aToRead);
1391
1392 HRESULT hr = S_OK;
1393
1394 size_t cbRead;
1395 int vrc = i_readDataAt(aOffset, aToRead, aTimeoutMS,
1396 &aData.front(), aToRead, &cbRead);
1397 if (RT_SUCCESS(vrc))
1398 {
1399 if (aData.size() != cbRead)
1400 aData.resize(cbRead);
1401 }
1402 else
1403 {
1404 aData.resize(0);
1405
1406 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading from file \"%s\" (at offset %RU64) failed: %Rrc"),
1407 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1408 }
1409
1410 LogFlowFuncLeaveRC(vrc);
1411 return hr;
1412}
1413
1414HRESULT GuestFile::seek(LONG64 aOffset, FileSeekOrigin_T aWhence, LONG64 *aNewOffset)
1415{
1416 AutoCaller autoCaller(this);
1417 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1418
1419 HRESULT hr = S_OK;
1420
1421 GUEST_FILE_SEEKTYPE eSeekType;
1422 switch (aWhence)
1423 {
1424 case FileSeekOrigin_Begin:
1425 eSeekType = GUEST_FILE_SEEKTYPE_BEGIN;
1426 break;
1427
1428 case FileSeekOrigin_Current:
1429 eSeekType = GUEST_FILE_SEEKTYPE_CURRENT;
1430 break;
1431
1432 case FileSeekOrigin_End:
1433 eSeekType = GUEST_FILE_SEEKTYPE_END;
1434 break;
1435
1436 default:
1437 return setError(E_INVALIDARG, tr("Invalid seek type specified"));
1438 }
1439
1440 LogFlowThisFuncEnter();
1441
1442 uint64_t uNewOffset;
1443 int vrc = i_seekAt(aOffset, eSeekType,
1444 30 * 1000 /* 30s timeout */, &uNewOffset);
1445 if (RT_SUCCESS(vrc))
1446 *aNewOffset = RT_MIN(uNewOffset, (uint64_t)INT64_MAX);
1447 else
1448 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Seeking file \"%s\" (to offset %RI64) failed: %Rrc"),
1449 mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1450
1451 LogFlowFuncLeaveRC(vrc);
1452 return hr;
1453}
1454
1455HRESULT GuestFile::setACL(const com::Utf8Str &aAcl, ULONG aMode)
1456{
1457 RT_NOREF(aAcl, aMode);
1458 ReturnComNotImplemented();
1459}
1460
1461HRESULT GuestFile::setSize(LONG64 aSize)
1462{
1463 RT_NOREF(aSize);
1464 ReturnComNotImplemented();
1465}
1466
1467HRESULT GuestFile::write(const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1468{
1469 AutoCaller autoCaller(this);
1470 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1471
1472 LogFlowThisFuncEnter();
1473
1474 HRESULT hr = S_OK;
1475
1476 uint32_t cbData = (uint32_t)aData.size();
1477 void *pvData = cbData > 0? (void *)&aData.front(): NULL;
1478 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1479 if (RT_FAILURE(vrc))
1480 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" failed: %Rrc"),
1481 aData.size(), mData.mOpenInfo.mFileName.c_str(), vrc);
1482
1483 LogFlowFuncLeaveRC(vrc);
1484 return hr;
1485}
1486
1487HRESULT GuestFile::writeAt(LONG64 aOffset, const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1488{
1489 AutoCaller autoCaller(this);
1490 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1491
1492 LogFlowThisFuncEnter();
1493
1494 HRESULT hr = S_OK;
1495
1496 uint32_t cbData = (uint32_t)aData.size();
1497 void *pvData = cbData > 0? (void *)&aData.front(): NULL;
1498 int vrc = i_writeData(aTimeoutMS, pvData, cbData, (uint32_t*)aWritten);
1499 if (RT_FAILURE(vrc))
1500 hr = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Writing %zubytes to file \"%s\" (at offset %RU64) failed: %Rrc"),
1501 aData.size(), mData.mOpenInfo.mFileName.c_str(), aOffset, vrc);
1502
1503 LogFlowFuncLeaveRC(vrc);
1504 return hr;
1505}
1506
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