/** * Common worker for the debug and normal APIs. * * @returns VINF_SUCCESS if entered successfully. * @returns rcBusy when encountering a busy critical section in GC/R0. * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * * @param pCritSect The PDM critical section to enter. * @param rcBusy The status code to return when we're in GC or R0 * and the section is busy. */ DECL_FORCE_INLINE(int) pdmCritSectEnter(PPDMCRITSECT pCritSect, int rcBusy, PCRTLOCKVALSRCPOS pSrcPos) { Assert(pCritSect->s.Core.cNestings < 8); /* useful to catch incorrect locking */ Assert(pCritSect->s.Core.cNestings >= 0); /* * If the critical section has already been destroyed, then inform the caller. */ AssertMsgReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, ("%p %RX32\n", pCritSect, pCritSect->s.Core.u32Magic), VERR_SEM_DESTROYED); /* * See if we're lucky. */ /* NOP ... */ if (pCritSect->s.Core.fFlags & RTCRITSECT_FLAGS_NOP) return VINF_SUCCESS; RTNATIVETHREAD hNativeSelf = pdmCritSectGetNativeSelf(pCritSect); /* ... not owned ... */ if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, 0, -1)) return pdmCritSectEnterFirst(pCritSect, hNativeSelf, pSrcPos); /* ... or nested. */ if (pCritSect->s.Core.NativeThreadOwner == hNativeSelf) { ASMAtomicIncS32(&pCritSect->s.Core.cLockers); ASMAtomicIncS32(&pCritSect->s.Core.cNestings); Assert(pCritSect->s.Core.cNestings > 1); return VINF_SUCCESS; } /* * Spin for a bit without incrementing the counter. */ /** @todo Move this to cfgm variables since it doesn't make sense to spin on UNI * cpu systems. */ int32_t cSpinsLeft = CTX_SUFF(PDMCRITSECT_SPIN_COUNT_); while (cSpinsLeft-- > 0) { if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, 0, -1)) return pdmCritSectEnterFirst(pCritSect, hNativeSelf, pSrcPos); ASMNopPause(); /** @todo Should use monitor/mwait on e.g. &cLockers here, possibly with a cli'ed pendingpreemption check up front using sti w/ instruction fusing for avoiding races. Hmm ... This is assuming the other party is actually executing code on another CPU ... which we could keep track of if we wanted. */ } #ifdef IN_RING3 /* * Take the slow path. */ NOREF(rcBusy); return pdmR3R0CritSectEnterContended(pCritSect, hNativeSelf, pSrcPos); #else # ifdef IN_RING0 /** @todo If preemption is disabled it means we're in VT-x/AMD-V context * and would be better off switching out of that while waiting for * the lock. Several of the locks jumps back to ring-3 just to * get the lock, the ring-3 code will then call the kernel to do * the lock wait and when the call return it will call ring-0 * again and resume via in setjmp style. Not very efficient. */ # if 0 if (ASMIntAreEnabled()) /** @todo this can be handled as well by changing * callers not prepared for longjmp/blocking to * use PDMCritSectTryEnter. */ { /* * Leave HM context while waiting if necessary. */ int rc; if (RTThreadPreemptIsEnabled(NIL_RTTHREAD)) { STAM_REL_COUNTER_ADD(&pCritSect->s.StatContentionRZLock, 1000000); rc = pdmR3R0CritSectEnterContended(pCritSect, hNativeSelf, pSrcPos); } else { STAM_REL_COUNTER_ADD(&pCritSect->s.StatContentionRZLock, 1000000000); PVM pVM = pCritSect->s.CTX_SUFF(pVM); PVMCPU pVCpu = VMMGetCpu(pVM); HMR0Leave(pVM, pVCpu); RTThreadPreemptRestore(NIL_RTTHREAD, XXX); rc = pdmR3R0CritSectEnterContended(pCritSect, hNativeSelf, pSrcPos); RTThreadPreemptDisable(NIL_RTTHREAD, XXX); HMR0Enter(pVM, pVCpu); } return rc; } # else /* * We preemption hasn't been disabled, we can block here in ring-0. */ if ( RTThreadPreemptIsEnabled(NIL_RTTHREAD) && ASMIntAreEnabled()) return pdmR3R0CritSectEnterContended(pCritSect, hNativeSelf, pSrcPos); # endif #endif /* IN_RING0 */ STAM_REL_COUNTER_INC(&pCritSect->s.StatContentionRZLock); /* * Call ring-3 to acquire the critical section? */ if (rcBusy == VINF_SUCCESS) { PVM pVM = pCritSect->s.CTX_SUFF(pVM); AssertPtr(pVM); PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu); return VMMRZCallRing3(pVM, pVCpu, VMMCALLRING3_PDM_CRIT_SECT_ENTER, MMHyperCCToR3(pVM, pCritSect)); } /* * Return busy. */ LogFlow(("PDMCritSectEnter: locked => R3 (%Rrc)\n", rcBusy)); return rcBusy; #endif /* !IN_RING3 */ }
/** * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug. * * @returns VBox status code. * @param pThis The event semaphore. * @param fFlags See RTSemEventMultiWaitEx. * @param uTimeout See RTSemEventMultiWaitEx. * @param pSrcPos The source code position of the wait. */ static int rtR0SemEventMultiLnxWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout, PCRTLOCKVALSRCPOS pSrcPos) { uint32_t fOrgStateAndGen; int rc; /* * Validate the input. */ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER); rtR0SemEventMultiLnxRetain(pThis); /* * Is the event already signalled or do we have to wait? */ fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen); if (fOrgStateAndGen & RTSEMEVENTMULTILNX_STATE_MASK) rc = VINF_SUCCESS; else { /* * We have to wait. */ RTR0SEMLNXWAIT Wait; rc = rtR0SemLnxWaitInit(&Wait, fFlags, uTimeout, &pThis->Head); if (RT_SUCCESS(rc)) { IPRT_DEBUG_SEMS_STATE(pThis, 'E'); for (;;) { /* The destruction test. */ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)) rc = VERR_SEM_DESTROYED; else { rtR0SemLnxWaitPrepare(&Wait); /* Check the exit conditions. */ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)) rc = VERR_SEM_DESTROYED; else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen) rc = VINF_SUCCESS; else if (rtR0SemLnxWaitHasTimedOut(&Wait)) rc = VERR_TIMEOUT; else if (rtR0SemLnxWaitWasInterrupted(&Wait)) rc = VERR_INTERRUPTED; else { /* Do the wait and then recheck the conditions. */ rtR0SemLnxWaitDoIt(&Wait); continue; } } break; } rtR0SemLnxWaitDelete(&Wait); IPRT_DEBUG_SEMS_STATE_RC(pThis, 'E', rc); } } rtR0SemEventMultiLnxRelease(pThis); return rc; }
RTDECL(int) RTMpNotificationRegister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser) { PRTMPNOTIFYREG pCur; PRTMPNOTIFYREG pNew; /* * Validation. */ AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER); AssertReturn(g_hRTMpNotifySpinLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER); RT_ASSERT_PREEMPTIBLE(); RTSpinlockAcquire(g_hRTMpNotifySpinLock); for (pCur = g_pRTMpCallbackHead; pCur; pCur = pCur->pNext) if ( pCur->pvUser == pvUser && pCur->pfnCallback == pfnCallback) break; RTSpinlockRelease(g_hRTMpNotifySpinLock); AssertMsgReturn(!pCur, ("pCur=%p pfnCallback=%p pvUser=%p\n", pCur, pfnCallback, pvUser), VERR_ALREADY_EXISTS); /* * Allocate a new record and attempt to insert it. */ pNew = (PRTMPNOTIFYREG)RTMemAlloc(sizeof(*pNew)); if (!pNew) return VERR_NO_MEMORY; pNew->pNext = NULL; pNew->pfnCallback = pfnCallback; pNew->pvUser = pvUser; memset(&pNew->bmDone[0], 0xff, sizeof(pNew->bmDone)); RTSpinlockAcquire(g_hRTMpNotifySpinLock); pCur = g_pRTMpCallbackHead; if (!pCur) g_pRTMpCallbackHead = pNew; else { for (pCur = g_pRTMpCallbackHead; ; pCur = pCur->pNext) if ( pCur->pvUser == pvUser && pCur->pfnCallback == pfnCallback) break; else if (!pCur->pNext) { pCur->pNext = pNew; pCur = NULL; break; } } ASMAtomicIncU32(&g_iRTMpGeneration); RTSpinlockRelease(g_hRTMpNotifySpinLock); /* duplicate? */ if (pCur) { RTMemFree(pCur); AssertMsgFailedReturn(("pCur=%p pfnCallback=%p pvUser=%p\n", pCur, pfnCallback, pvUser), VERR_ALREADY_EXISTS); } return VINF_SUCCESS; }
/** * Runs all the filters on the specified device. * * All filters mean global and active VM, with the exception of those * belonging to \a aMachine. If a global ignore filter matched or if * none of the filters matched, the device will be released back to * the host. * * The device calling us here will be in the HeldByProxy, Unused, or * Capturable state. The caller is aware that locks held might have * to be abandond because of IPC and that the device might be in * almost any state upon return. * * * @returns COM status code (only parameter & state checks will fail). * @param aDevice The USB device to apply filters to. * @param aIgnoreMachine The machine to ignore filters from (we've just * detached the device from this machine). * * @note The caller is expected to own no locks. */ HRESULT USBProxyService::runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, SessionMachine *aIgnoreMachine) { LogFlowThisFunc(("{%s} ignoring=%p\n", aDevice->i_getName().c_str(), aIgnoreMachine)); /* * Verify preconditions. */ AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL); AssertReturn(!aDevice->isWriteLockOnCurrentThread(), E_FAIL); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS); AssertMsgReturn(aDevice->i_isCapturableOrHeld(), ("{%s} %s\n", aDevice->i_getName().c_str(), aDevice->i_getStateName()), E_FAIL); /* * Get the lists we'll iterate. */ Host::USBDeviceFilterList globalFilters; mHost->i_getUSBFilters(&globalFilters); /* * Run global filters filters first. */ bool fHoldIt = false; for (Host::USBDeviceFilterList::const_iterator it = globalFilters.begin(); it != globalFilters.end(); ++it) { AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS); const HostUSBDeviceFilter::Data &data = (*it)->i_getData(); if (aDevice->i_isMatch(data)) { USBDeviceFilterAction_T action = USBDeviceFilterAction_Null; (*it)->COMGETTER(Action)(&action); if (action == USBDeviceFilterAction_Ignore) { /* * Release the device to the host and we're done. */ filterLock.release(); devLock.release(); alock.release(); aDevice->i_requestReleaseToHost(); return S_OK; } if (action == USBDeviceFilterAction_Hold) { /* * A device held by the proxy needs to be subjected * to the machine filters. */ fHoldIt = true; break; } AssertMsgFailed(("action=%d\n", action)); } } globalFilters.clear(); /* * Run the per-machine filters. */ for (SessionMachinesList::const_iterator it = llOpenedMachines.begin(); it != llOpenedMachines.end(); ++it) { ComObjPtr<SessionMachine> pMachine = *it; /* Skip the machine the device was just detached from. */ if ( aIgnoreMachine && pMachine == aIgnoreMachine) continue; /* runMachineFilters takes care of checking the machine state. */ devLock.release(); alock.release(); if (runMachineFilters(pMachine, aDevice)) { LogFlowThisFunc(("{%s} attached to %p\n", aDevice->i_getName().c_str(), (void *)pMachine)); return S_OK; } alock.acquire(); devLock.acquire(); } /* * No matching machine, so request hold or release depending * on global filter match. */ devLock.release(); alock.release(); if (fHoldIt) aDevice->i_requestHold(); else aDevice->i_requestReleaseToHost(); return S_OK; }
RTDECL(int) RTFileMove(const char *pszSrc, const char *pszDst, unsigned fMove) { /* * Validate input. */ AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER); AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER); AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER); AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER); AssertMsgReturn(!(fMove & ~RTFILEMOVE_FLAGS_REPLACE), ("%#x\n", fMove), VERR_INVALID_PARAMETER); /* * Try RTFileRename first. */ Assert(RTPATHRENAME_FLAGS_REPLACE == RTFILEMOVE_FLAGS_REPLACE); unsigned fRename = fMove; int rc = RTFileRename(pszSrc, pszDst, fRename); if (rc == VERR_NOT_SAME_DEVICE) { const char *pszDelete = NULL; /* * The source and target are not on the same device, darn. * We'll try open both ends and perform a copy. */ RTFILE FileSrc; rc = RTFileOpen(&FileSrc, pszSrc, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN); if (RT_SUCCESS(rc)) { RTFILE FileDst; rc = RTFileOpen(&FileDst, pszDst, RTFILE_O_WRITE | RTFILE_O_DENY_ALL | RTFILE_O_CREATE_REPLACE); if (RT_SUCCESS(rc)) { rc = RTFileCopyByHandles(FileSrc, FileDst); if (RT_SUCCESS(rc)) pszDelete = pszSrc; else { pszDelete = pszDst; Log(("RTFileMove('%s', '%s', %#x): copy failed, rc=%Rrc\n", pszSrc, pszDst, fMove, rc)); } /* try delete without closing, and could perhaps avoid some trouble */ int rc2 = RTFileDelete(pszDelete); if (RT_SUCCESS(rc2)) pszDelete = NULL; RTFileClose(FileDst); } else Log(("RTFileMove('%s', '%s', %#x): failed to create destination, rc=%Rrc\n", pszSrc, pszDst, fMove, rc)); RTFileClose(FileSrc); } else Log(("RTFileMove('%s', '%s', %#x): failed to open source, rc=%Rrc\n", pszSrc, pszDst, fMove, rc)); /* if we failed to close it while open, close it now */ if (pszDelete) { int rc2 = RTFileDelete(pszDelete); if (RT_FAILURE(rc2)) Log(("RTFileMove('%s', '%s', %#x): failed to delete '%s', rc2=%Rrc (rc=%Rrc)\n", pszSrc, pszDst, fMove, pszDelete, rc2, rc)); } } LogFlow(("RTDirRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n", pszSrc, pszSrc, pszDst, pszDst, fMove, rc)); return rc; }
/** * Construct a block driver instance. * * @copydoc FNPDMDRVCONSTRUCT */ static DECLCALLBACK(int) drvscsiConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { int rc = VINF_SUCCESS; PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI); LogFlowFunc(("pDrvIns=%#p pCfg=%#p\n", pDrvIns, pCfg)); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); /* * Initialize the instance data. */ pThis->pDrvIns = pDrvIns; pThis->ISCSIConnector.pfnSCSIRequestSend = drvscsiRequestSend; pDrvIns->IBase.pfnQueryInterface = drvscsiQueryInterface; pThis->IPort.pfnQueryDeviceLocation = drvscsiQueryDeviceLocation; pThis->IPortAsync.pfnTransferCompleteNotify = drvscsiTransferCompleteNotify; pThis->hQueueRequests = NIL_RTREQQUEUE; /* Query the SCSI port interface above. */ pThis->pDevScsiPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMISCSIPORT); AssertMsgReturn(pThis->pDevScsiPort, ("Missing SCSI port interface above\n"), VERR_PDM_MISSING_INTERFACE); /* Query the optional LED interface above. */ pThis->pLedPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS); if (pThis->pLedPort != NULL) { /* Get The Led. */ rc = pThis->pLedPort->pfnQueryStatusLed(pThis->pLedPort, 0, &pThis->pLed); if (RT_FAILURE(rc)) pThis->pLed = &pThis->Led; } else pThis->pLed = &pThis->Led; /* * Validate and read configuration. */ if (!CFGMR3AreValuesValid(pCfg, "NonRotationalMedium\0Readonly\0")) return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, N_("SCSI configuration error: unknown option specified")); rc = CFGMR3QueryBoolDef(pCfg, "NonRotationalMedium", &pThis->fNonRotational, false); if (RT_FAILURE(rc)) return PDMDRV_SET_ERROR(pDrvIns, rc, N_("SCSI configuration error: failed to read \"NonRotationalMedium\" as boolean")); rc = CFGMR3QueryBoolDef(pCfg, "Readonly", &pThis->fReadonly, false); if (RT_FAILURE(rc)) return PDMDRV_SET_ERROR(pDrvIns, rc, N_("SCSI configuration error: failed to read \"Readonly\" as boolean")); /* * Try attach driver below and query it's block interface. */ rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pThis->pDrvBase); AssertMsgReturn(RT_SUCCESS(rc), ("Attaching driver below failed rc=%Rrc\n", rc), rc); /* * Query the block and blockbios interfaces. */ pThis->pDrvBlock = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBLOCK); if (!pThis->pDrvBlock) { AssertMsgFailed(("Configuration error: No block interface!\n")); return VERR_PDM_MISSING_INTERFACE; } pThis->pDrvBlockBios = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBLOCKBIOS); if (!pThis->pDrvBlockBios) { AssertMsgFailed(("Configuration error: No block BIOS interface!\n")); return VERR_PDM_MISSING_INTERFACE; } pThis->pDrvMount = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMOUNT); /* Try to get the optional async block interface. */ pThis->pDrvBlockAsync = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBLOCKASYNC); PDMBLOCKTYPE enmType = pThis->pDrvBlock->pfnGetType(pThis->pDrvBlock); if (enmType != PDMBLOCKTYPE_HARD_DISK) return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_UNSUPPORTED_BLOCK_TYPE, RT_SRC_POS, N_("Only hard disks are currently supported as SCSI devices (enmType=%d)"), enmType); /* Create VSCSI device and LUN. */ pThis->VScsiIoCallbacks.pfnVScsiLunMediumGetSize = drvscsiGetSize; pThis->VScsiIoCallbacks.pfnVScsiLunReqTransferEnqueue = drvscsiReqTransferEnqueue; pThis->VScsiIoCallbacks.pfnVScsiLunGetFeatureFlags = drvscsiGetFeatureFlags; rc = VSCSIDeviceCreate(&pThis->hVScsiDevice, drvscsiVScsiReqCompleted, pThis); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create VSCSI device rc=%Rrc\n"), rc); rc = VSCSILunCreate(&pThis->hVScsiLun, VSCSILUNTYPE_SBC, &pThis->VScsiIoCallbacks, pThis); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create VSCSI LUN rc=%Rrc\n"), rc); rc = VSCSIDeviceLunAttach(pThis->hVScsiDevice, pThis->hVScsiLun, 0); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to attached the LUN to the SCSI device\n"), rc); /* Register statistics counter. */ /** @todo aeichner: Find a way to put the instance number of the attached * controller device when we support more than one controller of the same type. * At the moment we have the 0 hardcoded. */ PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data read.", "/Devices/SCSI0/%d/ReadBytes", pDrvIns->iInstance); PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data written.", "/Devices/SCSI0/%d/WrittenBytes", pDrvIns->iInstance); pThis->StatIoDepth = 0; PDMDrvHlpSTAMRegisterF(pDrvIns, (void *)&pThis->StatIoDepth, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of active tasks.", "/Devices/SCSI0/%d/IoDepth", pDrvIns->iInstance); if (!pThis->pDrvBlockAsync) { /* Create request queue. */ rc = RTReqQueueCreate(&pThis->hQueueRequests); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create request queue rc=%Rrc\n"), rc); /* Create I/O thread. */ rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pAsyncIOThread, pThis, drvscsiAsyncIOLoop, drvscsiAsyncIOLoopWakeup, 0, RTTHREADTYPE_IO, "SCSI async IO"); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create async I/O thread rc=%Rrc\n"), rc); LogRel(("SCSI#%d: using normal I/O\n", pDrvIns->iInstance)); } else LogRel(("SCSI#%d: using async I/O\n", pDrvIns->iInstance)); if ( pThis->pDrvBlock->pfnDiscard || ( pThis->pDrvBlockAsync && pThis->pDrvBlockAsync->pfnStartDiscard)) LogRel(("SCSI#%d: Enabled UNMAP support\n")); return VINF_SUCCESS; }
/** * Construct a status driver instance. * * @copydoc FNPDMDRVCONSTRUCT */ DECLCALLBACK(int) VMStatus::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { PDRVMAINSTATUS pData = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS); LogFlow(("VMStatus::drvConstruct: iInstance=%d\n", pDrvIns->iInstance)); /* * Validate configuration. */ if (!CFGMR3AreValuesValid(pCfg, "papLeds\0First\0Last\0")) return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES; AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER, ("Configuration error: Not possible to attach anything to this driver!\n"), VERR_PDM_DRVINS_NO_ATTACH); /* * Data. */ pDrvIns->IBase.pfnQueryInterface = VMStatus::drvQueryInterface; pData->ILedConnectors.pfnUnitChanged = VMStatus::drvUnitChanged; /* * Read config. */ int rc = CFGMR3QueryPtr(pCfg, "papLeds", (void **)&pData->papLeds); if (RT_FAILURE(rc)) { AssertMsgFailed(("Configuration error: Failed to query the \"papLeds\" value! rc=%Rrc\n", rc)); return rc; } rc = CFGMR3QueryU32(pCfg, "First", &pData->iFirstLUN); if (rc == VERR_CFGM_VALUE_NOT_FOUND) pData->iFirstLUN = 0; else if (RT_FAILURE(rc)) { AssertMsgFailed(("Configuration error: Failed to query the \"First\" value! rc=%Rrc\n", rc)); return rc; } rc = CFGMR3QueryU32(pCfg, "Last", &pData->iLastLUN); if (rc == VERR_CFGM_VALUE_NOT_FOUND) pData->iLastLUN = 0; else if (RT_FAILURE(rc)) { AssertMsgFailed(("Configuration error: Failed to query the \"Last\" value! rc=%Rrc\n", rc)); return rc; } if (pData->iFirstLUN > pData->iLastLUN) { AssertMsgFailed(("Configuration error: Invalid unit range %u-%u\n", pData->iFirstLUN, pData->iLastLUN)); return VERR_GENERAL_FAILURE; } /* * Get the ILedPorts interface of the above driver/device and * query the LEDs we want. */ pData->pLedPorts = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS); AssertMsgReturn(pData->pLedPorts, ("Configuration error: No led ports interface above!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE); for (unsigned i = pData->iFirstLUN; i <= pData->iLastLUN; i++) VMStatus::drvUnitChanged(&pData->ILedConnectors, i); return VINF_SUCCESS; }
/** * Worker for RTSemEventWaitEx and RTSemEventWaitExDebug. * * @returns VBox status code. * @param pThis The event semaphore. * @param fFlags See RTSemEventWaitEx. * @param uTimeout See RTSemEventWaitEx. * @param pSrcPos The source code position of the wait. */ static int rtR0SemEventWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout, PCRTLOCKVALSRCPOS pSrcPos) { status_t status; int rc; int32 flags = 0; bigtime_t timeout; /* in microseconds */ /* * Validate the input. */ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER); if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE) timeout = B_INFINITE_TIMEOUT; else { if (fFlags & RTSEMWAIT_FLAGS_NANOSECS) timeout = uTimeout / 1000; else if (fFlags & RTSEMWAIT_FLAGS_MILLISECS) timeout = uTimeout * 1000; else return VERR_INVALID_PARAMETER; if (fFlags & RTSEMWAIT_FLAGS_RELATIVE) flags |= B_RELATIVE_TIMEOUT; else if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE) flags |= B_ABSOLUTE_TIMEOUT; else return VERR_INVALID_PARAMETER; } if (fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE) flags |= B_CAN_INTERRUPT; // likely not: //else // flags |= B_KILL_CAN_INTERRUPT; rtR0SemEventHkuRetain(pThis); status = acquire_sem_etc(pThis->SemId, 1, flags, timeout); switch (status) { case B_OK: rc = VINF_SUCCESS; break; case B_BAD_SEM_ID: rc = VERR_SEM_DESTROYED; break; case B_INTERRUPTED: rc = VERR_INTERRUPTED; break; case B_WOULD_BLOCK: /* fallthrough ? */ case B_TIMED_OUT: rc = VERR_TIMEOUT; break; default: rc = RTErrConvertFromHaikuKernReturn(status); break; } rtR0SemEventHkuRelease(pThis); return rc; }
/** * Adjusts and validates the flags. * * The adjustments are made according to the wishes specified using the RTFileSetForceFlags API. * * @returns IPRT status code. * @param pfOpen Pointer to the user specified flags on input. * Updated on successful return. * @internal */ int rtFileRecalcAndValidateFlags(uint64_t *pfOpen) { /* * Recalc. */ uint32_t fOpen = *pfOpen; switch (fOpen & RTFILE_O_ACCESS_MASK) { case RTFILE_O_READ: fOpen |= g_fOpenReadSet; fOpen &= ~g_fOpenReadMask; break; case RTFILE_O_WRITE: fOpen |= g_fOpenWriteSet; fOpen &= ~g_fOpenWriteMask; break; case RTFILE_O_READWRITE: fOpen |= g_fOpenReadWriteSet; fOpen &= ~g_fOpenReadWriteMask; break; default: AssertMsgFailed(("Invalid RW value, fOpen=%#llx\n", fOpen)); return VERR_INVALID_PARAMETER; } /* * Validate . */ AssertMsgReturn(fOpen & RTFILE_O_ACCESS_MASK, ("Missing RTFILE_O_READ/WRITE: fOpen=%#llx\n", fOpen), VERR_INVALID_PARAMETER); #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) AssertMsgReturn(!(fOpen & (~(uint64_t)RTFILE_O_VALID_MASK | RTFILE_O_NON_BLOCK)), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER); #else AssertMsgReturn(!(fOpen & ~(uint64_t)RTFILE_O_VALID_MASK), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER); #endif AssertMsgReturn((fOpen & (RTFILE_O_TRUNCATE | RTFILE_O_WRITE)) != RTFILE_O_TRUNCATE, ("%#llx\n", fOpen), VERR_INVALID_PARAMETER); switch (fOpen & RTFILE_O_ACTION_MASK) { case 0: /* temporarily */ AssertMsgFailed(("Missing RTFILE_O_OPEN/CREATE*! (continuable assertion)\n")); fOpen |= RTFILE_O_OPEN; break; case RTFILE_O_OPEN: AssertMsgReturn(!(RTFILE_O_NOT_CONTENT_INDEXED & fOpen), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER); case RTFILE_O_OPEN_CREATE: case RTFILE_O_CREATE: case RTFILE_O_CREATE_REPLACE: break; default: AssertMsgFailed(("Invalid action value: fOpen=%#llx\n", fOpen)); return VERR_INVALID_PARAMETER; } switch (fOpen & RTFILE_O_DENY_MASK) { case 0: /* temporarily */ AssertMsgFailed(("Missing RTFILE_O_DENY_*! (continuable assertion)\n")); fOpen |= RTFILE_O_DENY_NONE; break; case RTFILE_O_DENY_NONE: case RTFILE_O_DENY_READ: case RTFILE_O_DENY_WRITE: case RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ: case RTFILE_O_DENY_NOT_DELETE: case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READ: case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE: case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ: break; default: AssertMsgFailed(("Invalid deny value: fOpen=%#llx\n", fOpen)); return VERR_INVALID_PARAMETER; } /* done */ *pfOpen = fOpen; return VINF_SUCCESS; }
RTDECL(RTLDRARCH) RTLdrGetArch(RTLDRMOD hLdrMod) { AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRARCH_INVALID); PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod; return pMod->enmArch; }
RTDECL(RTLDRFMT) RTLdrGetFormat(RTLDRMOD hLdrMod) { AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRFMT_INVALID); PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod; return pMod->enmFormat; }
RTDECL(RTLDRENDIAN) RTLdrGetEndian(RTLDRMOD hLdrMod) { AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRENDIAN_INVALID); PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod; return pMod->enmEndian; }
RTDECL(RTLDRTYPE) RTLdrGetType(RTLDRMOD hLdrMod) { AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRTYPE_INVALID); PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod; return pMod->enmType; }
/** * Implements the timed wait. * * @returns See RTSemEventMultiWaitEx * @param pThis The semaphore. * @param fFlags See RTSemEventMultiWaitEx. * @param uTimeout See RTSemEventMultiWaitEx. * @param pSrcPos The source position, can be NULL. */ static int rtSemEventMultiPosixWaitTimed(struct RTSEMEVENTMULTIINTERNAL *pThis, uint32_t fFlags, uint64_t uTimeout, PCRTLOCKVALSRCPOS pSrcPos) { /* * Convert uTimeout to a relative value in nano seconds. */ if (fFlags & RTSEMWAIT_FLAGS_MILLISECS) uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000) ? uTimeout * UINT32_C(1000000) : UINT64_MAX; if (uTimeout == UINT64_MAX) /* unofficial way of indicating an indefinite wait */ return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos); uint64_t uAbsTimeout = uTimeout; if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE) { uint64_t u64Now = RTTimeSystemNanoTS(); uTimeout = uTimeout > u64Now ? uTimeout - u64Now : 0; } if (uTimeout == 0) return rtSemEventMultiPosixWaitPoll(pThis); /* * Get current time and calc end of deadline relative to real time. */ struct timespec ts = {0,0}; if (!pThis->fMonotonicClock) { #if defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU) struct timeval tv = {0,0}; gettimeofday(&tv, NULL); ts.tv_sec = tv.tv_sec; ts.tv_nsec = tv.tv_usec * 1000; #else clock_gettime(CLOCK_REALTIME, &ts); #endif struct timespec tsAdd; tsAdd.tv_nsec = uTimeout % UINT32_C(1000000000); tsAdd.tv_sec = uTimeout / UINT32_C(1000000000); if ( sizeof(ts.tv_sec) < sizeof(uint64_t) && ( uTimeout > UINT64_C(1000000000) * UINT32_MAX || (uint64_t)ts.tv_sec + tsAdd.tv_sec >= UINT32_MAX) ) return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos); ts.tv_sec += tsAdd.tv_sec; ts.tv_nsec += tsAdd.tv_nsec; if (ts.tv_nsec >= 1000000000) { ts.tv_nsec -= 1000000000; ts.tv_sec++; } /* Note! No need to complete uAbsTimeout for RTSEMWAIT_FLAGS_RELATIVE in this path. */ } else { /* ASSUMES RTTimeSystemNanoTS() == RTTimeNanoTS() == clock_gettime(CLOCK_MONOTONIC). */ if (fFlags & RTSEMWAIT_FLAGS_RELATIVE) uAbsTimeout += RTTimeSystemNanoTS(); if ( sizeof(ts.tv_sec) < sizeof(uint64_t) && uAbsTimeout > UINT64_C(1000000000) * UINT32_MAX) return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos); ts.tv_nsec = uAbsTimeout % UINT32_C(1000000000); ts.tv_sec = uAbsTimeout / UINT32_C(1000000000); } /* * To business! */ /* take mutex */ int rc = pthread_mutex_lock(&pThis->Mutex); AssertMsgReturn(rc == 0, ("rc=%d pThis=%p\n", rc, pThis), RTErrConvertFromErrno(rc)); NOREF(rc); ASMAtomicIncU32(&pThis->cWaiters); for (;;) { /* check state. */ uint32_t const u32State = pThis->u32State; if (u32State != EVENTMULTI_STATE_NOT_SIGNALED) { ASMAtomicDecU32(&pThis->cWaiters); rc = pthread_mutex_unlock(&pThis->Mutex); AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", pThis, rc)); return u32State == EVENTMULTI_STATE_SIGNALED ? VINF_SUCCESS : VERR_SEM_DESTROYED; } /* wait */ #ifdef RTSEMEVENTMULTI_STRICT RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt(); if (pThis->fEverHadSignallers) { rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false, uTimeout / UINT32_C(1000000), RTTHREADSTATE_EVENT_MULTI, true); if (RT_FAILURE(rc)) { ASMAtomicDecU32(&pThis->cWaiters); pthread_mutex_unlock(&pThis->Mutex); return rc; } } #else RTTHREAD hThreadSelf = RTThreadSelf(); #endif RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true); rc = pthread_cond_timedwait(&pThis->Cond, &pThis->Mutex, &ts); RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI); if ( rc && ( rc != EINTR /* according to SuS this function shall not return EINTR, but linux man page says differently. */ || (fFlags & RTSEMWAIT_FLAGS_NORESUME)) ) { AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", pThis, rc)); ASMAtomicDecU32(&pThis->cWaiters); int rc2 = pthread_mutex_unlock(&pThis->Mutex); AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", pThis, rc2)); NOREF(rc2); return RTErrConvertFromErrno(rc); } /* check the absolute deadline. */ } }
/** * Construct a display driver instance. * * @copydoc FNPDMDRVCONSTRUCT */ DECLCALLBACK(int) Display::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { PDRVMAINDISPLAY pData = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY); LogFlow(("Display::drvConstruct: iInstance=%d\n", pDrvIns->iInstance)); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); /* * Validate configuration. */ if (!CFGMR3AreValuesValid(pCfg, "Object\0")) return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES; AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER, ("Configuration error: Not possible to attach anything to this driver!\n"), VERR_PDM_DRVINS_NO_ATTACH); /* * Init Interfaces. */ pDrvIns->IBase.pfnQueryInterface = Display::drvQueryInterface; pData->Connector.pfnResize = Display::displayResizeCallback; pData->Connector.pfnUpdateRect = Display::displayUpdateCallback; pData->Connector.pfnRefresh = Display::displayRefreshCallback; pData->Connector.pfnReset = Display::displayResetCallback; pData->Connector.pfnLFBModeChange = Display::displayLFBModeChangeCallback; pData->Connector.pfnProcessAdapterData = Display::displayProcessAdapterDataCallback; pData->Connector.pfnProcessDisplayData = Display::displayProcessDisplayDataCallback; /* * Get the IDisplayPort interface of the above driver/device. */ pData->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYPORT); if (!pData->pUpPort) { AssertMsgFailed(("Configuration error: No display port interface above!\n")); return VERR_PDM_MISSING_INTERFACE_ABOVE; } /* * Get the Display object pointer and update the mpDrv member. */ void *pv; int rc = CFGMR3QueryPtr(pCfg, "Object", &pv); if (RT_FAILURE(rc)) { AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc)); return rc; } pData->pDisplay = (Display *)pv; /** @todo Check this cast! */ pData->pDisplay->mpDrv = pData; /* * If there is a Framebuffer, we have to update our display information */ if (pData->pDisplay->mFramebuffer) pData->pDisplay->updateDisplayData(); /* * Start periodic screen refreshes */ pData->pUpPort->pfnSetRefreshRate(pData->pUpPort, 50); return VINF_SUCCESS; }
/** * Copies a file given the handles to both files and * provide progress callbacks. * * @returns VBox Status code. * * @param FileSrc The source file. The file position is unaltered. * @param FileDst The destination file. * On successful returns the file position is at the end of the file. * On failures the file position and size is undefined. * @param pfnProgress Pointer to callback function for reporting progress. * @param pvUser User argument to pass to pfnProgress along with the completion percentage. */ RTDECL(int) RTFileCopyByHandlesEx(RTFILE FileSrc, RTFILE FileDst, PFNRTPROGRESS pfnProgress, void *pvUser) { /* * Validate input. */ AssertMsgReturn(RTFileIsValid(FileSrc), ("FileSrc=%RTfile\n", FileSrc), VERR_INVALID_PARAMETER); AssertMsgReturn(RTFileIsValid(FileDst), ("FileDst=%RTfile\n", FileDst), VERR_INVALID_PARAMETER); AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER); /* * Save file offset. */ RTFOFF offSrcSaved; int rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_CURRENT, (uint64_t *)&offSrcSaved); if (RT_FAILURE(rc)) return rc; /* * Get the file size. */ RTFOFF cbSrc; rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_END, (uint64_t *)&cbSrc); if (RT_FAILURE(rc)) return rc; /* * Allocate buffer. */ size_t cbBuf; uint8_t *pbBufFree = NULL; uint8_t *pbBuf; if (cbSrc < _512K) { cbBuf = 8*_1K; pbBuf = (uint8_t *)alloca(cbBuf); } else { cbBuf = _128K; pbBuf = pbBufFree = (uint8_t *)RTMemTmpAlloc(cbBuf); } if (pbBuf) { /* * Seek to the start of each file * and set the size of the destination file. */ rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_SUCCESS(rc)) { rc = RTFileSeek(FileDst, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_SUCCESS(rc)) rc = RTFileSetSize(FileDst, cbSrc); if (RT_SUCCESS(rc) && pfnProgress) rc = pfnProgress(0, pvUser); if (RT_SUCCESS(rc)) { /* * Copy loop. */ unsigned uPercentage = 0; RTFOFF off = 0; RTFOFF cbPercent = cbSrc / 100; RTFOFF offNextPercent = cbPercent; while (off < cbSrc) { /* copy block */ RTFOFF cbLeft = cbSrc - off; size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft; rc = RTFileRead(FileSrc, pbBuf, cbBlock, NULL); if (RT_FAILURE(rc)) break; rc = RTFileWrite(FileDst, pbBuf, cbBlock, NULL); if (RT_FAILURE(rc)) break; /* advance */ off += cbBlock; if (pfnProgress && offNextPercent < off) { while (offNextPercent < off) { uPercentage++; offNextPercent += cbPercent; } rc = pfnProgress(uPercentage, pvUser); if (RT_FAILURE(rc)) break; } } #if 0 /* * Copy OS specific data (EAs and stuff). */ rtFileCopyOSStuff(FileSrc, FileDst); #endif /* 100% */ if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc)) rc = pfnProgress(100, pvUser); } } RTMemTmpFree(pbBufFree); } else rc = VERR_NO_MEMORY; /* * Restore source position. */ RTFileSeek(FileSrc, offSrcSaved, RTFILE_SEEK_BEGIN, NULL); return rc; }
int HostDnsServiceLinux::monitorWorker() { AutoNotify a; int rc = socketpair(AF_LOCAL, SOCK_DGRAM, 0, g_DnsMonitorStop); AssertMsgReturn(rc == 0, ("socketpair: failed (%d: %s)\n", errno, strerror(errno)), E_FAIL); FileDescriptor stopper0(g_DnsMonitorStop[0]); FileDescriptor stopper1(g_DnsMonitorStop[1]); pollfd polls[2]; RT_ZERO(polls); polls[0].fd = a.fileDescriptor(); polls[0].events = POLLIN; polls[1].fd = g_DnsMonitorStop[1]; polls[1].events = POLLIN; monitorThreadInitializationDone(); int wd[2]; wd[0] = wd[1] = -1; /* inotify inialization */ wd[0] = inotify_add_watch(a.fileDescriptor(), g_ResolvConfFullPath.c_str(), IN_CLOSE_WRITE|IN_DELETE_SELF); /** * If /etc/resolv.conf exists we want to listen for movements: because * # mv /etc/resolv.conf ... * won't arm IN_DELETE_SELF on wd[0] instead it will fire IN_MOVE_FROM on wd[1]. * * Because on some distributions /etc/resolv.conf is link, wd[0] can't detect deletion, * it's recognizible on directory level (wd[1]) only. */ wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(), wd[0] == -1 ? IN_MOVED_TO|IN_CREATE : IN_MOVED_FROM|IN_DELETE); struct InotifyEventWithName combo; while(true) { rc = poll(polls, 2, -1); if (rc == -1) continue; AssertMsgReturn( ((polls[0].revents & (POLLERR|POLLNVAL)) == 0) && ((polls[1].revents & (POLLERR|POLLNVAL)) == 0), ("Debug Me"), VERR_INTERNAL_ERROR); if (polls[1].revents & POLLIN) return VINF_SUCCESS; /* time to shutdown */ if (polls[0].revents & POLLIN) { RT_ZERO(combo); ssize_t r = read(polls[0].fd, static_cast<void *>(&combo), sizeof(combo)); NOREF(r); if (combo.e.wd == wd[0]) { if (combo.e.mask & IN_CLOSE_WRITE) { readResolvConf(); } else if (combo.e.mask & IN_DELETE_SELF) { inotify_rm_watch(a.fileDescriptor(), wd[0]); /* removes file watcher */ inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(), IN_MOVED_TO|IN_CREATE); /* alter folder watcher */ } else if (combo.e.mask & IN_IGNORED) { wd[0] = -1; /* we want receive any events on this watch */ } else { /** * It shouldn't happen, in release we will just ignore in debug * we will have to chance to look at into inotify_event */ AssertMsgFailed(("Debug Me!!!")); } } else if (combo.e.wd == wd[1]) { if ( combo.e.mask & IN_MOVED_FROM || combo.e.mask & IN_DELETE) { if (g_ResolvConf == combo.e.name) { /** * Our file has been moved so we should change watching mode. */ inotify_rm_watch(a.fileDescriptor(), wd[0]); wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(), IN_MOVED_TO|IN_CREATE); AssertMsg(wd[1] != -1, ("It shouldn't happen, further investigation is needed\n")); } } else { AssertMsg(combo.e.mask & (IN_MOVED_TO|IN_CREATE), ("%RX32 event isn't expected, we are waiting for IN_MOVED|IN_CREATE\n", combo.e.mask)); if (g_ResolvConf == combo.e.name) { AssertMsg(wd[0] == -1, ("We haven't removed file watcher first\n")); /* alter folder watcher*/ wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(), IN_MOVED_FROM|IN_DELETE); AssertMsg(wd[1] != -1, ("It shouldn't happen.\n")); wd[0] = inotify_add_watch(a.fileDescriptor(), g_ResolvConfFullPath.c_str(), IN_CLOSE_WRITE | IN_DELETE_SELF); AssertMsg(wd[0] != -1, ("Adding watcher to file (%s) has been failed!\n", g_ResolvConfFullPath.c_str())); /* Notify our listeners */ readResolvConf(); } } } else { /* It shouldn't happen */ AssertMsgFailed(("Shouldn't happen! Please debug me!")); } } } }
/** * Process events pending on this event queue, and wait up to given timeout, if * nothing is available. * * Must be called on same thread this event queue was created on. * * @param cMsTimeout The timeout specified as milliseconds. Use * RT_INDEFINITE_WAIT to wait till an event is posted on the * queue. * * @returns VBox status code * @retval VINF_SUCCESS if one or more messages was processed. * @retval VERR_TIMEOUT if cMsTimeout expired. * @retval VERR_INVALID_CONTEXT if called on the wrong thread. * @retval VERR_INTERRUPTED if interruptEventQueueProcessing was called. * On Windows will also be returned when WM_QUIT is encountered. * On Darwin this may also be returned when the native queue is * stopped or destroyed/finished. * @retval VINF_INTERRUPTED if the native system call was interrupted by a * an asynchronous event delivery (signal) or just felt like returning * out of bounds. On darwin it will also be returned if the queue is * stopped. */ int EventQueue::processEventQueue(RTMSINTERVAL cMsTimeout) { int rc; CHECK_THREAD_RET(VERR_INVALID_CONTEXT); #ifdef VBOX_WITH_XPCOM /* * Process pending events, if none are available and we're not in a * poll call, wait for some to appear. (We have to be a little bit * careful after waiting for the events since Darwin will process * them as part of the wait, while the XPCOM case will not.) * * Note! Unfortunately, WaitForEvent isn't interruptible with Ctrl-C, * while select() is. So we cannot use it for indefinite waits. */ rc = processPendingEvents(mEventQ); if ( rc == VERR_TIMEOUT && cMsTimeout > 0) { # ifdef RT_OS_DARWIN /** @todo check how Ctrl-C works on Darwin. */ rc = waitForEventsOnDarwin(cMsTimeout); if (rc == VERR_TIMEOUT) rc = processPendingEvents(mEventQ); # else // !RT_OS_DARWIN rc = waitForEventsOnXPCOM(mEventQ, cMsTimeout); if ( RT_SUCCESS(rc) || rc == VERR_TIMEOUT) rc = processPendingEvents(mEventQ); # endif // !RT_OS_DARWIN } if ( ( RT_SUCCESS(rc) || rc == VERR_INTERRUPTED || rc == VERR_TIMEOUT) && mInterrupted) { mInterrupted = false; rc = VERR_INTERRUPTED; } #else // !VBOX_WITH_XPCOM if (cMsTimeout == RT_INDEFINITE_WAIT) { BOOL fRet; MSG Msg; rc = VINF_SUCCESS; while ( rc != VERR_INTERRUPTED && (fRet = GetMessage(&Msg, NULL /*hWnd*/, WM_USER, WM_USER)) && fRet != -1) rc = EventQueue::dispatchMessageOnWindows(&Msg, rc); if (fRet == 0) rc = VERR_INTERRUPTED; else if (fRet == -1) rc = RTErrConvertFromWin32(GetLastError()); } else { rc = processPendingEvents(); if ( rc == VERR_TIMEOUT && cMsTimeout != 0) { DWORD rcW = MsgWaitForMultipleObjects(1, &mhThread, TRUE /*fWaitAll*/, cMsTimeout, QS_ALLINPUT); AssertMsgReturn(rcW == WAIT_TIMEOUT || rcW == WAIT_OBJECT_0, ("%d\n", rcW), VERR_INTERNAL_ERROR_4); rc = processPendingEvents(); } } #endif // !VBOX_WITH_XPCOM Assert(rc != VERR_TIMEOUT || cMsTimeout != RT_INDEFINITE_WAIT); return rc; }
/** * Construct a block driver instance. * * @copydoc FNPDMDRVCONSTRUCT */ static DECLCALLBACK(int) drvscsiConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { int rc = VINF_SUCCESS; PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI); LogFlowFunc(("pDrvIns=%#p pCfg=%#p\n", pDrvIns, pCfg)); PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); /* * Initialize the instance data. */ pThis->pDrvIns = pDrvIns; pThis->ISCSIConnector.pfnSCSIRequestSend = drvscsiRequestSend; pThis->ISCSIConnector.pfnQueryLUNType = drvscsiQueryLUNType; pDrvIns->IBase.pfnQueryInterface = drvscsiQueryInterface; pThis->IMountNotify.pfnMountNotify = drvscsiMountNotify; pThis->IMountNotify.pfnUnmountNotify = drvscsiUnmountNotify; pThis->IPort.pfnQueryDeviceLocation = drvscsiQueryDeviceLocation; pThis->IPortAsync.pfnTransferCompleteNotify = drvscsiTransferCompleteNotify; pThis->hQueueRequests = NIL_RTREQQUEUE; /* Query the SCSI port interface above. */ pThis->pDevScsiPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMISCSIPORT); AssertMsgReturn(pThis->pDevScsiPort, ("Missing SCSI port interface above\n"), VERR_PDM_MISSING_INTERFACE); /* Query the optional LED interface above. */ pThis->pLedPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS); if (pThis->pLedPort != NULL) { /* Get The Led. */ rc = pThis->pLedPort->pfnQueryStatusLed(pThis->pLedPort, 0, &pThis->pLed); if (RT_FAILURE(rc)) pThis->pLed = &pThis->Led; } else pThis->pLed = &pThis->Led; /* * Validate and read configuration. */ if (!CFGMR3AreValuesValid(pCfg, "NonRotationalMedium\0Readonly\0")) return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, N_("SCSI configuration error: unknown option specified")); rc = CFGMR3QueryBoolDef(pCfg, "NonRotationalMedium", &pThis->fNonRotational, false); if (RT_FAILURE(rc)) return PDMDRV_SET_ERROR(pDrvIns, rc, N_("SCSI configuration error: failed to read \"NonRotationalMedium\" as boolean")); rc = CFGMR3QueryBoolDef(pCfg, "Readonly", &pThis->fReadonly, false); if (RT_FAILURE(rc)) return PDMDRV_SET_ERROR(pDrvIns, rc, N_("SCSI configuration error: failed to read \"Readonly\" as boolean")); /* * Try attach driver below and query it's block interface. */ rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pThis->pDrvBase); AssertMsgReturn(RT_SUCCESS(rc), ("Attaching driver below failed rc=%Rrc\n", rc), rc); /* * Query the block and blockbios interfaces. */ pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMEDIA); if (!pThis->pDrvMedia) { AssertMsgFailed(("Configuration error: No block interface!\n")); return VERR_PDM_MISSING_INTERFACE; } pThis->pDrvMount = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMOUNT); /* Try to get the optional async block interface. */ pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMEDIAASYNC); PDMMEDIATYPE enmType = pThis->pDrvMedia->pfnGetType(pThis->pDrvMedia); VSCSILUNTYPE enmLunType; switch (enmType) { case PDMMEDIATYPE_HARD_DISK: enmLunType = VSCSILUNTYPE_SBC; break; case PDMMEDIATYPE_CDROM: case PDMMEDIATYPE_DVD: enmLunType = VSCSILUNTYPE_MMC; break; default: return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_UNSUPPORTED_BLOCK_TYPE, RT_SRC_POS, N_("Only hard disks and CD/DVD-ROMs are currently supported as SCSI devices (enmType=%d)"), enmType); } if ( ( enmType == PDMMEDIATYPE_DVD || enmType == PDMMEDIATYPE_CDROM) && !pThis->pDrvMount) { AssertMsgFailed(("Internal error: cdrom without a mountable interface\n")); return VERR_INTERNAL_ERROR; } /* Create VSCSI device and LUN. */ pThis->VScsiIoCallbacks.pfnVScsiLunMediumGetSize = drvscsiGetSize; pThis->VScsiIoCallbacks.pfnVScsiLunMediumGetSectorSize = drvscsiGetSectorSize; pThis->VScsiIoCallbacks.pfnVScsiLunReqTransferEnqueue = drvscsiReqTransferEnqueue; pThis->VScsiIoCallbacks.pfnVScsiLunGetFeatureFlags = drvscsiGetFeatureFlags; pThis->VScsiIoCallbacks.pfnVScsiLunMediumSetLock = drvscsiSetLock; rc = VSCSIDeviceCreate(&pThis->hVScsiDevice, drvscsiVScsiReqCompleted, pThis); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create VSCSI device rc=%Rrc\n", rc), rc); rc = VSCSILunCreate(&pThis->hVScsiLun, enmLunType, &pThis->VScsiIoCallbacks, pThis); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create VSCSI LUN rc=%Rrc\n", rc), rc); rc = VSCSIDeviceLunAttach(pThis->hVScsiDevice, pThis->hVScsiLun, 0); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to attached the LUN to the SCSI device\n"), rc); //@todo: This is a very hacky way of telling the LUN whether a medium was mounted. // The mount/unmount interface doesn't work in a very sensible manner! if (pThis->pDrvMount) { if (pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia)) { rc = VINF_SUCCESS; VSCSILunMountNotify(pThis->hVScsiLun); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to notify the LUN of media being mounted\n"), rc); } else { rc = VINF_SUCCESS; VSCSILunUnmountNotify(pThis->hVScsiLun); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to notify the LUN of media being unmounted\n"), rc); } } const char *pszCtrl = NULL; uint32_t iCtrlInstance = 0; uint32_t iCtrlLun = 0; rc = pThis->pDevScsiPort->pfnQueryDeviceLocation(pThis->pDevScsiPort, &pszCtrl, &iCtrlInstance, &iCtrlLun); if (RT_SUCCESS(rc)) { const char *pszCtrlId = strcmp(pszCtrl, "Msd") == 0 ? "USB" : strcmp(pszCtrl, "lsilogicsas") == 0 ? "SAS" : "SCSI"; /* Register statistics counter. */ PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data read.", "/Devices/%s%u/%u/ReadBytes", pszCtrlId, iCtrlInstance, iCtrlLun); PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data written.", "/Devices/%s%u/%u/WrittenBytes", pszCtrlId, iCtrlInstance, iCtrlLun); PDMDrvHlpSTAMRegisterF(pDrvIns, (void *)&pThis->StatIoDepth, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of active tasks.", "/Devices/%s%u/%u/IoDepth", pszCtrlId, iCtrlInstance, iCtrlLun); } pThis->StatIoDepth = 0; if (!pThis->pDrvMediaAsync) { /* Create request queue. */ rc = RTReqQueueCreate(&pThis->hQueueRequests); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create request queue rc=%Rrc\n", rc), rc); /* Create I/O thread. */ rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pAsyncIOThread, pThis, drvscsiAsyncIOLoop, drvscsiAsyncIOLoopWakeup, 0, RTTHREADTYPE_IO, "SCSI async IO"); AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create async I/O thread rc=%Rrc\n", rc), rc); LogRel(("SCSI#%d: using normal I/O\n", pDrvIns->iInstance)); } else LogRel(("SCSI#%d: using async I/O\n", pDrvIns->iInstance)); if ( pThis->pDrvMedia->pfnDiscard || ( pThis->pDrvMediaAsync && pThis->pDrvMediaAsync->pfnStartDiscard)) LogRel(("SCSI#%d: Enabled UNMAP support\n", pDrvIns->iInstance)); return VINF_SUCCESS; }
/** * Internal worker for RTTimeNormalize and RTTimeLocalNormalize. * It doesn't adjust the UCT offset but leaves that for RTTimeLocalNormalize. */ static PRTTIME rtTimeNormalizeInternal(PRTTIME pTime) { unsigned uSecond; unsigned uMinute; unsigned uHour; bool fLeapYear; /* * Fix the YearDay and Month/MonthDay. */ fLeapYear = rtTimeIsLeapYear(pTime->i32Year); if (!pTime->u16YearDay) { /* * The Month+MonthDay must present, overflow adjust them and calc the year day. */ AssertMsgReturn( pTime->u8Month && pTime->u8MonthDay, ("date=%d-%d-%d\n", pTime->i32Year, pTime->u8Month, pTime->u8MonthDay), NULL); while (pTime->u8Month > 12) { pTime->u8Month -= 12; pTime->i32Year++; fLeapYear = rtTimeIsLeapYear(pTime->i32Year); pTime->fFlags &= ~(RTTIME_FLAGS_COMMON_YEAR | RTTIME_FLAGS_LEAP_YEAR); } for (;;) { unsigned cDaysInMonth = fLeapYear ? g_acDaysInMonthsLeap[pTime->u8Month - 1] : g_acDaysInMonths[pTime->u8Month - 1]; if (pTime->u8MonthDay <= cDaysInMonth) break; pTime->u8MonthDay -= cDaysInMonth; if (pTime->u8Month != 12) pTime->u8Month++; else { pTime->u8Month = 1; pTime->i32Year++; fLeapYear = rtTimeIsLeapYear(pTime->i32Year); pTime->fFlags &= ~(RTTIME_FLAGS_COMMON_YEAR | RTTIME_FLAGS_LEAP_YEAR); } } pTime->u16YearDay = pTime->u8MonthDay - 1 + (fLeapYear ? g_aiDayOfYearLeap[pTime->u8Month - 1] : g_aiDayOfYear[pTime->u8Month - 1]); } else { /* * Are both YearDay and Month/MonthDay valid? * Check that they don't overflow and match, if not use YearDay (simpler). */ bool fRecalc = true; if ( pTime->u8Month && pTime->u8MonthDay) { do { uint16_t u16YearDay; /* If you change one, zero the other to make clear what you mean. */ AssertBreak(pTime->u8Month <= 12); AssertBreak(pTime->u8MonthDay <= (fLeapYear ? g_acDaysInMonthsLeap[pTime->u8Month - 1] : g_acDaysInMonths[pTime->u8Month - 1])); u16YearDay = pTime->u8MonthDay - 1 + (fLeapYear ? g_aiDayOfYearLeap[pTime->u8Month - 1] : g_aiDayOfYear[pTime->u8Month - 1]); AssertBreak(u16YearDay == pTime->u16YearDay); fRecalc = false; } while (0); } if (fRecalc) { const uint16_t *paiDayOfYear; /* overflow adjust YearDay */ while (pTime->u16YearDay > (fLeapYear ? 366 : 365)) { pTime->u16YearDay -= fLeapYear ? 366 : 365; pTime->i32Year++; fLeapYear = rtTimeIsLeapYear(pTime->i32Year); pTime->fFlags &= ~(RTTIME_FLAGS_COMMON_YEAR | RTTIME_FLAGS_LEAP_YEAR); } /* calc Month and MonthDay */ paiDayOfYear = fLeapYear ? &g_aiDayOfYearLeap[0] : &g_aiDayOfYear[0]; pTime->u8Month = 1; while (pTime->u16YearDay > paiDayOfYear[pTime->u8Month]) pTime->u8Month++; Assert(pTime->u8Month >= 1 && pTime->u8Month <= 12); pTime->u8MonthDay = pTime->u16YearDay - paiDayOfYear[pTime->u8Month - 1] + 1; } } /* * Fixup time overflows. * Use unsigned int values internally to avoid overflows. */ uSecond = pTime->u8Second; uMinute = pTime->u8Minute; uHour = pTime->u8Hour; while (pTime->u32Nanosecond >= 1000000000) { pTime->u32Nanosecond -= 1000000000; uSecond++; } while (uSecond >= 60) { uSecond -= 60; uMinute++; } while (uMinute >= 60) { uMinute -= 60; uHour++; } while (uHour >= 24) { uHour -= 24; /* This is really a RTTimeIncDay kind of thing... */ if (pTime->u16YearDay + 1 != (fLeapYear ? g_aiDayOfYearLeap[pTime->u8Month] : g_aiDayOfYear[pTime->u8Month])) { pTime->u16YearDay++; pTime->u8MonthDay++; } else if (pTime->u8Month != 12) { pTime->u16YearDay++; pTime->u8Month++; pTime->u8MonthDay = 1; } else { pTime->i32Year++; fLeapYear = rtTimeIsLeapYear(pTime->i32Year); pTime->fFlags &= ~(RTTIME_FLAGS_COMMON_YEAR | RTTIME_FLAGS_LEAP_YEAR); pTime->u16YearDay = 1; pTime->u8Month = 1; pTime->u8MonthDay = 1; } } pTime->u8Second = uSecond; pTime->u8Minute = uMinute; pTime->u8Hour = uHour; /* * Correct the leap year flag. * Assert if it's wrong, but ignore if unset. */ if (fLeapYear) { Assert(!(pTime->fFlags & RTTIME_FLAGS_COMMON_YEAR)); pTime->fFlags &= ~RTTIME_FLAGS_COMMON_YEAR; pTime->fFlags |= RTTIME_FLAGS_LEAP_YEAR; } else { Assert(!(pTime->fFlags & RTTIME_FLAGS_LEAP_YEAR)); pTime->fFlags &= ~RTTIME_FLAGS_LEAP_YEAR; pTime->fFlags |= RTTIME_FLAGS_COMMON_YEAR; } /* * Calc week day. * * 1970-01-01 was a Thursday (3), so find the number of days relative to * that point. We use the table when possible and a slow+stupid+brute-force * algorithm for points outside it. Feel free to optimize the latter by * using some clever formula. */ if ( pTime->i32Year >= OFF_YEAR_IDX_0_YEAR && pTime->i32Year < OFF_YEAR_IDX_0_YEAR + (int32_t)RT_ELEMENTS(g_aoffYear)) { int32_t offDays = g_aoffYear[pTime->i32Year - OFF_YEAR_IDX_0_YEAR] + pTime->u16YearDay -1; pTime->u8WeekDay = ((offDays % 7) + 3 + 7) % 7; } else { int32_t i32Year = pTime->i32Year; if (i32Year >= 1970) { uint64_t offDays = pTime->u16YearDay - 1; while (--i32Year >= 1970) offDays += rtTimeIsLeapYear(i32Year) ? 366 : 365; pTime->u8WeekDay = (uint8_t)((offDays + 3) % 7); } else { int64_t offDays = (fLeapYear ? -366 - 1 : -365 - 1) + pTime->u16YearDay; while (++i32Year < 1970) offDays -= rtTimeIsLeapYear(i32Year) ? 366 : 365; pTime->u8WeekDay = ((int)(offDays % 7) + 3 + 7) % 7; } } return pTime; }
/** * Internal helper for rtZipGzip_Write, rtZipGzip_Flush and rtZipGzip_Close. * * @returns IPRT status code. * @retval VINF_SUCCESS * @retval VINF_TRY_AGAIN - the only informational status. * @retval VERR_INTERRUPTED - call again. * * @param pThis The gzip I/O stream instance data. * @param fBlocking Whether to block or not. */ static int rtZipGzip_WriteOutputBuffer(PRTZIPGZIPSTREAM pThis, bool fBlocking) { /* * Anything to write? No, then just return immediately. */ size_t cbToWrite = sizeof(pThis->abBuffer) - pThis->Zlib.avail_out; if (cbToWrite == 0) { Assert(pThis->Zlib.next_out == &pThis->abBuffer[0]); return VINF_SUCCESS; } Assert(cbToWrite <= sizeof(pThis->abBuffer)); /* * Loop write on VERR_INTERRUPTED. * * Note! Asserting a bit extra here to make sure the * RTVfsIoStrmSgWrite works correctly. */ int rc; size_t cbWrittenOut; for (;;) { /* Set up the buffer. */ pThis->SgSeg.cbSeg = cbToWrite; Assert(pThis->SgSeg.pvSeg == &pThis->abBuffer[0]); RTSgBufReset(&pThis->SgBuf); cbWrittenOut = ~(size_t)0; rc = RTVfsIoStrmSgWrite(pThis->hVfsIos, -1 /*off*/, &pThis->SgBuf, fBlocking, &cbWrittenOut); if (rc != VINF_SUCCESS) { AssertMsg(RT_FAILURE(rc) || rc == VINF_TRY_AGAIN, ("%Rrc\n", rc)); if (rc == VERR_INTERRUPTED) { Assert(cbWrittenOut == 0); continue; } if (RT_FAILURE(rc) || rc == VINF_TRY_AGAIN || cbWrittenOut == 0) { AssertReturn(cbWrittenOut == 0, VERR_INTERNAL_ERROR_3); AssertReturn(rc != VINF_SUCCESS, VERR_IPE_UNEXPECTED_INFO_STATUS); return rc; } } break; } AssertMsgReturn(cbWrittenOut > 0 && cbWrittenOut <= sizeof(pThis->abBuffer), ("%zu %Rrc\n", cbWrittenOut, rc), VERR_INTERNAL_ERROR_4); /* * Adjust the Zlib output buffer members. */ if (cbWrittenOut == pThis->SgBuf.paSegs[0].cbSeg) { pThis->Zlib.avail_out = sizeof(pThis->abBuffer); pThis->Zlib.next_out = &pThis->abBuffer[0]; } else { Assert(cbWrittenOut <= pThis->SgBuf.paSegs[0].cbSeg); size_t cbLeft = pThis->SgBuf.paSegs[0].cbSeg - cbWrittenOut; memmove(&pThis->abBuffer[0], &pThis->abBuffer[cbWrittenOut], cbLeft); pThis->Zlib.avail_out += (uInt)cbWrittenOut; pThis->Zlib.next_out = &pThis->abBuffer[cbWrittenOut]; } return VINF_SUCCESS; }
/** * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug. * * @returns VBox status code. * @param pThis The event semaphore. * @param fFlags See RTSemEventMultiWaitEx. * @param uTimeout See RTSemEventMultiWaitEx. * @param pSrcPos The source code position of the wait. */ static int rtR0SemEventMultiDarwinWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout, PCRTLOCKVALSRCPOS pSrcPos) { /* * Validate input. */ AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE); AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER); if (uTimeout != 0 || (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)) RT_ASSERT_PREEMPTIBLE(); rtR0SemEventMultiDarwinRetain(pThis); lck_spin_lock(pThis->pSpinlock); /* * Is the event already signalled or do we have to wait? */ int rc; uint32_t const fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen); if (fOrgStateAndGen & RTSEMEVENTMULTIDARWIN_STATE_MASK) rc = VINF_SUCCESS; else { /* * We have to wait. So, we'll need to convert the timeout and figure * out if it's indefinite or not. */ uint64_t uNsAbsTimeout = 1; if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE)) { if (fFlags & RTSEMWAIT_FLAGS_MILLISECS) uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000) ? uTimeout * UINT32_C(1000000) : UINT64_MAX; if (uTimeout == UINT64_MAX) fFlags |= RTSEMWAIT_FLAGS_INDEFINITE; else { uint64_t u64Now; if (fFlags & RTSEMWAIT_FLAGS_RELATIVE) { if (uTimeout != 0) { u64Now = RTTimeSystemNanoTS(); uNsAbsTimeout = u64Now + uTimeout; if (uNsAbsTimeout < u64Now) /* overflow */ fFlags |= RTSEMWAIT_FLAGS_INDEFINITE; } } else { uNsAbsTimeout = uTimeout; u64Now = RTTimeSystemNanoTS(); uTimeout = u64Now < uTimeout ? uTimeout - u64Now : 0; } } } if ( !(fFlags & RTSEMWAIT_FLAGS_INDEFINITE) && uTimeout == 0) { /* * Poll call, we already checked the condition above so no need to * wait for anything. */ rc = VERR_TIMEOUT; } else { for (;;) { /* * Do the actual waiting. */ ASMAtomicWriteBool(&pThis->fHaveBlockedThreads, true); wait_interrupt_t fInterruptible = fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE ? THREAD_ABORTSAFE : THREAD_UNINT; wait_result_t rcWait; if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE) rcWait = lck_spin_sleep(pThis->pSpinlock, LCK_SLEEP_DEFAULT, (event_t)pThis, fInterruptible); else { uint64_t u64AbsTime; nanoseconds_to_absolutetime(uNsAbsTimeout, &u64AbsTime); rcWait = lck_spin_sleep_deadline(pThis->pSpinlock, LCK_SLEEP_DEFAULT, (event_t)pThis, fInterruptible, u64AbsTime); } /* * Deal with the wait result. */ if (RT_LIKELY(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC)) { switch (rcWait) { case THREAD_AWAKENED: if (RT_LIKELY(ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)) rc = VINF_SUCCESS; else if (fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE) rc = VERR_INTERRUPTED; else continue; /* Seen this happen after fork/exec/something. */ break; case THREAD_TIMED_OUT: Assert(!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE)); rc = VERR_TIMEOUT; break; case THREAD_INTERRUPTED: Assert(fInterruptible != THREAD_UNINT); rc = VERR_INTERRUPTED; break; case THREAD_RESTART: AssertMsg(pThis->u32Magic == ~RTSEMEVENTMULTI_MAGIC, ("%#x\n", pThis->u32Magic)); rc = VERR_SEM_DESTROYED; break; default: AssertMsgFailed(("rcWait=%d\n", rcWait)); rc = VERR_INTERNAL_ERROR_3; break; } } else rc = VERR_SEM_DESTROYED; break; } } } lck_spin_unlock(pThis->pSpinlock); rtR0SemEventMultiDarwinRelease(pThis); return rc; }
/** * Worker function for acquiring the mutex. * * @param hMutexSem The mutex object. * @param fFlags Mutex flags (see RTSEMWAIT_FLAGS_*) * @param uTimeout Timeout in units specified by the flags. * * @return IPRT status code. */ static int rtSemMutexRequestEx(RTSEMMUTEX hMutexSem, uint32_t fFlags, uint64_t uTimeout) { PRTSEMMUTEXINTERNAL pThis = hMutexSem; int rc; status_t status; int32 flags = 0; bigtime_t timeout; /* in microseconds */ AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE); if (pThis->OwnerId == find_thread(NULL)) { pThis->OwnerId++; return VINF_SUCCESS; } if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE) timeout = B_INFINITE_TIMEOUT; else { if (fFlags & RTSEMWAIT_FLAGS_NANOSECS) timeout = uTimeout / 1000; else if (fFlags & RTSEMWAIT_FLAGS_MILLISECS) timeout = uTimeout * 1000; else return VERR_INVALID_PARAMETER; if (fFlags & RTSEMWAIT_FLAGS_RELATIVE) flags |= B_RELATIVE_TIMEOUT; else if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE) flags |= B_ABSOLUTE_TIMEOUT; else return VERR_INVALID_PARAMETER; } if (fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE) flags |= B_CAN_INTERRUPT; status = acquire_sem_etc(pThis->SemId, 1, flags, timeout); switch (status) { case B_OK: rc = VINF_SUCCESS; pThis->cRecursion = 1; pThis->OwnerId = find_thread(NULL); break; case B_BAD_SEM_ID: rc = VERR_SEM_DESTROYED; break; case B_INTERRUPTED: rc = VERR_INTERRUPTED; break; case B_WOULD_BLOCK: /* fallthrough? */ case B_TIMED_OUT: rc = VERR_TIMEOUT; break; default: rc = VERR_INVALID_PARAMETER; break; } return rc; }
/** * Worker for RTSemEventWaitEx and RTSemEventWaitExDebug. * * @returns VBox status code. * @param pThis The event semaphore. * @param fFlags See RTSemEventWaitEx. * @param uTimeout See RTSemEventWaitEx. * @param pSrcPos The source code position of the wait. */ static int rtR0SemEventLnxWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout, PCRTLOCKVALSRCPOS pSrcPos) { int rc; /* * Validate the input. */ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER); rtR0SemEventLnxRetain(pThis); /* * Try grab the event without setting up the wait. */ if ( 1 /** @todo check if there are someone waiting already - waitqueue_active, but then what do we do below? */ && ASMAtomicCmpXchgU32(&pThis->fState, 0, 1)) rc = VINF_SUCCESS; else { /* * We have to wait. */ IPRT_LINUX_SAVE_EFL_AC(); RTR0SEMLNXWAIT Wait; rc = rtR0SemLnxWaitInit(&Wait, fFlags, uTimeout, &pThis->Head); if (RT_SUCCESS(rc)) { IPRT_DEBUG_SEMS_STATE(pThis, 'E'); for (;;) { /* The destruction test. */ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC)) rc = VERR_SEM_DESTROYED; else { rtR0SemLnxWaitPrepare(&Wait); /* Check the exit conditions. */ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC)) rc = VERR_SEM_DESTROYED; else if (ASMAtomicCmpXchgU32(&pThis->fState, 0, 1)) rc = VINF_SUCCESS; else if (rtR0SemLnxWaitHasTimedOut(&Wait)) rc = VERR_TIMEOUT; else if (rtR0SemLnxWaitWasInterrupted(&Wait)) rc = VERR_INTERRUPTED; else { /* Do the wait and then recheck the conditions. */ rtR0SemLnxWaitDoIt(&Wait); continue; } } break; } rtR0SemLnxWaitDelete(&Wait); IPRT_DEBUG_SEMS_STATE_RC(pThis, 'E', rc); } IPRT_LINUX_RESTORE_EFL_AC(); } rtR0SemEventLnxRelease(pThis); return rc; }
RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags) { /** @todo Symlinks: Find[First|Next]FileW will return info about the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */ /* * Validate input. */ if (!pDir || pDir->u32Magic != RTDIR_MAGIC) { AssertMsgFailed(("Invalid pDir=%p\n", pDir)); return VERR_INVALID_PARAMETER; } if (!pDirEntry) { AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry)); return VERR_INVALID_PARAMETER; } if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING || enmAdditionalAttribs > RTFSOBJATTRADD_LAST) { AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs)); return VERR_INVALID_PARAMETER; } AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); size_t cbDirEntry = sizeof(*pDirEntry); if (pcbDirEntry) { cbDirEntry = *pcbDirEntry; if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRYEX, szName[2])) { AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2]))); return VERR_INVALID_PARAMETER; } } /* * Fetch data? */ if (!pDir->fDataUnread) { RTStrFree(pDir->pszName); pDir->pszName = NULL; BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data); if (!fRc) { int iErr = GetLastError(); if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES) return VERR_NO_MORE_FILES; return RTErrConvertFromWin32(iErr); } } /* * Convert the filename to UTF-8. */ if (!pDir->pszName) { int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName); if (RT_FAILURE(rc)) { pDir->pszName = NULL; return rc; } pDir->cchName = strlen(pDir->pszName); } /* * Check if we've got enough space to return the data. */ const char *pszName = pDir->pszName; const size_t cchName = pDir->cchName; const size_t cbRequired = RT_OFFSETOF(RTDIRENTRYEX, szName[1]) + cchName; if (pcbDirEntry) *pcbDirEntry = cbRequired; if (cbRequired > cbDirEntry) return VERR_BUFFER_OVERFLOW; /* * Setup the returned data. */ pDir->fDataUnread = false; pDirEntry->cbName = (uint16_t)cchName; Assert(pDirEntry->cbName == cchName); memcpy(pDirEntry->szName, pszName, cchName + 1); if (pDir->Data.cAlternateFileName[0]) { /* copy and calc length */ PCRTUTF16 pwszSrc = (PCRTUTF16)pDir->Data.cAlternateFileName; PRTUTF16 pwszDst = pDirEntry->wszShortName; uint32_t off = 0; while (pwszSrc[off] && off < RT_ELEMENTS(pDirEntry->wszShortName) - 1U) { pwszDst[off] = pwszSrc[off]; off++; } pDirEntry->cwcShortName = (uint16_t)off; /* zero the rest */ do pwszDst[off++] = '\0'; while (off < RT_ELEMENTS(pDirEntry->wszShortName)); } else { memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName)); pDirEntry->cwcShortName = 0; } pDirEntry->Info.cbObject = ((uint64_t)pDir->Data.nFileSizeHigh << 32) | (uint64_t)pDir->Data.nFileSizeLow; pDirEntry->Info.cbAllocated = pDirEntry->Info.cbObject; Assert(sizeof(uint64_t) == sizeof(pDir->Data.ftCreationTime)); RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, *(uint64_t *)&pDir->Data.ftCreationTime); RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, *(uint64_t *)&pDir->Data.ftLastAccessTime); RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, *(uint64_t *)&pDir->Data.ftLastWriteTime); pDirEntry->Info.ChangeTime = pDirEntry->Info.ModificationTime; pDirEntry->Info.Attr.fMode = rtFsModeFromDos((pDir->Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, pszName, cchName); /* * Requested attributes (we cannot provide anything actually). */ switch (enmAdditionalAttribs) { case RTFSOBJATTRADD_EASIZE: pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_EASIZE; pDirEntry->Info.Attr.u.EASize.cb = 0; break; case RTFSOBJATTRADD_UNIX: pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX; pDirEntry->Info.Attr.u.Unix.uid = ~0U; pDirEntry->Info.Attr.u.Unix.gid = ~0U; pDirEntry->Info.Attr.u.Unix.cHardlinks = 1; pDirEntry->Info.Attr.u.Unix.INodeIdDevice = 0; /** @todo Use the volume serial number (see GetFileInformationByHandle). */ pDirEntry->Info.Attr.u.Unix.INodeId = 0; /** @todo Use the fileid (see GetFileInformationByHandle). */ pDirEntry->Info.Attr.u.Unix.fFlags = 0; pDirEntry->Info.Attr.u.Unix.GenerationId = 0; pDirEntry->Info.Attr.u.Unix.Device = 0; break; case RTFSOBJATTRADD_NOTHING: pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING; break; case RTFSOBJATTRADD_UNIX_OWNER: pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER; pDirEntry->Info.Attr.u.UnixOwner.uid = ~0U; pDirEntry->Info.Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */ break; case RTFSOBJATTRADD_UNIX_GROUP: pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP; pDirEntry->Info.Attr.u.UnixGroup.gid = ~0U; pDirEntry->Info.Attr.u.UnixGroup.szName[0] = '\0'; break; default: AssertMsgFailed(("Impossible!\n")); return VERR_INTERNAL_ERROR; } return VINF_SUCCESS; }
DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable) { AssertMsgReturn(cb <= _1G, ("%#x\n", cb), VERR_OUT_OF_RANGE); /* for safe size_t -> ULONG */ /* * Try see if we get lucky first... * (We could probably just assume we're lucky on NT4.) */ int rc = rtR0MemObjNativeAllocPage(ppMem, cb, fExecutable); if (RT_SUCCESS(rc)) { size_t iPage = cb >> PAGE_SHIFT; while (iPage-- > 0) if (rtR0MemObjNativeGetPagePhysAddr(*ppMem, iPage) >= _4G) { rc = VERR_NO_LOW_MEMORY; break; } if (RT_SUCCESS(rc)) return rc; /* The following ASSUMES that rtR0MemObjNativeAllocPage returns a completed object. */ RTR0MemObjFree(*ppMem, false); *ppMem = NULL; } #ifndef IPRT_TARGET_NT4 /* * Use MmAllocatePagesForMdl to specify the range of physical addresses we wish to use. */ PHYSICAL_ADDRESS Zero; Zero.QuadPart = 0; PHYSICAL_ADDRESS HighAddr; HighAddr.QuadPart = _4G - 1; PMDL pMdl = MmAllocatePagesForMdl(Zero, HighAddr, Zero, cb); if (pMdl) { if (MmGetMdlByteCount(pMdl) >= cb) { __try { void *pv = MmMapLockedPagesSpecifyCache(pMdl, KernelMode, MmCached, NULL /* no base address */, FALSE /* no bug check on failure */, NormalPagePriority); if (pv) { PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_LOW, pv, cb); if (pMemNt) { pMemNt->fAllocatedPagesForMdl = true; pMemNt->cMdls = 1; pMemNt->apMdls[0] = pMdl; *ppMem = &pMemNt->Core; return VINF_SUCCESS; } MmUnmapLockedPages(pv, pMdl); } } __except(EXCEPTION_EXECUTE_HANDLER) { NTSTATUS rcNt = GetExceptionCode(); Log(("rtR0MemObjNativeAllocLow: Exception Code %#x\n", rcNt)); /* nothing */ } } MmFreePagesFromMdl(pMdl); ExFreePool(pMdl); }
RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags) { /* * Validate and digest input. */ if (!rtDirValidHandle(pDir)) return VERR_INVALID_PARAMETER; AssertMsgReturn(VALID_PTR(pDirEntry), ("%p\n", pDirEntry), VERR_INVALID_POINTER); AssertMsgReturn( enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST, ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs), VERR_INVALID_PARAMETER); AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); size_t cbDirEntry = sizeof(*pDirEntry); if (pcbDirEntry) { AssertMsgReturn(VALID_PTR(pcbDirEntry), ("%p\n", pcbDirEntry), VERR_INVALID_POINTER); cbDirEntry = *pcbDirEntry; AssertMsgReturn(cbDirEntry >= (unsigned)RT_OFFSETOF(RTDIRENTRYEX, szName[2]), ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])), VERR_INVALID_PARAMETER); } /* * Fetch more data if necessary and/or convert the name. */ int rc = rtDirReadMore(pDir); if (RT_SUCCESS(rc)) { /* * Check if we've got enough space to return the data. */ const char *pszName = pDir->pszName; const size_t cchName = pDir->cchName; const size_t cbRequired = RT_OFFSETOF(RTDIRENTRYEX, szName[1]) + cchName; if (pcbDirEntry) *pcbDirEntry = cbRequired; if (cbRequired <= cbDirEntry) { /* * Setup the returned data. */ pDirEntry->cwcShortName = 0; pDirEntry->wszShortName[0] = 0; pDirEntry->cbName = (uint16_t)cchName; Assert(pDirEntry->cbName == cchName); memcpy(pDirEntry->szName, pszName, cchName + 1); /* get the info data */ size_t cch = cchName + pDir->cchPath + 1; char *pszNamePath = (char *)alloca(cch); if (pszNamePath) { memcpy(pszNamePath, pDir->pszPath, pDir->cchPath); memcpy(pszNamePath + pDir->cchPath, pszName, cchName + 1); rc = RTPathQueryInfoEx(pszNamePath, &pDirEntry->Info, enmAdditionalAttribs, fFlags); } else rc = VERR_NO_MEMORY; if (RT_FAILURE(rc)) { #ifdef HAVE_DIRENT_D_TYPE rtDirSetDummyInfo(&pDirEntry->Info, rtDirType(pDir->Data.d_type)); #else rtDirSetDummyInfo(&pDirEntry->Info, RTDIRENTRYTYPE_UNKNOWN); #endif rc = VWRN_NO_DIRENT_INFO; } /* free cached data */ pDir->fDataUnread = false; rtPathFreeIprt(pDir->pszName, pDir->Data.d_name); pDir->pszName = NULL; } else rc = VERR_BUFFER_OVERFLOW; } return rc; }
RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags) { /* * Validate input. */ AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(*pszPath, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER); AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER); AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER); AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER); AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); /* * Convert the path. */ PRTUTF16 pwszPath; int rc = RTStrToUtf16(pszPath, &pwszPath); if (RT_SUCCESS(rc)) { HANDLE hFile; if (fFlags & RTPATH_F_FOLLOW_LINK) hFile = CreateFileW(pwszPath, FILE_WRITE_ATTRIBUTES, /* dwDesiredAccess */ FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* dwShareMode */ NULL, /* security attribs */ OPEN_EXISTING, /* dwCreationDisposition */ FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL, NULL); else { /** @todo Symlink: Test RTPathSetTimesEx on Windows. (The code is disabled * because it's not tested yet.) */ #if 0 //def FILE_FLAG_OPEN_REPARSE_POINT hFile = CreateFileW(pwszPath, FILE_WRITE_ATTRIBUTES, /* dwDesiredAccess */ FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* dwShareMode */ NULL, /* security attribs */ OPEN_EXISTING, /* dwCreationDisposition */ FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OPEN_REPARSE_POINT, NULL); if (hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_PARAMETER) #endif hFile = CreateFileW(pwszPath, FILE_WRITE_ATTRIBUTES, /* dwDesiredAccess */ FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* dwShareMode */ NULL, /* security attribs */ OPEN_EXISTING, /* dwCreationDisposition */ FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_NORMAL, NULL); } if (hFile != INVALID_HANDLE_VALUE) { /* * Check if it's a no-op. */ if (!pAccessTime && !pModificationTime && !pBirthTime) rc = VINF_SUCCESS; /* NOP */ else { /* * Convert the input and call the API. */ FILETIME CreationTimeFT; PFILETIME pCreationTimeFT = NULL; if (pBirthTime) pCreationTimeFT = RTTimeSpecGetNtFileTime(pBirthTime, &CreationTimeFT); FILETIME LastAccessTimeFT; PFILETIME pLastAccessTimeFT = NULL; if (pAccessTime) pLastAccessTimeFT = RTTimeSpecGetNtFileTime(pAccessTime, &LastAccessTimeFT); FILETIME LastWriteTimeFT; PFILETIME pLastWriteTimeFT = NULL; if (pModificationTime) pLastWriteTimeFT = RTTimeSpecGetNtFileTime(pModificationTime, &LastWriteTimeFT); if (SetFileTime(hFile, pCreationTimeFT, pLastAccessTimeFT, pLastWriteTimeFT)) rc = VINF_SUCCESS; else { DWORD Err = GetLastError(); rc = RTErrConvertFromWin32(Err); Log(("RTPathSetTimes('%s', %p, %p, %p, %p): SetFileTime failed with lasterr %d (%Rrc)\n", pszPath, pAccessTime, pModificationTime, pChangeTime, pBirthTime, Err, rc)); } } BOOL fRc = CloseHandle(hFile); Assert(fRc); NOREF(fRc); } else { DWORD Err = GetLastError(); rc = RTErrConvertFromWin32(Err); Log(("RTPathSetTimes('%s',,,,): failed with %Rrc and lasterr=%u\n", pszPath, rc, Err)); } RTUtf16Free(pwszPath); } LogFlow(("RTPathSetTimes(%p:{%s}, %p:{%RDtimespec}, %p:{%RDtimespec}, %p:{%RDtimespec}, %p:{%RDtimespec}): return %Rrc\n", pszPath, pszPath, pAccessTime, pAccessTime, pModificationTime, pModificationTime, pChangeTime, pChangeTime, pBirthTime, pBirthTime)); return rc; }
RTDECL(int) RTDirRead(PRTDIR pDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry) { /* * Validate and digest input. */ if (!rtDirValidHandle(pDir)) return VERR_INVALID_PARAMETER; AssertMsgReturn(VALID_PTR(pDirEntry), ("%p\n", pDirEntry), VERR_INVALID_POINTER); size_t cbDirEntry = sizeof(*pDirEntry); if (pcbDirEntry) { AssertMsgReturn(VALID_PTR(pcbDirEntry), ("%p\n", pcbDirEntry), VERR_INVALID_POINTER); cbDirEntry = *pcbDirEntry; AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRY, szName[2]), ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])), VERR_INVALID_PARAMETER); } /* * Fetch more data if necessary and/or convert the name. */ int rc = rtDirReadMore(pDir); if (RT_SUCCESS(rc)) { /* * Check if we've got enough space to return the data. */ const char *pszName = pDir->pszName; const size_t cchName = pDir->cchName; const size_t cbRequired = RT_OFFSETOF(RTDIRENTRY, szName[1]) + cchName; if (pcbDirEntry) *pcbDirEntry = cbRequired; if (cbRequired <= cbDirEntry) { /* * Setup the returned data. */ pDirEntry->INodeId = pDir->Data.d_ino; /* may need #ifdefing later */ #ifdef HAVE_DIRENT_D_TYPE pDirEntry->enmType = rtDirType(pDir->Data.d_type); #else pDirEntry->enmType = RTDIRENTRYTYPE_UNKNOWN; #endif pDirEntry->cbName = (uint16_t)cchName; Assert(pDirEntry->cbName == cchName); memcpy(pDirEntry->szName, pszName, cchName + 1); /* free cached data */ pDir->fDataUnread = false; rtPathFreeIprt(pDir->pszName, pDir->Data.d_name); pDir->pszName = NULL; } else rc = VERR_BUFFER_OVERFLOW; } LogFlow(("RTDirRead(%p:{%s}, %p:{%s}, %p:{%u}): returns %Rrc\n", pDir, pDir->pszPath, pDirEntry, RT_SUCCESS(rc) ? pDirEntry->szName : "<failed>", pcbDirEntry, pcbDirEntry ? *pcbDirEntry : 0, rc)); return rc; }
RTR3DECL(int) RTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags) { /* * Validate input. */ AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(*pszPath, VERR_INVALID_PARAMETER); AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER); AssertMsgReturn( enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST, ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs), VERR_INVALID_PARAMETER); AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); /* * Query file info. */ WIN32_FILE_ATTRIBUTE_DATA Data; PRTUTF16 pwszPath; int rc = RTStrToUtf16(pszPath, &pwszPath); if (RT_FAILURE(rc)) return rc; if (!GetFileAttributesExW(pwszPath, GetFileExInfoStandard, &Data)) { /* Fallback to FindFileFirst in case of sharing violation. */ if (GetLastError() == ERROR_SHARING_VIOLATION) { WIN32_FIND_DATAW FindData; HANDLE hDir = FindFirstFileW(pwszPath, &FindData); if (hDir == INVALID_HANDLE_VALUE) { rc = RTErrConvertFromWin32(GetLastError()); RTUtf16Free(pwszPath); return rc; } FindClose(hDir); Data.dwFileAttributes = FindData.dwFileAttributes; Data.ftCreationTime = FindData.ftCreationTime; Data.ftLastAccessTime = FindData.ftLastAccessTime; Data.ftLastWriteTime = FindData.ftLastWriteTime; Data.nFileSizeHigh = FindData.nFileSizeHigh; Data.nFileSizeLow = FindData.nFileSizeLow; } else { rc = RTErrConvertFromWin32(GetLastError()); RTUtf16Free(pwszPath); return rc; } } /* * Getting the information for the link target is a bit annoying and * subject to the same access violation mess as above.. :/ */ /** @todo we're too lazy wrt to error paths here... */ if ( (fFlags & RTPATH_F_FOLLOW_LINK) && (Data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { HANDLE hFinal = CreateFileW(pwszPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFinal != INVALID_HANDLE_VALUE) { BY_HANDLE_FILE_INFORMATION FileData; if (GetFileInformationByHandle(hFinal, &FileData)) { Data.dwFileAttributes = FileData.dwFileAttributes; Data.ftCreationTime = FileData.ftCreationTime; Data.ftLastAccessTime = FileData.ftLastAccessTime; Data.ftLastWriteTime = FileData.ftLastWriteTime; Data.nFileSizeHigh = FileData.nFileSizeHigh; Data.nFileSizeLow = FileData.nFileSizeLow; } CloseHandle(hFinal); } else if (GetLastError() != ERROR_SHARING_VIOLATION) { rc = RTErrConvertFromWin32(GetLastError()); RTUtf16Free(pwszPath); return rc; } } RTUtf16Free(pwszPath); /* * Setup the returned data. */ pObjInfo->cbObject = ((uint64_t)Data.nFileSizeHigh << 32) | (uint64_t)Data.nFileSizeLow; pObjInfo->cbAllocated = pObjInfo->cbObject; Assert(sizeof(uint64_t) == sizeof(Data.ftCreationTime)); RTTimeSpecSetNtTime(&pObjInfo->BirthTime, *(uint64_t *)&Data.ftCreationTime); RTTimeSpecSetNtTime(&pObjInfo->AccessTime, *(uint64_t *)&Data.ftLastAccessTime); RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, *(uint64_t *)&Data.ftLastWriteTime); pObjInfo->ChangeTime = pObjInfo->ModificationTime; pObjInfo->Attr.fMode = rtFsModeFromDos((Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, pszPath, strlen(pszPath)); /* * Requested attributes (we cannot provide anything actually). */ switch (enmAdditionalAttribs) { case RTFSOBJATTRADD_NOTHING: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_NOTHING; break; case RTFSOBJATTRADD_UNIX: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX; pObjInfo->Attr.u.Unix.uid = ~0U; pObjInfo->Attr.u.Unix.gid = ~0U; pObjInfo->Attr.u.Unix.cHardlinks = 1; pObjInfo->Attr.u.Unix.INodeIdDevice = 0; /** @todo use volume serial number */ pObjInfo->Attr.u.Unix.INodeId = 0; /** @todo use fileid (see GetFileInformationByHandle). */ pObjInfo->Attr.u.Unix.fFlags = 0; pObjInfo->Attr.u.Unix.GenerationId = 0; pObjInfo->Attr.u.Unix.Device = 0; break; case RTFSOBJATTRADD_UNIX_OWNER: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER; pObjInfo->Attr.u.UnixOwner.uid = ~0U; pObjInfo->Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */ break; case RTFSOBJATTRADD_UNIX_GROUP: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP; pObjInfo->Attr.u.UnixGroup.gid = ~0U; pObjInfo->Attr.u.UnixGroup.szName[0] = '\0'; break; case RTFSOBJATTRADD_EASIZE: pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE; pObjInfo->Attr.u.EASize.cb = 0; break; default: AssertMsgFailed(("Impossible!\n")); return VERR_INTERNAL_ERROR; } return VINF_SUCCESS; }