/**
 * 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;
}
Пример #3
0
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;
}
Пример #5
0
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;
}
Пример #6
0
/**
 * 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;
}
Пример #7
0
/**
 * 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;
}
Пример #9
0
/**
 * 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;
}
Пример #10
0
RTDECL(RTLDRARCH) RTLdrGetArch(RTLDRMOD hLdrMod)
{
    AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRARCH_INVALID);
    PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
    return pMod->enmArch;
}
Пример #11
0
RTDECL(RTLDRFMT) RTLdrGetFormat(RTLDRMOD hLdrMod)
{
    AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRFMT_INVALID);
    PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
    return pMod->enmFormat;
}
Пример #12
0
RTDECL(RTLDRENDIAN) RTLdrGetEndian(RTLDRMOD hLdrMod)
{
    AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRENDIAN_INVALID);
    PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
    return pMod->enmEndian;
}
Пример #13
0
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. */
    }
}
Пример #15
0
/**
 * 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;
}
Пример #16
0
/**
 * 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;
}
Пример #17
0
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!"));
            }
        }
    }
}
Пример #18
0
/**
 * 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;
}
Пример #19
0
/**
 * 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;
}
Пример #20
0
/**
 * 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;
}
Пример #22
0
/**
 * 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;
}
Пример #23
0
/**
 * 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;
}
Пример #24
0
/**
 * 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;
}
Пример #25
0
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);
    }
Пример #27
0
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;
}
Пример #28
0
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;
}
Пример #29
0
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;
}
Пример #30
-1
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;
}