VirtualBox

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

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

Guest Control/Main: One more error code for GuestFile::i_guestErrorToString().

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

© 2023 Oracle
ContactPrivacy policyTerms of Use