int GuestFile::i_waitForOffsetChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, uint64_t *puOffset) { AssertPtrReturn(pEvent, VERR_INVALID_POINTER); VBoxEventType_T evtType; ComPtr<IEvent> pIEvent; int vrc = waitForEvent(pEvent, uTimeoutMS, &evtType, pIEvent.asOutParam()); if (RT_SUCCESS(vrc)) { if (evtType == VBoxEventType_OnGuestFileOffsetChanged) { if (puOffset) { ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent; Assert(!pFileEvent.isNull()); HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset); ComAssertComRC(hr); } } else vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED; } return vrc; }
int GuestFile::i_waitForWrite(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, uint32_t *pcbWritten) { AssertPtrReturn(pEvent, VERR_INVALID_POINTER); VBoxEventType_T evtType; ComPtr<IEvent> pIEvent; int vrc = waitForEvent(pEvent, uTimeoutMS, &evtType, pIEvent.asOutParam()); if (RT_SUCCESS(vrc)) { if (evtType == VBoxEventType_OnGuestFileWrite) { if (pcbWritten) { ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent; Assert(!pFileEvent.isNull()); HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten); ComAssertComRC(hr); } } else vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED; } return vrc; }
int GuestFile::waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead) { AssertPtrReturn(pEvent, VERR_INVALID_POINTER); VBoxEventType_T evtType; ComPtr<IEvent> pIEvent; int vrc = waitForEvent(pEvent, uTimeoutMS, &evtType, pIEvent.asOutParam()); if (RT_SUCCESS(vrc)) { if (evtType == VBoxEventType_OnGuestFileRead) { ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent; Assert(!pFileEvent.isNull()); HRESULT hr; if (pvData) { com::SafeArray <BYTE> data; hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data)); ComAssertComRC(hr); size_t cbRead = data.size(); if ( cbRead && cbRead <= cbData) { memcpy(pvData, data.raw(), data.size()); } else vrc = VERR_BUFFER_OVERFLOW; } if (pcbRead) { hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead); ComAssertComRC(hr); } } else vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED; } return vrc; }
int GuestFile::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, FileStatus_T *pFileStatus, int *pGuestRc) { AssertPtrReturn(pEvent, VERR_INVALID_POINTER); /* pFileStatus is optional. */ VBoxEventType_T evtType; ComPtr<IEvent> pIEvent; int vrc = waitForEvent(pEvent, uTimeoutMS, &evtType, pIEvent.asOutParam()); if (RT_SUCCESS(vrc)) { Assert(evtType == VBoxEventType_OnGuestFileStateChanged); ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent; Assert(!pFileEvent.isNull()); HRESULT hr; if (pFileStatus) { hr = pFileEvent->COMGETTER(Status)(pFileStatus); ComAssertComRC(hr); } ComPtr<IVirtualBoxErrorInfo> errorInfo; hr = pFileEvent->COMGETTER(Error)(errorInfo.asOutParam()); ComAssertComRC(hr); LONG lGuestRc; hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc); ComAssertComRC(hr); LogFlowThisFunc(("resultDetail=%RI32 (%Rrc)\n", lGuestRc, lGuestRc)); if (RT_FAILURE((int)lGuestRc)) vrc = VERR_GSTCTL_GUEST_ERROR; if (pGuestRc) *pGuestRc = (int)lGuestRc; } return vrc; }
int GuestFile::i_setFileStatus(FileStatus_T fileStatus, int fileRc) { LogFlowThisFuncEnter(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, fileRc=%Rrc\n", mData.mStatus, fileStatus, fileRc)); #ifdef VBOX_STRICT if (fileStatus == FileStatus_Error) { AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc)); } else AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc)); #endif if (mData.mStatus != fileStatus) { mData.mStatus = fileStatus; mData.mLastError = fileRc; ComObjPtr<VirtualBoxErrorInfo> errorInfo; HRESULT hr = errorInfo.createObject(); ComAssertComRC(hr); if (RT_FAILURE(fileRc)) { hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, fileRc, COM_IIDOF(IGuestFile), getComponentName(), i_guestErrorToString(fileRc)); ComAssertComRC(hr); } alock.release(); /* Release lock before firing off event. */ fireGuestFileStateChangedEvent(mEventSource, mSession, this, fileStatus, errorInfo); } return VINF_SUCCESS; }
/** * Detach all USB devices currently attached to a VM. * * This is in an interface for SessionMachine::DetachAllUSBDevices(), which * is an internal worker used by Console::powerDown() from the VM process * at VM startup, and SessionMachine::uninit() at VM abend. * * This is, like #detachDeviceFromVM(), normally a two stage journey * where \a aDone indicates where we are. In addition we may be called * to clean up VMs that have abended, in which case there will be no * preparatory call. Filters will be applied to the devices in the final * call with the risk that we have to do some IPC when attaching them * to other VMs. * * @param aMachine The machine to detach devices from. * * @returns COM status code, perhaps with error info. * * @remarks Write locks the host object and may temporarily abandon * its locks to perform IPC. */ HRESULT USBProxyService::detachAllDevicesFromVM(SessionMachine *aMachine, bool aDone, bool aAbnormal) { // get a list of all running machines while we're outside the lock // (getOpenedMachines requests locks which are incompatible with the host object lock) SessionMachinesList llOpenedMachines; mHost->i_parent()->i_getOpenedMachines(llOpenedMachines); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); /* * Make a copy of the device list (not the HostUSBDevice objects, just * the list) since we may end up performing IPC and temporarily have * to abandon locks when applying filters. */ HostUSBDeviceList ListCopy = mDevices; for (HostUSBDeviceList::iterator it = ListCopy.begin(); it != ListCopy.end(); ++it) { ComObjPtr<HostUSBDevice> pHostDevice = *it; AutoWriteLock devLock(pHostDevice COMMA_LOCKVAL_SRC_POS); if (pHostDevice->i_getMachine() == aMachine) { /* * Same procedure as in detachUSBDevice(). */ bool fRunFilters = false; HRESULT hrc = pHostDevice->i_onDetachFromVM(aMachine, aDone, &fRunFilters, aAbnormal); if ( SUCCEEDED(hrc) && fRunFilters) { Assert( aDone && pHostDevice->i_getUnistate() == kHostUSBDeviceState_HeldByProxy && pHostDevice->i_getMachine().isNull()); devLock.release(); alock.release(); HRESULT hrc2 = runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine); ComAssertComRC(hrc2); alock.acquire(); } } } return S_OK; }
/** * Notification from VM process about USB device detaching progress. * * This is in an interface for SessionMachine::DetachUSBDevice(), which is * an internal worker used by Console::DetachUSBDevice() from the VM process. * * @param aMachine The machine which is sending the notification. * @param aId The UUID of the USB device is concerns. * @param aDone \a false for the pre-action notification (necessary * for advancing the device state to avoid confusing * the guest). * \a true for the post-action notification. The device * will be subjected to all filters except those of * of \a Machine. * * @returns COM status code. * * @remarks When \a aDone is \a true this method may end up doing IPC to other * VMs when running filters. In these cases it will temporarily * abandon its locks. */ HRESULT USBProxyService::detachDeviceFromVM(SessionMachine *aMachine, IN_GUID aId, bool aDone) { LogFlowThisFunc(("aMachine=%p{%s} aId={%RTuuid} aDone=%RTbool\n", aMachine, aMachine->getName().c_str(), Guid(aId).raw(), aDone)); // get a list of all running machines while we're outside the lock // (getOpenedMachines requests locks which are incompatible with the lock of the machines list) SessionMachinesList llOpenedMachines; mHost->parent()->getOpenedMachines(llOpenedMachines); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); ComObjPtr<HostUSBDevice> pHostDevice = findDeviceById(aId); ComAssertRet(!pHostDevice.isNull(), E_FAIL); AutoWriteLock devLock(pHostDevice COMMA_LOCKVAL_SRC_POS); /* * Work the state machine. */ LogFlowThisFunc(("id={%RTuuid} state=%s aDone=%RTbool name={%s}\n", pHostDevice->getId().raw(), pHostDevice->getStateName(), aDone, pHostDevice->getName().c_str())); bool fRunFilters = false; HRESULT hrc = pHostDevice->onDetachFromVM(aMachine, aDone, &fRunFilters); /* * Run filters if necessary. */ if ( SUCCEEDED(hrc) && fRunFilters) { Assert(aDone && pHostDevice->getUnistate() == kHostUSBDeviceState_HeldByProxy && pHostDevice->getMachine().isNull()); devLock.release(); alock.release(); HRESULT hrc2 = runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine); ComAssertComRC(hrc2); } return hrc; }
STDMETHODIMP GuestDirectory::Read(IFsObjInfo **aInfo) { #ifndef VBOX_WITH_GUEST_CONTROL ReturnComNotImplemented(); #else LogFlowThisFuncEnter(); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); ComObjPtr<GuestProcess> pProcess = mData.mProcess; Assert(!pProcess.isNull()); GuestProcessStreamBlock streamBlock; GuestFsObjData objData; int rc = parseData(streamBlock); if ( RT_FAILURE(rc) || streamBlock.IsEmpty()) /* More data needed. */ { rc = pProcess->waitForStart(30 * 1000 /* 30s timeout */); } if (RT_SUCCESS(rc)) { BYTE byBuf[_64K]; size_t cbRead = 0; /** @todo Merge with GuestSession::queryFileInfoInternal. */ for (;RT_SUCCESS(rc);) { GuestProcessWaitResult waitRes; rc = pProcess->waitFor( ProcessWaitForFlag_Terminate | ProcessWaitForFlag_StdOut, 30 * 1000 /* Timeout */, waitRes); if ( RT_FAILURE(rc) || waitRes.mResult == ProcessWaitResult_Terminate || waitRes.mResult == ProcessWaitResult_Error || waitRes.mResult == ProcessWaitResult_Timeout) { if (RT_FAILURE(waitRes.mRC)) rc = waitRes.mRC; break; } rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf), 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf), &cbRead); if (RT_FAILURE(rc)) break; if (cbRead) { AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); rc = mData.mStream.AddData(byBuf, cbRead); if (RT_FAILURE(rc)) break; LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64, cbStreamOut=%RU32\n", rc, cbRead, mData.mStream.GetSize())); rc = parseData(streamBlock); if (RT_SUCCESS(rc)) { /* Parsing the current stream block succeeded so * we don't need more at the moment. */ break; } } } LogFlowThisFunc(("Reading done with rc=%Rrc, cbRead=%RU64, cbStream=%RU32\n", rc, cbRead, mData.mStream.GetSize())); if (RT_SUCCESS(rc)) { rc = parseData(streamBlock); if (rc == VERR_NO_DATA) /* Since this is the last parsing call, this is ok. */ rc = VINF_SUCCESS; } /* * Note: The guest process can still be around to serve the next * upcoming stream block next time. */ if (RT_SUCCESS(rc)) { /** @todo Move into common function. */ ProcessStatus_T procStatus = ProcessStatus_Undefined; LONG exitCode = 0; HRESULT hr2 = pProcess->COMGETTER(Status(&procStatus)); ComAssertComRC(hr2); hr2 = pProcess->COMGETTER(ExitCode(&exitCode)); ComAssertComRC(hr2); if ( ( procStatus != ProcessStatus_Started && procStatus != ProcessStatus_Paused && procStatus != ProcessStatus_Terminating ) && exitCode != 0) { rc = VERR_ACCESS_DENIED; } } } if (RT_SUCCESS(rc)) { if (streamBlock.GetCount()) /* Did we get content? */ { rc = objData.FromLs(streamBlock); if (RT_FAILURE(rc)) rc = VERR_PATH_NOT_FOUND; if (RT_SUCCESS(rc)) { /* Create the object. */ ComObjPtr<GuestFsObjInfo> pFsObjInfo; HRESULT hr2 = pFsObjInfo.createObject(); if (FAILED(hr2)) rc = VERR_COM_UNEXPECTED; if (RT_SUCCESS(rc)) rc = pFsObjInfo->init(objData); if (RT_SUCCESS(rc)) { /* Return info object to the caller. */ hr2 = pFsObjInfo.queryInterfaceTo(aInfo); if (FAILED(hr2)) rc = VERR_COM_UNEXPECTED; } } } else { /* Nothing to read anymore. Tell the caller. */ rc = VERR_NO_MORE_FILES; } } HRESULT hr = S_OK; if (RT_FAILURE(rc)) /** @todo Add more errors here. */ { switch (rc) { case VERR_ACCESS_DENIED: hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Unable to read / access denied"), mData.mName.c_str()); break; case VERR_PATH_NOT_FOUND: hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Path not found"), mData.mName.c_str()); break; case VERR_NO_MORE_FILES: hr = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No more entries for directory \"%s\""), mData.mName.c_str()); break; default: hr = setError(VBOX_E_IPRT_ERROR, tr("Error while reading directory \"%s\": %Rrc\n"), mData.mName.c_str(), rc); break; } } LogFlowFuncLeaveRC(rc); return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ }