Beispiel #1
0
RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed)
{
    /* Validate input */
    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
    AssertReturn(cbSize > 0, VERR_INVALID_PARAMETER);
    AssertPtrReturn(paTests, VERR_INVALID_POINTER);
    AssertReturn(cTests > 0, VERR_INVALID_PARAMETER);
    AssertPtrNullReturn(piFailed, VERR_INVALID_POINTER);

    int rc = VINF_SUCCESS;

    PRTMANIFESTFILEENTRY paFiles = (PRTMANIFESTFILEENTRY)RTMemTmpAllocZ(sizeof(RTMANIFESTFILEENTRY) * cTests);
    if (!paFiles)
        return VERR_NO_MEMORY;

    /* Fill our compare list */
    for (size_t i = 0; i < cTests; ++i)
        paFiles[i].pTestPattern = &paTests[i];

    char *pcBuf = (char*)pvBuf;
    size_t cbRead = 0;
    /* Parse the manifest file line by line */
    for (;;)
    {
        if (cbRead >= cbSize)
            break;

        size_t cch = rtManifestIndexOfCharInBuf(pcBuf, cbSize - cbRead, '\n') + 1;

        /* Skip empty lines (UNIX/DOS format) */
        if (   (   cch == 1
                   && pcBuf[0] == '\n')
                || (   cch == 2
                       && pcBuf[0] == '\r'
                       && pcBuf[1] == '\n'))
        {
            pcBuf += cch;
            cbRead += cch;
            continue;
        }

        /** @todo r=bird:
         *  -# Better deal with this EOF line platform dependency
         *  -# The SHA1 test should probably include a blank space check.
         *  -# If there is a specific order to the elements in the string, it would be
         *     good if the delimiter searching checked for it.
         *  -# Deal with filenames containing delimiter characters.
         */

        /* Check for the digest algorithm */
        if (   cch < 4
                || !(   pcBuf[0] == 'S'
                        && pcBuf[1] == 'H'
                        && pcBuf[2] == 'A'
                        && pcBuf[3] == '1'))
        {
            /* Digest unsupported */
            rc = VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE;
            break;
        }

        /* Try to find the filename */
        char *pszNameStart = rtManifestPosOfCharInBuf(pcBuf, cch, '(');
        if (!pszNameStart)
        {
            rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
            break;
        }
        char *pszNameEnd = rtManifestPosOfCharInBuf(pcBuf, cch, ')');
        if (!pszNameEnd)
        {
            rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
            break;
        }

        /* Copy the filename part */
        size_t cchName = pszNameEnd - pszNameStart - 1;
        char *pszName = (char *)RTMemTmpAlloc(cchName + 1);
        if (!pszName)
        {
            rc = VERR_NO_MEMORY;
            break;
        }
        memcpy(pszName, pszNameStart + 1, cchName);
        pszName[cchName] = '\0';

        /* Try to find the digest sum */
        char *pszDigestStart = rtManifestPosOfCharInBuf(pcBuf, cch, '=') + 1;
        if (!pszDigestStart)
        {
            RTMemTmpFree(pszName);
            rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
            break;
        }
        char *pszDigestEnd = rtManifestPosOfCharInBuf(pcBuf, cch, '\r');
        if (!pszDigestEnd)
            pszDigestEnd = rtManifestPosOfCharInBuf(pcBuf, cch, '\n');
        if (!pszDigestEnd)
        {
            rc = VERR_MANIFEST_WRONG_FILE_FORMAT;
            break;
        }
        /* Copy the digest part */
        size_t cchDigest = pszDigestEnd - pszDigestStart - 1;
        char *pszDigest = (char *)RTMemTmpAlloc(cchDigest + 1);
        if (!pszDigest)
        {
            rc = VERR_NO_MEMORY;
            break;
        }
        memcpy(pszDigest, pszDigestStart + 1, cchDigest);
        pszDigest[cchDigest] = '\0';

        /* Check our file list against the extracted data */
        bool fFound = false;
        for (size_t i = 0; i < cTests; ++i)
        {
            if (!RTStrCmp(RTPathFilename(paFiles[i].pTestPattern->pszTestFile), RTStrStrip(pszName)))
            {
                /* Add the data of the manifest file to the file list */
                paFiles[i].pszManifestFile = RTStrDup(RTStrStrip(pszName));
                paFiles[i].pszManifestDigest = RTStrDup(RTStrStrip(pszDigest));
                fFound = true;
                break;
            }
        }
        RTMemTmpFree(pszName);
        RTMemTmpFree(pszDigest);
        if (!fFound)
        {
            /* There have to be an entry in the file list */
            rc = VERR_MANIFEST_FILE_MISMATCH;
            break;
        }

        pcBuf += cch;
        cbRead += cch;
    }

    if (   rc == VINF_SUCCESS
            || rc == VERR_EOF)
    {
        rc = VINF_SUCCESS;
        for (size_t i = 0; i < cTests; ++i)
        {
            /* If there is an entry in the file list, which hasn't an
             * equivalent in the manifest file, its an error. */
            if (   !paFiles[i].pszManifestFile
                    || !paFiles[i].pszManifestDigest)
            {
                rc = VERR_MANIFEST_FILE_MISMATCH;
                break;
            }

            /* Do the manifest SHA1 digest match against the actual digest? */
            if (RTStrICmp(paFiles[i].pszManifestDigest, paFiles[i].pTestPattern->pszTestDigest))
            {
                if (piFailed)
                    *piFailed = i;
                rc = VERR_MANIFEST_DIGEST_MISMATCH;
                break;
            }
        }
    }

    /* Cleanup */
    for (size_t i = 0; i < cTests; ++i)
    {
        if (paFiles[i].pszManifestFile)
            RTStrFree(paFiles[i].pszManifestFile);
        if (paFiles[i].pszManifestDigest)
            RTStrFree(paFiles[i].pszManifestDigest);
    }
    RTMemTmpFree(paFiles);

    return rc;
}
RTDECL(int) RTSystemQueryDmiString(RTSYSDMISTR enmString, char *pszBuf, size_t cbBuf)
{
    AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
    AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
    *pszBuf = '\0';
    AssertReturn(enmString > RTSYSDMISTR_INVALID && enmString < RTSYSDMISTR_END, VERR_INVALID_PARAMETER);

    /*
     * Figure the property name before we start.
     */
    const char *pszPropName;
    switch (enmString)
    {
        case RTSYSDMISTR_PRODUCT_NAME:      pszPropName = "Name"; break;
        case RTSYSDMISTR_PRODUCT_VERSION:   pszPropName = "Version"; break;
        case RTSYSDMISTR_PRODUCT_UUID:      pszPropName = "UUID"; break;
        case RTSYSDMISTR_PRODUCT_SERIAL:    pszPropName = "IdentifyingNumber"; break;
        case RTSYSDMISTR_MANUFACTURER:      pszPropName = "Vendor"; break;

        default:
            return VERR_NOT_SUPPORTED;
    }

    /*
     * Before we do anything with COM, we have to initialize it.
     */
    bool fUninit = true;
    HRESULT hrc = rtSystemDmiWinInitialize();
    if (hrc == RPC_E_CHANGED_MODE)
        fUninit = false;  /* don't fail if already initialized */
    else if (FAILED(hrc))
        return VERR_NOT_SUPPORTED;

    int rc = VERR_NOT_SUPPORTED;
    BSTR pBstrPropName = rtSystemWinBstrFromUtf8(pszPropName);
    if (pBstrPropName)
    {
        /*
         * Instantiate the IWbemLocator, whatever that is and connect to the
         * DMI serve.
         */
        IWbemLocator *pLoc;
        hrc = CoCreateInstance(CLSID_WbemLocator,
                               0,
                               CLSCTX_INPROC_SERVER,
                               IID_IWbemLocator,
                               (LPVOID *)&pLoc);
        if (SUCCEEDED(hrc))
        {
            IWbemServices *pServices;
            hrc = rtSystemDmiWinConnectToServer(pLoc, "ROOT\\CIMV2", &pServices);
            if (SUCCEEDED(hrc))
            {
                /*
                 * Enumerate whatever it is we're looking at and try get
                 * the desired property.
                 */
                BSTR pBstrFilter = rtSystemWinBstrFromUtf8("Win32_ComputerSystemProduct");
                if (pBstrFilter)
                {
                    IEnumWbemClassObject *pEnum;
                    hrc = pServices->CreateInstanceEnum(pBstrFilter, 0, NULL, &pEnum);
                    if (SUCCEEDED(hrc))
                    {
                        do
                        {
                            IWbemClassObject *pObj;
                            ULONG cObjRet;
                            hrc = pEnum->Next(WBEM_INFINITE, 1, &pObj, &cObjRet);
                            if (   SUCCEEDED(hrc)
                                && cObjRet >= 1)
                            {
                                VARIANT Var;
                                VariantInit(&Var);
                                hrc = pObj->Get(pBstrPropName, 0, &Var, 0, 0);
                                if (   SUCCEEDED(hrc)
                                    && V_VT(&Var) == VT_BSTR)
                                {
                                    /*
                                     * Convert the BSTR to UTF-8 and copy it
                                     * into the return buffer.
                                     */
                                    char *pszValue;
                                    rc = RTUtf16ToUtf8(Var.bstrVal, &pszValue);
                                    if (RT_SUCCESS(rc))
                                    {
                                        rc = RTStrCopy(pszBuf, cbBuf, pszValue);
                                        RTStrFree(pszValue);
                                        hrc = WBEM_S_FALSE;
                                    }
                                }
                                VariantClear(&Var);
                                pObj->Release();
                            }
                        } while (hrc != WBEM_S_FALSE);

                        pEnum->Release();
                    }
                    SysFreeString(pBstrFilter);
                }
                else
                    hrc = E_OUTOFMEMORY;
                pServices->Release();
            }
            pLoc->Release();
        }
        SysFreeString(pBstrPropName);
    }
    else
        hrc = E_OUTOFMEMORY;
    if (fUninit)
        rtSystemDmiWinTerminate();
    if (FAILED(hrc) && rc == VERR_NOT_SUPPORTED)
        rc = VERR_NOT_SUPPORTED;
    return rc;
}
Beispiel #3
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;
}
/**
 * Adds data to the internal parser buffer. Useful if there
 * are multiple rounds of adding data needed.
 *
 * @return  IPRT status code.
 * @param   pbData              Pointer to data to add.
 * @param   cbData              Size (in bytes) of data to add.
 */
int GuestProcessStream::AddData(const BYTE *pbData, size_t cbData)
{
    AssertPtrReturn(pbData, VERR_INVALID_POINTER);
    AssertReturn(cbData, VERR_INVALID_PARAMETER);

    int rc = VINF_SUCCESS;

    /* Rewind the buffer if it's empty. */
    size_t     cbInBuf   = m_cbSize - m_cbOffset;
    bool const fAddToSet = cbInBuf == 0;
    if (fAddToSet)
        m_cbSize = m_cbOffset = 0;

    /* Try and see if we can simply append the data. */
    if (cbData + m_cbSize <= m_cbAllocated)
    {
        memcpy(&m_pbBuffer[m_cbSize], pbData, cbData);
        m_cbSize += cbData;
    }
    else
    {
        /* Move any buffered data to the front. */
        cbInBuf = m_cbSize - m_cbOffset;
        if (cbInBuf == 0)
            m_cbSize = m_cbOffset = 0;
        else if (m_cbOffset) /* Do we have something to move? */
        {
            memmove(m_pbBuffer, &m_pbBuffer[m_cbOffset], cbInBuf);
            m_cbSize = cbInBuf;
            m_cbOffset = 0;
        }

        /* Do we need to grow the buffer? */
        if (cbData + m_cbSize > m_cbAllocated)
        {
            size_t cbAlloc = m_cbSize + cbData;
            cbAlloc = RT_ALIGN_Z(cbAlloc, _64K);
            void *pvNew = RTMemRealloc(m_pbBuffer, cbAlloc);
            if (pvNew)
            {
                m_pbBuffer = (uint8_t *)pvNew;
                m_cbAllocated = cbAlloc;
            }
            else
                rc = VERR_NO_MEMORY;
        }

        /* Finally, copy the data. */
        if (RT_SUCCESS(rc))
        {
            if (cbData + m_cbSize <= m_cbAllocated)
            {
                memcpy(&m_pbBuffer[m_cbSize], pbData, cbData);
                m_cbSize += cbData;
            }
            else
                rc = VERR_BUFFER_OVERFLOW;
        }
    }

    return rc;
}
extern "C" int RTWinSocketPair(int domain, int type, int protocol, SOCKET socket_vector[2])
{
    LogFlowFunc(("ENTER: domain:%d, type:%d, protocol:%d, socket_vector:%p\n",
		 domain, type, protocol, socket_vector));
    switch (domain)
    {
    case AF_INET:
	break;
    case AF_INET6: /* I dobt we really need it. */
    default:
	AssertMsgFailedReturn(("Unsuported domain:%d\n", domain), 
	  		      VERR_INVALID_PARAMETER);
    }
    
    switch(type)
    {
    case SOCK_STREAM:
    case SOCK_DGRAM:
	break;
    default:
	AssertMsgFailedReturn(("Unsuported type:%d\n", type), 
	 		      VERR_INVALID_PARAMETER);
    }
    
    AssertPtrReturn(socket_vector, VERR_INVALID_PARAMETER);
    if (!socket_vector)
      return VERR_INVALID_PARAMETER;

    socket_vector[0] = socket_vector[1] = INVALID_SOCKET;

    SOCKET listener = INVALID_SOCKET;
    
    union {
	struct sockaddr_in in_addr;
	struct sockaddr addr;
    } sa[2];

    int cb = sizeof(sa);
    memset(&sa, 0, cb);

    sa[0].in_addr.sin_family = domain;
    sa[0].in_addr.sin_addr.s_addr = RT_H2N_U32(INADDR_LOOPBACK);
    sa[0].in_addr.sin_port = 0;
    cb = sizeof(sa[0]);

    if (type == SOCK_STREAM)
    {
	listener = WSASocket(domain, type, protocol, 0, NULL, 0);
    
	if (listener == INVALID_SOCKET)
	{
	    return VERR_INTERNAL_ERROR;
	}
    
	int reuse = 1;
	cb = sizeof(int);
	int rc = setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, cb);

	if (rc)
	{
	    goto close_socket;
	}
    
	cb = sizeof(sa[0]);
	rc = bind(listener, &sa[0].addr, cb);
	if(rc)
	{
	    goto close_socket;
	}

	memset(&sa[0], 0, cb);
	rc = getsockname(listener, &sa[0].addr, &cb);
	if (rc)
	{
	    goto close_socket;
	}

	rc = listen(listener, 1);
	if (rc)
	{
	    goto close_socket;
	}
    
	socket_vector[0] = WSASocket(domain, type, protocol, 0, NULL, 0);
	if (socket_vector[0] == INVALID_SOCKET)
	{
	    goto close_socket;
	}

	rc = connect(socket_vector[0], &sa[0].addr, cb);
	if (rc)
	  goto close_socket;

    
	socket_vector[1] = accept(listener, NULL, NULL);
	if (socket_vector[1] == INVALID_SOCKET)
	{
	    goto close_socket;
	}

	closesocket(listener);
    }
    else
    {
	socket_vector[0] = WSASocket(domain, type, protocol, 0, NULL, 0);
	
	cb = sizeof(sa[0]);
	int rc = bind(socket_vector[0], &sa[0].addr, cb);
	Assert(rc != SOCKET_ERROR);
	if (rc == SOCKET_ERROR)
	{
	    goto close_socket;
	}

	sa[1].in_addr.sin_family = domain;
	sa[1].in_addr.sin_addr.s_addr = RT_H2N_U32(INADDR_LOOPBACK);
	sa[1].in_addr.sin_port = 0;

	socket_vector[1] = WSASocket(domain, type, protocol, 0, NULL, 0);
	rc = bind(socket_vector[1], &sa[1].addr, cb);
	Assert(rc != SOCKET_ERROR);
	if (rc == SOCKET_ERROR)
	{
	    goto close_socket;
	}

	{
	    u_long mode = 0;
	    rc = ioctlsocket(socket_vector[0], FIONBIO, &mode);
	    AssertMsgReturn(rc != SOCKET_ERROR, 
			    ("ioctl error: %d\n", WSAGetLastError()),
			    VERR_INTERNAL_ERROR);

	    rc = ioctlsocket(socket_vector[1], FIONBIO, &mode);
	    AssertMsgReturn(rc != SOCKET_ERROR, 
			    ("ioctl error: %d\n", WSAGetLastError()),
			    VERR_INTERNAL_ERROR);
	}

	memset(&sa, 0, 2 * cb);
	rc = getsockname(socket_vector[0], &sa[0].addr, &cb);
	Assert(rc != SOCKET_ERROR);
	if (rc == SOCKET_ERROR)
	{
	    goto close_socket;
	}

	rc = getsockname(socket_vector[1], &sa[1].addr, &cb);
	Assert(rc != SOCKET_ERROR);
	if (rc == SOCKET_ERROR)
	{
	    goto close_socket;
	}

	rc = connect(socket_vector[0], &sa[1].addr, cb);
	Assert(rc != SOCKET_ERROR);
	if (rc == SOCKET_ERROR)
	{
	    goto close_socket;
	}

	rc = connect(socket_vector[1], &sa[0].addr, cb);
	Assert(rc != SOCKET_ERROR);
	if (rc == SOCKET_ERROR)
	{
	    goto close_socket;
	}
    }
    LogFlowFuncLeaveRC(VINF_SUCCESS);
    return VINF_SUCCESS;

close_socket:
    if (listener != INVALID_SOCKET)
      closesocket(listener);

    if (socket_vector[0] != INVALID_SOCKET)
      closesocket(socket_vector[0]);

    if (socket_vector[1] != INVALID_SOCKET)
      closesocket(socket_vector[1]);

    LogFlowFuncLeaveRC(VERR_INTERNAL_ERROR);
    return VERR_INTERNAL_ERROR;
}
/**
 * Retrieves the data stored in this object and store the result in
 * pMedium.
 *
 * @return  IPRT status code.
 * @return  HRESULT
 * @param   pFormatEtc
 * @param   pMedium
 */
STDMETHODIMP UIDnDDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
{
    AssertPtrReturn(pFormatEtc, DV_E_FORMATETC);
    AssertPtrReturn(pMedium, DV_E_FORMATETC);

    HRESULT hr = DV_E_FORMATETC;

    LPFORMATETC pThisFormat = NULL;
    LPSTGMEDIUM pThisMedium = NULL;

    LogFlowThisFunc(("\n"));

    /* Format supported? */
    ULONG lIndex;
    if (   LookupFormatEtc(pFormatEtc, &lIndex)
        && lIndex < m_cFormats) /* Paranoia. */
    {
        pThisMedium = &m_pStgMedium[lIndex];
        AssertPtr(pThisMedium);
        pThisFormat = &m_pFormatEtc[lIndex];
        AssertPtr(pThisFormat);

        LogFlowThisFunc(("pThisMedium=%p, pThisFormat=%p\n", pThisMedium, pThisFormat));
        LogFlowThisFunc(("mStatus=%RU32\n", m_enmStatus));
        switch (m_enmStatus)
        {
            case DnDDataObjectStatus_Dropping:
            {
#if 0
                LogRel3(("DnD: Dropping\n"));
                LogFlowFunc(("Waiting for event ...\n"));
                int rc2 = RTSemEventWait(m_SemEvent, RT_INDEFINITE_WAIT);
                LogFlowFunc(("rc=%Rrc, mStatus=%RU32\n", rc2, m_enmStatus));
#endif
                break;
            }

            case DnDDataObjectStatus_Dropped:
            {
                LogRel3(("DnD: Dropped\n"));
                LogRel3(("DnD: cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32\n",
                         pThisFormat->cfFormat, UIDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
                         pThisFormat->tymed, pThisFormat->dwAspect));
                LogRel3(("DnD: Got strFormat=%s, pvData=%p, cbData=%RU32\n",
                         m_strFormat.toAscii().constData(), m_pvData, m_cbData));

                QVariant::Type vaType;
                QString strMIMEType;
                if (    (pFormatEtc->tymed & TYMED_HGLOBAL)
                     && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
                     && (   pFormatEtc->cfFormat == CF_TEXT
                         || pFormatEtc->cfFormat == CF_UNICODETEXT)
                   )
                {
                    strMIMEType = "text/plain"; /** @todo Indicate UTF8 encoding? */
                    vaType = QVariant::String;
                }
                else if (   (pFormatEtc->tymed & TYMED_HGLOBAL)
                         && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
                         && (pFormatEtc->cfFormat == CF_HDROP))
                {
                    strMIMEType = "text/uri-list";
                    vaType = QVariant::StringList;
                }
#if 0 /* More formats; not needed right now. */
                else if (   (pFormatEtc->tymed & TYMED_ISTREAM)
                        && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
                        && (pFormatEtc->cfFormat == CF_FILECONTENTS))
                {

                }
                else if  (   (pFormatEtc->tymed & TYMED_HGLOBAL)
                          && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
                          && (pFormatEtc->cfFormat == CF_FILEDESCRIPTOR))
                {

                }
                else if (   (pFormatEtc->tymed & TYMED_HGLOBAL)
                         && (pFormatEtc->cfFormat == CF_PREFERREDDROPEFFECT))
                {
                    HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, sizeof(DWORD));
                    DWORD *pdwEffect = (DWORD *)GlobalLock(hData);
                    AssertPtr(pdwEffect);
                    *pdwEffect = DROPEFFECT_COPY;
                    GlobalUnlock(hData);

                    pMedium->hGlobal = hData;
                    pMedium->tymed = TYMED_HGLOBAL;
                }
#endif
                LogRel3(("DnD: strMIMEType=%s, vaType=%ld\n", strMIMEType.toAscii().constData(), vaType));

                int rc;

                if (!m_fDataRetrieved)
                {
                    if (m_pDnDHandler)
                    {
                        rc = m_pDnDHandler->retrieveData(Qt::CopyAction,
                                                         strMIMEType, vaType, m_vaData);
                    }
                    else
                        rc = VERR_NOT_FOUND;

                    m_fDataRetrieved = true;
                    LogFlowFunc(("Retrieving data ended with %Rrc\n", rc));
                }
                else /* Data already been retrieved. */
                    rc = VINF_SUCCESS;

                if (   RT_SUCCESS(rc)
                    && m_vaData.isValid())
                {
                    if (   strMIMEType.startsWith("text/uri-list")
                               /* One item. */
                        && (   m_vaData.canConvert(QVariant::String)
                               /* Multiple items. */
                            || m_vaData.canConvert(QVariant::StringList))
                       )
                    {
                        QStringList lstFilesURI = m_vaData.toStringList();
                        QStringList lstFiles;
                        for (size_t i = 0; i < lstFilesURI.size(); i++)
                        {
                            char *pszFilePath = RTUriFilePath(lstFilesURI.at(i).toAscii().constData());
                            if (pszFilePath)
                            {
                                lstFiles.append(pszFilePath);
                                RTStrFree(pszFilePath);
                            }
                            else /* Unable to parse -- refuse entire request. */
                            {
                                lstFiles.clear();
                                rc = VERR_INVALID_PARAMETER;
                                break;
                            }
                        }

                        size_t cFiles = lstFiles.size();
                        LogFlowThisFunc(("Files (%zu)\n", cFiles));
                        if (   RT_SUCCESS(rc)
                            && cFiles)
                        {
                            size_t cchFiles = 0; /* Number of characters. */
                            for (size_t i = 0; i < cFiles; i++)
                            {
                                const char *pszFile = lstFiles.at(i).toAscii().constData();
                                cchFiles += strlen(pszFile);
                                cchFiles += 1; /* Terminating '\0'. */
                                LogFlowThisFunc(("\tFile: %s (cchFiles=%zu)\n", pszFile, cchFiles));
                            }

                            /* List termination with '\0'. */
                            cchFiles++;

                            size_t cbBuf = sizeof(DROPFILES) + (cchFiles * sizeof(RTUTF16));
                            DROPFILES *pDropFiles = (DROPFILES *)RTMemAllocZ(cbBuf);
                            if (pDropFiles)
                            {
                                /* Put the files list right after our DROPFILES structure. */
                                pDropFiles->pFiles = sizeof(DROPFILES); /* Offset to file list. */
                                pDropFiles->fWide  = 1;                 /* We use Unicode. Always. */

                                uint8_t *pCurFile = (uint8_t *)pDropFiles + pDropFiles->pFiles;
                                AssertPtr(pCurFile);

                                LogFlowThisFunc(("Encoded:\n"));
                                for (size_t i = 0; i < cFiles; i++)
                                {
                                    const char *pszFile = lstFiles.at(i).toUtf8().constData();
                                    Assert(strlen(pszFile));

                                    size_t cchCurFile;
                                    PRTUTF16 pwszFile;
                                    rc = RTStrToUtf16(pszFile, &pwszFile);
                                    if (RT_SUCCESS(rc))
                                    {
                                        cchCurFile = RTUtf16Len(pwszFile);
                                        Assert(cchCurFile);
                                        memcpy(pCurFile, pwszFile, cchCurFile * sizeof(RTUTF16));
                                        RTUtf16Free(pwszFile);
                                    }
                                    else
                                        break;

                                    pCurFile += cchCurFile * sizeof(RTUTF16);

                                    /* Terminate current file name. */
                                    *pCurFile = L'\0';
                                    pCurFile += sizeof(RTUTF16);

                                    LogFlowThisFunc(("\t#%zu: cchCurFile=%zu\n", i, cchCurFile));
                                }

                                if (RT_SUCCESS(rc))
                                {
                                    *pCurFile = L'\0'; /* Final list terminator. */

                                    /*
                                     * Fill out the medium structure we're going to report back.
                                     */
                                    pMedium->tymed          = TYMED_HGLOBAL;
                                    pMedium->pUnkForRelease = NULL;
                                    pMedium->hGlobal        = GlobalAlloc(  GMEM_ZEROINIT
                                                                          | GMEM_MOVEABLE
                                                                          | GMEM_DDESHARE, cbBuf);
                                    if (pMedium->hGlobal)
                                    {
                                        LPVOID pvMem = GlobalLock(pMedium->hGlobal);
                                        if (pvMem)
                                        {
                                            memcpy(pvMem, pDropFiles, cbBuf);
                                            GlobalUnlock(pMedium->hGlobal);

                                            hr = S_OK;
                                        }
                                        else
                                            rc = VERR_ACCESS_DENIED;
                                    }
                                    else
                                        rc = VERR_NO_MEMORY;

                                    LogFlowThisFunc(("Copying to TYMED_HGLOBAL (%zu bytes): %Rrc\n", cbBuf, rc));
                                }

                                RTMemFree(pDropFiles);
                            }
                            else
                                rc = VERR_NO_MEMORY;

                            if (RT_FAILURE(rc))
                                LogFlowThisFunc(("Failed with %Rrc\n", rc));
                        }
                    }
                    else if (   strMIMEType.startsWith("text/plain")
                             && m_vaData.canConvert(QVariant::String))
                    {
                        const bool fUnicode = pFormatEtc->cfFormat == CF_UNICODETEXT;
                        const size_t cbCh   = fUnicode
                                            ? sizeof(WCHAR) : sizeof(char);

                        QString strText = m_vaData.toString();
                        size_t cbSrc = strText.length() * cbCh;
                        Assert(cbSrc);
                        LPCVOID pvSrc = fUnicode
                                      ? (void *)strText.unicode()
                                      : (void *)strText.toAscii().constData();
                        AssertPtr(pvSrc);

                        LogFlowFunc(("pvSrc=0x%p, cbSrc=%zu, cbCh=%zu, fUnicode=%RTbool\n",
                                     pvSrc, cbSrc, cbCh, fUnicode));

                        pMedium->tymed          = TYMED_HGLOBAL;
                        pMedium->pUnkForRelease = NULL;
                        pMedium->hGlobal        = GlobalAlloc(GHND | GMEM_SHARE, cbSrc);
                        if (pMedium->hGlobal)
                        {
                            LPVOID pvDst = GlobalLock(pMedium->hGlobal);
                            if (pvDst)
                            {
                                memcpy(pvDst, pvSrc, cbSrc);
                                GlobalUnlock(pMedium->hGlobal);
                            }
                            else
                                rc = VERR_ACCESS_DENIED;

                            hr = S_OK;
                        }
                        else
                            hr  = VERR_NO_MEMORY;
                    }
                    else
                        LogRel2(("DnD: MIME type '%s' not supported\n", strMIMEType.toAscii().constData()));

                    LogFlowThisFunc(("Handling formats ended with rc=%Rrc\n", rc));
                }

                break;
            }

            default:
                break;
        }
    }

    /*
     * Fallback in error case.
     */
    if (FAILED(hr))
    {
        if (pThisMedium)
        {
            switch (pThisMedium->tymed)
            {

            case TYMED_HGLOBAL:
                pMedium->hGlobal = (HGLOBAL)OleDuplicateData(pThisMedium->hGlobal,
                                                             pThisFormat->cfFormat,
                                                             0 /* Flags */);
                break;

            default:
                break;
            }
        }

        if (pFormatEtc)
            pMedium->tymed = pFormatEtc->tymed;

        pMedium->pUnkForRelease = NULL;
    }

    LogFlowThisFunc(("Returning hr=%Rhrc\n", hr));
    return hr;
}
static int solarisWalkDeviceNode(di_node_t Node, void *pvArg)
{
    PUSBDEVICELIST pList = (PUSBDEVICELIST)pvArg;
    AssertPtrReturn(pList, DI_WALK_TERMINATE);

    /*
     * Check if it's a USB device in the first place.
     */
    bool fUSBDevice = false;
    char *pszCompatNames = NULL;
    int cCompatNames = di_compatible_names(Node, &pszCompatNames);
    for (int i = 0; i < cCompatNames; i++, pszCompatNames += strlen(pszCompatNames) + 1)
        if (!strncmp(pszCompatNames, RT_STR_TUPLE("usb")))
        {
            fUSBDevice = true;
            break;
        }

    if (!fUSBDevice)
        return DI_WALK_CONTINUE;

    /*
     * Check if it's a device node or interface.
     */
    int *pInt = NULL;
    char *pStr = NULL;
    int rc = DI_WALK_CONTINUE;
    if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "interface", &pInt) < 0)
    {
        /* It's a device node. */
        char *pszDevicePath = di_devfs_path(Node);
        PUSBDEVICE pCur = (PUSBDEVICE)RTMemAllocZ(sizeof(*pCur));
        if (!pCur)
        {
            LogRel(("USBService: failed to allocate %d bytes for PUSBDEVICE.\n", sizeof(*pCur)));
            return DI_WALK_TERMINATE;
        }

        bool fValidDevice = false;
        do
        {
            AssertBreak(pszDevicePath);

            char *pszDriverName = di_driver_name(Node);

            /*
             * Skip hubs
             */
            if (   pszDriverName
                && !strcmp(pszDriverName, "hubd"))
            {
                break;
            }

            /*
             * Mandatory.
             * snv_85 and above have usb-dev-descriptor node properties, but older one's do not.
             * So if we cannot obtain the entire device descriptor, we try falling back to the
             * individual properties (those must not fail, if it does we drop the device).
             */
            uchar_t *pDevData = NULL;
            int cbProp = di_prop_lookup_bytes(DDI_DEV_T_ANY, Node, "usb-dev-descriptor", &pDevData);
            if (   cbProp > 0
                && pDevData)
            {
                usb_dev_descr_t *pDeviceDescriptor = (usb_dev_descr_t *)pDevData;
                pCur->bDeviceClass = pDeviceDescriptor->bDeviceClass;
                pCur->bDeviceSubClass = pDeviceDescriptor->bDeviceSubClass;
                pCur->bDeviceProtocol = pDeviceDescriptor->bDeviceProtocol;
                pCur->idVendor = pDeviceDescriptor->idVendor;
                pCur->idProduct = pDeviceDescriptor->idProduct;
                pCur->bcdDevice = pDeviceDescriptor->bcdDevice;
                pCur->bcdUSB = pDeviceDescriptor->bcdUSB;
                pCur->bNumConfigurations = pDeviceDescriptor->bNumConfigurations;
                pCur->fPartialDescriptor = false;
            }
            else
            {
                AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-vendor-id", &pInt) > 0);
                pCur->idVendor = (uint16_t)*pInt;

                AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-product-id", &pInt) > 0);
                pCur->idProduct = (uint16_t)*pInt;

                AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-revision-id", &pInt) > 0);
                pCur->bcdDevice = (uint16_t)*pInt;

                AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-release", &pInt) > 0);
                pCur->bcdUSB = (uint16_t)*pInt;

                pCur->fPartialDescriptor = true;
            }

            char *pszPortAddr = di_bus_addr(Node);
            if (pszPortAddr)
                pCur->bPort = RTStrToUInt8(pszPortAddr);     /* Bus & Port are mixed up (kernel driver/userland) */
            else
                pCur->bPort = 0;

            char szBuf[PATH_MAX + 48];
            RTStrPrintf(szBuf, sizeof(szBuf), "%#x:%#x:%d:%s", pCur->idVendor, pCur->idProduct, pCur->bcdDevice, pszDevicePath);
            pCur->pszAddress = RTStrDup(szBuf);
            AssertBreak(pCur->pszAddress);

            pCur->pszDevicePath = RTStrDup(pszDevicePath);
            AssertBreak(pCur->pszDevicePath);

            pCur->pszBackend = RTStrDup("host");
            AssertBreak(pCur->pszBackend);

            /*
             * Optional (some devices don't have all these)
             */
            char *pszCopy;
            if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-product-name", &pStr) > 0)
            {
                pCur->pszProduct = pszCopy = RTStrDup(pStr);
                USBLibPurgeEncoding(pszCopy);
            }

            if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-vendor-name", &pStr) > 0)
            {
                pCur->pszManufacturer = pszCopy = RTStrDup(pStr);
                USBLibPurgeEncoding(pszCopy);
            }

            if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-serialno", &pStr) > 0)
            {
                pCur->pszSerialNumber = pszCopy = RTStrDup(pStr);
                USBLibPurgeEncoding(pszCopy);
            }

            if (pCur->bcdUSB == 0x300)
                pCur->enmSpeed = USBDEVICESPEED_SUPER;
            else if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "low-speed", &pInt) >= 0)
                pCur->enmSpeed = USBDEVICESPEED_LOW;
            else if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "high-speed", &pInt) >= 0)
                pCur->enmSpeed = USBDEVICESPEED_HIGH;
            else
                pCur->enmSpeed = USBDEVICESPEED_FULL;

            /* Determine state of the USB device. */
            pCur->enmState = solarisDetermineUSBDeviceState(pCur, Node);

            /*
             * Valid device, add it to the list.
             */
            fValidDevice = true;
            pCur->pPrev = pList->pTail;
            if (pList->pTail)
                pList->pTail = pList->pTail->pNext = pCur;
            else
                pList->pTail = pList->pHead = pCur;

            rc = DI_WALK_CONTINUE;
        } while (0);

        di_devfs_path_free(pszDevicePath);
        if (!fValidDevice)
            solarisFreeUSBDevice(pCur);
    }
    return rc;
}
Beispiel #8
0
RTDECL(int) RTDirRead(PRTDIR pDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry)
{
    int rc;

    /*
     * Validate input.
     */
    AssertPtrReturn(pDir, VERR_INVALID_POINTER);
    AssertReturn(pDir->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
    AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
    size_t cbDirEntry = sizeof(*pDirEntry);
    if (pcbDirEntry)
    {
        cbDirEntry = *pcbDirEntry;
        AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRY, szName[2]),
                        ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRY, szName[2])),
                        VERR_INVALID_PARAMETER);
    }

    /*
     * Fetch data?
     */
    if (!pDir->fDataUnread)
    {
        rc = rtDirNtFetchMore(pDir);
        if (RT_FAILURE(rc))
            return rc;
    }

    /*
     * Convert the filename to UTF-8.
     */
    rc = rtDirNtConvertCurName(pDir);
    if (RT_FAILURE(rc))
        return 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)
        return VERR_BUFFER_OVERFLOW;

    /*
     * Setup the returned data.
     */
    pDirEntry->cbName = (uint16_t)cchName;
    Assert(pDirEntry->cbName == cchName);
    memcpy(pDirEntry->szName, pszName, cchName + 1);

    pDirEntry->INodeId = pDir->enmInfoClass == FileIdBothDirectoryInformation
                         ? pDir->uCurData.pBothId->FileId.QuadPart : 0;

#ifdef IPRT_WITH_NT_PATH_PASSTHRU
    if (pDir->enmInfoClass != FileMaximumInformation)
#endif
    {
        switch (   pDir->uCurData.pBoth->FileAttributes
                   & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY))
        {
        default:
            AssertFailed();
        case 0:
            pDirEntry->enmType = RTDIRENTRYTYPE_FILE;
            break;

        case FILE_ATTRIBUTE_DIRECTORY:
            pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY;
            break;

        case FILE_ATTRIBUTE_REPARSE_POINT:
        case FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY:
            pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK;
            break;
        }
    }
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
    else
    {
        pDirEntry->enmType = RTDIRENTRYTYPE_UNKNOWN;
        if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
                                    RT_STR_TUPLE("Directory")))
            pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY;
        else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
                                         RT_STR_TUPLE("SymbolicLink")))
            pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK;
    }
#endif

    return rtDirNtAdvanceBuffer(pDir);
}
Beispiel #9
0
RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
                        RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
{
    int rc;

    /*
     * Validate input.
     */
    AssertPtrReturn(pDir, VERR_INVALID_POINTER);
    AssertReturn(pDir->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
    AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);

    AssertReturn(enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST,
                 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;
        AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]),
                        ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])),
                        VERR_INVALID_PARAMETER);
    }

    /*
     * Fetch data?
     */
    if (!pDir->fDataUnread)
    {
        rc = rtDirNtFetchMore(pDir);
        if (RT_FAILURE(rc))
            return rc;
    }

    /*
     * Convert the filename to UTF-8.
     */
    rc = rtDirNtConvertCurName(pDir);
    if (RT_FAILURE(rc))
        return 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)
        return VERR_BUFFER_OVERFLOW;

    /*
     * Setup the returned data.
     */
    PFILE_BOTH_DIR_INFORMATION pBoth = pDir->uCurData.pBoth;

    pDirEntry->cbName  = (uint16_t)cchName;
    Assert(pDirEntry->cbName == cchName);
    memcpy(pDirEntry->szName, pszName, cchName + 1);
    memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName));
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
    if (pDir->enmInfoClass != FileMaximumInformation)
#endif
    {
        uint8_t cbShort = pBoth->ShortNameLength;
        if (cbShort > 0)
        {
            AssertStmt(cbShort < sizeof(pDirEntry->wszShortName), cbShort = sizeof(pDirEntry->wszShortName) - 2);
            memcpy(pDirEntry->wszShortName, pBoth->ShortName, cbShort);
            pDirEntry->cwcShortName = cbShort / 2;
        }
        else
            pDirEntry->cwcShortName = 0;

        pDirEntry->Info.cbObject    = pBoth->EndOfFile.QuadPart;
        pDirEntry->Info.cbAllocated = pBoth->AllocationSize.QuadPart;

        Assert(sizeof(uint64_t) == sizeof(pBoth->CreationTime));
        RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime,         pBoth->CreationTime.QuadPart);
        RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime,        pBoth->LastAccessTime.QuadPart);
        RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime,  pBoth->LastWriteTime.QuadPart);
        RTTimeSpecSetNtTime(&pDirEntry->Info.ChangeTime,        pBoth->ChangeTime.QuadPart);

        pDirEntry->Info.Attr.fMode  = rtFsModeFromDos((pBoth->FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
                                      pszName, cchName);
    }
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
    else
    {
        pDirEntry->cwcShortName = 0;
        pDirEntry->Info.cbObject    = 0;
        pDirEntry->Info.cbAllocated = 0;
        RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime,         0);
        RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime,        0);
        RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime,  0);
        RTTimeSpecSetNtTime(&pDirEntry->Info.ChangeTime,        0);

        if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
                                    RT_STR_TUPLE("Directory")))
            pDirEntry->Info.Attr.fMode = RTFS_DOS_DIRECTORY | RTFS_TYPE_DIRECTORY | 0777;
        else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
                                         RT_STR_TUPLE("SymbolicLink")))
            pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_REPARSE_POINT | RTFS_TYPE_SYMLINK | 0777;
        else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
                                         RT_STR_TUPLE("Device")))
            pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_DEVICE | RTFS_TYPE_DEV_CHAR | 0666;
        else
            pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FILE | 0666;
    }
#endif

    /*
     * Requested attributes (we cannot provide anything actually).
     */
    switch (enmAdditionalAttribs)
    {
    case RTFSOBJATTRADD_EASIZE:
        pDirEntry->Info.Attr.enmAdditional          = RTFSOBJATTRADD_EASIZE;
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
        if (pDir->enmInfoClass == FileMaximumInformation)
            pDirEntry->Info.Attr.u.EASize.cb        = 0;
        else
#endif
            pDirEntry->Info.Attr.u.EASize.cb        = pBoth->EaSize;
        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;
    }

    /*
     * Follow links if requested.
     */
    if (   (fFlags & RTPATH_F_FOLLOW_LINK)
            && RTFS_IS_SYMLINK(fFlags))
    {
        /** @todo Symlinks: Find[First|Next]FileW will return info about
            the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */
    }

    /*
     * Finally advance the buffer.
     */
    return rtDirNtAdvanceBuffer(pDir);
}
static int drvHostPulseAudioOpen(bool fIn, const char *pszName,
                                 pa_sample_spec *pSampleSpec, pa_buffer_attr *pBufAttr,
                                 pa_stream **ppStream)
{
    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
    AssertPtrReturn(pSampleSpec, VERR_INVALID_POINTER);
    AssertPtrReturn(pBufAttr, VERR_INVALID_POINTER);
    AssertPtrReturn(ppStream, VERR_INVALID_POINTER);

    if (!pa_sample_spec_valid(pSampleSpec))
    {
        LogRel(("PulseAudio: Unsupported sample specification for stream \"%s\"\n",
                pszName));
        return VERR_NOT_SUPPORTED;
    }

    int rc = VINF_SUCCESS;

    pa_stream *pStream = NULL;
    uint32_t   flags = PA_STREAM_NOFLAGS;

    LogFunc(("Opening \"%s\", rate=%dHz, channels=%d, format=%s\n",
             pszName, pSampleSpec->rate, pSampleSpec->channels,
             pa_sample_format_to_string(pSampleSpec->format)));

    pa_threaded_mainloop_lock(g_pMainLoop);

    do
    {
        if (!(pStream = pa_stream_new(g_pContext, pszName, pSampleSpec,
                                      NULL /* pa_channel_map */)))
        {
            LogRel(("PulseAudio: Could not create stream \"%s\"\n", pszName));
            rc = VERR_NO_MEMORY;
            break;
        }

        pa_stream_set_state_callback(pStream, drvHostPulseAudioCbStreamState, NULL);

#if PA_API_VERSION >= 12
        /* XXX */
        flags |= PA_STREAM_ADJUST_LATENCY;
#endif

#if 0
        /* Not applicable as we don't use pa_stream_get_latency() and pa_stream_get_time(). */
        flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
#endif
        /* No input/output right away after the stream was started. */
        flags |= PA_STREAM_START_CORKED;

        if (fIn)
        {
            LogFunc(("Input stream attributes: maxlength=%d fragsize=%d\n",
                     pBufAttr->maxlength, pBufAttr->fragsize));

            if (pa_stream_connect_record(pStream, /*dev=*/NULL, pBufAttr, (pa_stream_flags_t)flags) < 0)
            {
                LogRel(("PulseAudio: Could not connect input stream \"%s\": %s\n",
                        pszName, pa_strerror(pa_context_errno(g_pContext))));
                rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                break;
            }
        }
        else
        {
            LogFunc(("Output buffer attributes: maxlength=%d tlength=%d prebuf=%d minreq=%d\n",
                     pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq));

            if (pa_stream_connect_playback(pStream, /*dev=*/NULL, pBufAttr, (pa_stream_flags_t)flags,
                                           /*cvolume=*/NULL, /*sync_stream=*/NULL) < 0)
            {
                LogRel(("PulseAudio: Could not connect playback stream \"%s\": %s\n",
                        pszName, pa_strerror(pa_context_errno(g_pContext))));
                rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                break;
            }
        }

        /* Wait until the stream is ready. */
        pa_stream_state_t sstate;
        for (;;)
        {
            pa_threaded_mainloop_wait(g_pMainLoop);

            sstate = pa_stream_get_state(pStream);
            if (sstate == PA_STREAM_READY)
                break;
            else if (   sstate == PA_STREAM_FAILED
                     || sstate == PA_STREAM_TERMINATED)
            {
                LogRel(("PulseAudio: Failed to initialize stream \"%s\" (state %ld)\n",
                        pszName, sstate));
                rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                break;
            }
        }

        if (RT_FAILURE(rc))
            break;

        const pa_buffer_attr *pBufAttrObtained = pa_stream_get_buffer_attr(pStream);
        AssertPtr(pBufAttrObtained);
        memcpy(pBufAttr, pBufAttrObtained, sizeof(pa_buffer_attr));

        if (fIn)
            LogFunc(("Obtained record buffer attributes: maxlength=%RU32, fragsize=%RU32\n",
                     pBufAttr->maxlength, pBufAttr->fragsize));
        else
            LogFunc(("Obtained playback buffer attributes: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d\n",
                     pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq));

        pa_threaded_mainloop_unlock(g_pMainLoop);
    }
    while (0);

    if (RT_FAILURE(rc))
    {
        if (pStream)
            pa_stream_disconnect(pStream);

        pa_threaded_mainloop_unlock(g_pMainLoop);

        if (pStream)
            pa_stream_unref(pStream);
    }
    else
        *ppStream = pStream;

    LogFlowFuncLeaveRC(rc);
    return rc;
}
static DECLCALLBACK(int) drvHostPulseAudioInitOut(PPDMIHOSTAUDIO pInterface,
                                                  PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfg,
                                                  uint32_t *pcSamples)
{
    NOREF(pInterface);
    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
    /* pcSamples is optional. */

    PPULSEAUDIOSTREAM pThisStrmOut = (PPULSEAUDIOSTREAM)pHstStrmOut;

    LogFlowFuncEnter();

    pThisStrmOut->pDrainOp            = NULL;

    pThisStrmOut->SampleSpec.format   = drvHostPulseAudioFmtToPulse(pCfg->enmFormat);
    pThisStrmOut->SampleSpec.rate     = pCfg->uHz;
    pThisStrmOut->SampleSpec.channels = pCfg->cChannels;

    /* Note that setting maxlength to -1 does not work on PulseAudio servers
     * older than 0.9.10. So use the suggested value of 3/2 of tlength */
    pThisStrmOut->BufAttr.tlength     =   (pa_bytes_per_second(&pThisStrmOut->SampleSpec)
                                        * s_pulseCfg.buffer_msecs_out) / 1000;
    pThisStrmOut->BufAttr.maxlength   = (pThisStrmOut->BufAttr.tlength * 3) / 2;
    pThisStrmOut->BufAttr.prebuf      = -1; /* Same as tlength */
    pThisStrmOut->BufAttr.minreq      = -1; /* Pulse should set something sensible for minreq on it's own */

    /* Note that the struct BufAttr is updated to the obtained values after this call! */
    int rc = drvHostPulseAudioOpen(false /* fIn */, "pa.out", &pThisStrmOut->SampleSpec, &pThisStrmOut->BufAttr,
                                   &pThisStrmOut->pStream);
    if (RT_FAILURE(rc))
        return rc;

    PDMAUDIOSTREAMCFG streamCfg;
    rc = drvHostPulseAudioPulseToFmt(pThisStrmOut->SampleSpec.format,
                                     &streamCfg.enmFormat, &streamCfg.enmEndianness);
    if (RT_FAILURE(rc))
    {
        LogRel(("PulseAudio: Cannot find audio output format %ld\n", pThisStrmOut->SampleSpec.format));
        return rc;
    }

    streamCfg.uHz       = pThisStrmOut->SampleSpec.rate;
    streamCfg.cChannels = pThisStrmOut->SampleSpec.channels;

    rc = drvAudioStreamCfgToProps(&streamCfg, &pHstStrmOut->Props);
    if (RT_SUCCESS(rc))
    {
        uint32_t cbBuf  = RT_MIN(pThisStrmOut->BufAttr.tlength * 2,
                                 pThisStrmOut->BufAttr.maxlength); /** @todo Make this configurable! */
        if (cbBuf) 
        {
            pThisStrmOut->pvPCMBuf = RTMemAllocZ(cbBuf);
            if (pThisStrmOut->pvPCMBuf)
            {
                pThisStrmOut->cbPCMBuf = cbBuf;

                uint32_t cSamples = cbBuf >> pHstStrmOut->Props.cShift;
                if (pcSamples)
                    *pcSamples = cSamples;

                LogFunc(("cbBuf=%RU32, cSamples=%RU32\n", cbBuf, cSamples));
            }
            else
                rc = VERR_NO_MEMORY;
        }
RTDECL(bool)  RTUuidIsNull(PCRTUUID pUuid)
{
    AssertPtrReturn(pUuid, true);
    return !pUuid->au64[0]
        && !pUuid->au64[1];
}
RTDECL(int)  RTUuidFromUtf16(PRTUUID pUuid, PCRTUTF16 pwszString)
{
    bool fHaveBraces;

    /*
     * Validate parameters.
     */
    AssertPtrReturn(pUuid, VERR_INVALID_PARAMETER);
    AssertPtrReturn(pwszString, VERR_INVALID_PARAMETER);

    fHaveBraces = pwszString[0] == '{';
    pwszString += fHaveBraces;

#define MY_CHECK(expr) do { if (RT_UNLIKELY(!(expr))) return VERR_INVALID_UUID_FORMAT; } while (0)
#define MY_ISXDIGIT(ch) (!((ch) & 0xff00) && g_au8Digits[(ch) & 0xff] != 0xff)
    MY_CHECK(MY_ISXDIGIT(pwszString[ 0]));
    MY_CHECK(MY_ISXDIGIT(pwszString[ 1]));
    MY_CHECK(MY_ISXDIGIT(pwszString[ 2]));
    MY_CHECK(MY_ISXDIGIT(pwszString[ 3]));
    MY_CHECK(MY_ISXDIGIT(pwszString[ 4]));
    MY_CHECK(MY_ISXDIGIT(pwszString[ 5]));
    MY_CHECK(MY_ISXDIGIT(pwszString[ 6]));
    MY_CHECK(MY_ISXDIGIT(pwszString[ 7]));
    MY_CHECK(pwszString[ 8] == '-');
    MY_CHECK(MY_ISXDIGIT(pwszString[ 9]));
    MY_CHECK(MY_ISXDIGIT(pwszString[10]));
    MY_CHECK(MY_ISXDIGIT(pwszString[11]));
    MY_CHECK(MY_ISXDIGIT(pwszString[12]));
    MY_CHECK(pwszString[13] == '-');
    MY_CHECK(MY_ISXDIGIT(pwszString[14]));
    MY_CHECK(MY_ISXDIGIT(pwszString[15]));
    MY_CHECK(MY_ISXDIGIT(pwszString[16]));
    MY_CHECK(MY_ISXDIGIT(pwszString[17]));
    MY_CHECK(pwszString[18] == '-');
    MY_CHECK(MY_ISXDIGIT(pwszString[19]));
    MY_CHECK(MY_ISXDIGIT(pwszString[20]));
    MY_CHECK(MY_ISXDIGIT(pwszString[21]));
    MY_CHECK(MY_ISXDIGIT(pwszString[22]));
    MY_CHECK(pwszString[23] == '-');
    MY_CHECK(MY_ISXDIGIT(pwszString[24]));
    MY_CHECK(MY_ISXDIGIT(pwszString[25]));
    MY_CHECK(MY_ISXDIGIT(pwszString[26]));
    MY_CHECK(MY_ISXDIGIT(pwszString[27]));
    MY_CHECK(MY_ISXDIGIT(pwszString[28]));
    MY_CHECK(MY_ISXDIGIT(pwszString[29]));
    MY_CHECK(MY_ISXDIGIT(pwszString[30]));
    MY_CHECK(MY_ISXDIGIT(pwszString[31]));
    MY_CHECK(MY_ISXDIGIT(pwszString[32]));
    MY_CHECK(MY_ISXDIGIT(pwszString[33]));
    MY_CHECK(MY_ISXDIGIT(pwszString[34]));
    MY_CHECK(MY_ISXDIGIT(pwszString[35]));
    if (fHaveBraces)
        MY_CHECK(pwszString[36] == '}');
    MY_CHECK(!pwszString[36 + fHaveBraces]);
#undef MY_ISXDIGIT
#undef MY_CHECK

    /*
     * Inverse of RTUuidToUtf8 (see above).
     */
#define MY_TONUM(ch) (g_au8Digits[(ch) & 0xff])
    pUuid->Gen.u32TimeLow = RT_LE2H_U32((uint32_t)MY_TONUM(pwszString[ 0]) << 28
                          | (uint32_t)MY_TONUM(pwszString[ 1]) << 24
                          | (uint32_t)MY_TONUM(pwszString[ 2]) << 20
                          | (uint32_t)MY_TONUM(pwszString[ 3]) << 16
                          | (uint32_t)MY_TONUM(pwszString[ 4]) << 12
                          | (uint32_t)MY_TONUM(pwszString[ 5]) <<  8
                          | (uint32_t)MY_TONUM(pwszString[ 6]) <<  4
                          | (uint32_t)MY_TONUM(pwszString[ 7]));
    pUuid->Gen.u16TimeMid = RT_LE2H_U16((uint16_t)MY_TONUM(pwszString[ 9]) << 12
                          | (uint16_t)MY_TONUM(pwszString[10]) << 8
                          | (uint16_t)MY_TONUM(pwszString[11]) << 4
                          | (uint16_t)MY_TONUM(pwszString[12]));
    pUuid->Gen.u16TimeHiAndVersion = RT_LE2H_U16(
                            (uint16_t)MY_TONUM(pwszString[14]) << 12
                          | (uint16_t)MY_TONUM(pwszString[15]) << 8
                          | (uint16_t)MY_TONUM(pwszString[16]) << 4
                          | (uint16_t)MY_TONUM(pwszString[17]));
    pUuid->Gen.u8ClockSeqHiAndReserved =
                            (uint16_t)MY_TONUM(pwszString[19]) << 4
                          | (uint16_t)MY_TONUM(pwszString[20]);
    pUuid->Gen.u8ClockSeqLow =
                            (uint16_t)MY_TONUM(pwszString[21]) << 4
                          | (uint16_t)MY_TONUM(pwszString[22]);
    pUuid->Gen.au8Node[0] = (uint8_t)MY_TONUM(pwszString[24]) << 4
                          | (uint8_t)MY_TONUM(pwszString[25]);
    pUuid->Gen.au8Node[1] = (uint8_t)MY_TONUM(pwszString[26]) << 4
                          | (uint8_t)MY_TONUM(pwszString[27]);
    pUuid->Gen.au8Node[2] = (uint8_t)MY_TONUM(pwszString[28]) << 4
                          | (uint8_t)MY_TONUM(pwszString[29]);
    pUuid->Gen.au8Node[3] = (uint8_t)MY_TONUM(pwszString[30]) << 4
                          | (uint8_t)MY_TONUM(pwszString[31]);
    pUuid->Gen.au8Node[4] = (uint8_t)MY_TONUM(pwszString[32]) << 4
                          | (uint8_t)MY_TONUM(pwszString[33]);
    pUuid->Gen.au8Node[5] = (uint8_t)MY_TONUM(pwszString[34]) << 4
                          | (uint8_t)MY_TONUM(pwszString[35]);
#undef MY_TONUM
    return VINF_SUCCESS;
}
RTDECL(int)  RTUuidToUtf16(PCRTUUID pUuid, PRTUTF16 pwszString, size_t cwcString)
{
    uint32_t u32TimeLow;
    unsigned u;

    /* validate parameters */
    AssertPtrReturn(pUuid, VERR_INVALID_PARAMETER);
    AssertPtrReturn(pwszString, VERR_INVALID_PARAMETER);
    AssertReturn(cwcString >= RTUUID_STR_LENGTH, VERR_INVALID_PARAMETER);

    /*
     * RTStrPrintf(,,"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
     *             pUuid->Gen.u32TimeLow,
     *             pUuid->Gen.u16TimeMin,
     *             pUuid->Gen.u16TimeHiAndVersion,
     *             pUuid->Gen.u16ClockSeq & 0xff,
     *             pUuid->Gen.u16ClockSeq >> 8,
     *             pUuid->Gen.au8Node[0],
     *             pUuid->Gen.au8Node[1],
     *             pUuid->Gen.au8Node[2],
     *             pUuid->Gen.au8Node[3],
     *             pUuid->Gen.au8Node[4],
     *             pUuid->Gen.au8Node[5]);
     */
    u32TimeLow = RT_H2LE_U32(pUuid->Gen.u32TimeLow);
    pwszString[ 0] = g_achDigits[(u32TimeLow >> 28)/*& 0xf*/];
    pwszString[ 1] = g_achDigits[(u32TimeLow >> 24) & 0xf];
    pwszString[ 2] = g_achDigits[(u32TimeLow >> 20) & 0xf];
    pwszString[ 3] = g_achDigits[(u32TimeLow >> 16) & 0xf];
    pwszString[ 4] = g_achDigits[(u32TimeLow >> 12) & 0xf];
    pwszString[ 5] = g_achDigits[(u32TimeLow >>  8) & 0xf];
    pwszString[ 6] = g_achDigits[(u32TimeLow >>  4) & 0xf];
    pwszString[ 7] = g_achDigits[(u32TimeLow/*>>0*/)& 0xf];
    pwszString[ 8] = '-';
    u = RT_H2LE_U16(pUuid->Gen.u16TimeMid);
    pwszString[ 9] = g_achDigits[(u >> 12)/*& 0xf*/];
    pwszString[10] = g_achDigits[(u >>  8) & 0xf];
    pwszString[11] = g_achDigits[(u >>  4) & 0xf];
    pwszString[12] = g_achDigits[(u/*>>0*/)& 0xf];
    pwszString[13] = '-';
    u = RT_H2LE_U16(pUuid->Gen.u16TimeHiAndVersion);
    pwszString[14] = g_achDigits[(u >> 12)/*& 0xf*/];
    pwszString[15] = g_achDigits[(u >>  8) & 0xf];
    pwszString[16] = g_achDigits[(u >>  4) & 0xf];
    pwszString[17] = g_achDigits[(u/*>>0*/)& 0xf];
    pwszString[18] = '-';
    pwszString[19] = g_achDigits[pUuid->Gen.u8ClockSeqHiAndReserved >> 4];
    pwszString[20] = g_achDigits[pUuid->Gen.u8ClockSeqHiAndReserved & 0xf];
    pwszString[21] = g_achDigits[pUuid->Gen.u8ClockSeqLow >> 4];
    pwszString[22] = g_achDigits[pUuid->Gen.u8ClockSeqLow & 0xf];
    pwszString[23] = '-';
    pwszString[24] = g_achDigits[pUuid->Gen.au8Node[0] >> 4];
    pwszString[25] = g_achDigits[pUuid->Gen.au8Node[0] & 0xf];
    pwszString[26] = g_achDigits[pUuid->Gen.au8Node[1] >> 4];
    pwszString[27] = g_achDigits[pUuid->Gen.au8Node[1] & 0xf];
    pwszString[28] = g_achDigits[pUuid->Gen.au8Node[2] >> 4];
    pwszString[29] = g_achDigits[pUuid->Gen.au8Node[2] & 0xf];
    pwszString[30] = g_achDigits[pUuid->Gen.au8Node[3] >> 4];
    pwszString[31] = g_achDigits[pUuid->Gen.au8Node[3] & 0xf];
    pwszString[32] = g_achDigits[pUuid->Gen.au8Node[4] >> 4];
    pwszString[33] = g_achDigits[pUuid->Gen.au8Node[4] & 0xf];
    pwszString[34] = g_achDigits[pUuid->Gen.au8Node[5] >> 4];
    pwszString[35] = g_achDigits[pUuid->Gen.au8Node[5] & 0xf];
    pwszString[36] = '\0';

    return VINF_SUCCESS;
}
RTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs)
{
    int rc = VINF_SUCCESS;

    /*
     * Parameter validation.
     */
    PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
    RTFILEAIOCTX_VALID_RETURN(pCtxInt);
    AssertReturn(cReqs > 0,  VERR_INVALID_PARAMETER);
    AssertPtrReturn(pahReqs, VERR_INVALID_POINTER);
    uint32_t i = cReqs;
    PRTFILEAIOREQINTERNAL pReqInt = NULL;

    /*
     * Validate requests and associate with the context.
     */
    while (i-- > 0)
    {
        pReqInt = pahReqs[i];
        if (RTFILEAIOREQ_IS_NOT_VALID(pReqInt))
        {
            /* Undo everything and stop submitting. */
            size_t iUndo = cReqs;
            while (iUndo-- > i)
            {
                pReqInt = pahReqs[iUndo];
                RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
                pReqInt->pCtxInt = NULL;
            }
            return VERR_INVALID_HANDLE;
        }

        pReqInt->AioContext = pCtxInt->AioContext;
        pReqInt->pCtxInt    = pCtxInt;
        RTFILEAIOREQ_SET_STATE(pReqInt, SUBMITTED);
    }

    do
    {
        /*
         * We cast pahReqs to the Linux iocb structure to avoid copying the requests
         * into a temporary array. This is possible because the iocb structure is
         * the first element in the request structure (see PRTFILEAIOCTXINTERNAL).
         */
        int cReqsSubmitted = 0;
        rc = rtFileAsyncIoLinuxSubmit(pCtxInt->AioContext, cReqs,
                                      (PLNXKAIOIOCB *)pahReqs,
                                      &cReqsSubmitted);
        if (RT_FAILURE(rc))
        {
            /*
             * We encountered an error.
             * This means that the first IoCB
             * is not correctly initialized
             * (invalid buffer alignment or bad file descriptor).
             * Revert every request into the prepared state except
             * the first one which will switch to completed.
             * Another reason could be insufficient resources.
             */
            i = cReqs;
            while (i-- > 0)
            {
                /* Already validated. */
                pReqInt = pahReqs[i];
                pReqInt->pCtxInt    = NULL;
                pReqInt->AioContext = 0;
                RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
            }

            if (rc == VERR_TRY_AGAIN)
                return VERR_FILE_AIO_INSUFFICIENT_RESSOURCES;
            else
            {
                /* The first request failed. */
                pReqInt = pahReqs[0];
                RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
                pReqInt->Rc = rc;
                pReqInt->cbTransfered = 0;
                return rc;
            }
        }

        /* Advance. */
        cReqs   -= cReqsSubmitted;
        pahReqs += cReqsSubmitted;
        ASMAtomicAddS32(&pCtxInt->cRequests, cReqsSubmitted);

    } while (cReqs);

    return rc;
}
/**
 * Make a console instance.
 *
 * This will not return until either an 'exit' command is issued or a error code
 * indicating connection loss is encountered.
 *
 * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
 * @returns The VBox status code causing the console termination.
 *
 * @param   pUVM        The user mode VM handle.
 * @param   pBack       Pointer to the backend structure. This must contain
 *                      a full set of function pointers to service the console.
 * @param   fFlags      Reserved, must be zero.
 * @remark  A forced termination of the console is easiest done by forcing the
 *          callbacks to return fatal failures.
 */
DBGDECL(int) DBGCCreate(PUVM pUVM, PDBGCBACK pBack, unsigned fFlags)
{
    /*
     * Validate input.
     */
    AssertPtrNullReturn(pUVM, VERR_INVALID_VM_HANDLE);
    PVM pVM = NULL;
    if (pUVM)
    {
        pVM = VMR3GetVM(pUVM);
        AssertPtrReturn(pVM, VERR_INVALID_VM_HANDLE);
    }

    /*
     * Allocate and initialize instance data
     */
    PDBGC pDbgc;
    int rc = dbgcCreate(&pDbgc, pBack, fFlags);
    if (RT_FAILURE(rc))
        return rc;
    if (!HMR3IsEnabled(pUVM))
        pDbgc->hDbgAs = DBGF_AS_RC_AND_GC_GLOBAL;

    /*
     * Print welcome message.
     */
    rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
                                 "Welcome to the VirtualBox Debugger!\n");

    /*
     * Attach to the specified VM.
     */
    if (RT_SUCCESS(rc) && pUVM)
    {
        rc = DBGFR3Attach(pUVM);
        if (RT_SUCCESS(rc))
        {
            pDbgc->pVM   = pVM;
            pDbgc->pUVM  = pUVM;
            pDbgc->idCpu = 0;
            rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
                                         "Current VM is %08x, CPU #%u\n" /** @todo get and print the VM name! */
                                         , pDbgc->pVM, pDbgc->idCpu);
        }
        else
            rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
    }

    /*
     * Load plugins.
     */
    if (RT_SUCCESS(rc))
    {
        if (pVM)
            DBGFR3PlugInLoadAll(pDbgc->pUVM);
        rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
        if (RT_SUCCESS(rc))
        {
            /*
             * Set debug config log callback.
             */
            RTDBGCFG    hDbgCfg = DBGFR3AsGetConfig(pUVM);
            if (   hDbgCfg != NIL_RTDBGCFG
                && RTDbgCfgRetain(hDbgCfg) != UINT32_MAX)
            {
                int rc2 = RTDbgCfgSetLogCallback(hDbgCfg, dbgcDbgCfgLogCallback, pDbgc);
                if (RT_FAILURE(rc2))
                {
                    hDbgCfg = NIL_RTDBGCFG;
                    RTDbgCfgRelease(hDbgCfg);
                }
            }
            else
                hDbgCfg = NIL_RTDBGCFG;


            /*
             * Run the debugger main loop.
             */
            rc = dbgcRun(pDbgc);


            /*
             * Remove debug config log callback.
             */
            if (hDbgCfg != NIL_RTDBGCFG)
            {
                RTDbgCfgSetLogCallback(hDbgCfg, NULL, NULL);
                RTDbgCfgRelease(hDbgCfg);
            }
        }
    }
    else
        pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nDBGCCreate error: %Rrc\n", rc);


    /*
     * Cleanup console debugger session.
     */
    dbgcDestroy(pDbgc);
    return rc == VERR_DBGC_QUIT ? VINF_SUCCESS : rc;
}
RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL cMillies,
                             PRTFILEAIOREQ pahReqs, size_t cReqs, uint32_t *pcReqs)
{
    /*
     * Validate the parameters, making sure to always set pcReqs.
     */
    AssertPtrReturn(pcReqs, VERR_INVALID_POINTER);
    *pcReqs = 0; /* always set */
    PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
    RTFILEAIOCTX_VALID_RETURN(pCtxInt);
    AssertPtrReturn(pahReqs, VERR_INVALID_POINTER);
    AssertReturn(cReqs != 0, VERR_INVALID_PARAMETER);
    AssertReturn(cReqs >= cMinReqs, VERR_OUT_OF_RANGE);

    /*
     * Can't wait if there are not requests around.
     */
    if (RT_UNLIKELY(ASMAtomicUoReadS32(&pCtxInt->cRequests) == 0))
        return VERR_FILE_AIO_NO_REQUEST;

    /*
     * Convert the timeout if specified.
     */
    struct timespec    *pTimeout = NULL;
    struct timespec     Timeout = {0,0};
    uint64_t            StartNanoTS = 0;
    if (cMillies != RT_INDEFINITE_WAIT)
    {
        Timeout.tv_sec  = cMillies / 1000;
        Timeout.tv_nsec = cMillies % 1000 * 1000000;
        pTimeout = &Timeout;
        StartNanoTS = RTTimeNanoTS();
    }

    /* Wait for at least one. */
    if (!cMinReqs)
        cMinReqs = 1;

    /* For the wakeup call. */
    Assert(pCtxInt->hThreadWait == NIL_RTTHREAD);
    ASMAtomicWriteHandle(&pCtxInt->hThreadWait, RTThreadSelf());

    /*
     * Loop until we're woken up, hit an error (incl timeout), or
     * have collected the desired number of requests.
     */
    int rc = VINF_SUCCESS;
    int cRequestsCompleted = 0;
    while (!pCtxInt->fWokenUp)
    {
        LNXKAIOIOEVENT  aPortEvents[AIO_MAXIMUM_REQUESTS_PER_CONTEXT];
        int             cRequestsToWait = RT_MIN(cReqs, AIO_MAXIMUM_REQUESTS_PER_CONTEXT);
        ASMAtomicXchgBool(&pCtxInt->fWaiting, true);
        rc = rtFileAsyncIoLinuxGetEvents(pCtxInt->AioContext, cMinReqs, cRequestsToWait, &aPortEvents[0], pTimeout);
        ASMAtomicXchgBool(&pCtxInt->fWaiting, false);
        if (RT_FAILURE(rc))
            break;
        uint32_t const cDone = rc;
        rc = VINF_SUCCESS;

        /*
         * Process received events / requests.
         */
        for (uint32_t i = 0; i < cDone; i++)
        {
            /*
             * The iocb is the first element in our request structure.
             * So we can safely cast it directly to the handle (see above)
             */
            PRTFILEAIOREQINTERNAL pReqInt = (PRTFILEAIOREQINTERNAL)aPortEvents[i].pIoCB;
            AssertPtr(pReqInt);
            Assert(pReqInt->u32Magic == RTFILEAIOREQ_MAGIC);

            /** @todo aeichner: The rc field contains the result code
             *  like you can find in errno for the normal read/write ops.
             *  But there is a second field called rc2. I don't know the
             *  purpose for it yet.
             */
            if (RT_UNLIKELY(aPortEvents[i].rc < 0))
                pReqInt->Rc = RTErrConvertFromErrno(-aPortEvents[i].rc); /* Convert to positive value. */
            else
            {
                pReqInt->Rc = VINF_SUCCESS;
                pReqInt->cbTransfered = aPortEvents[i].rc;
            }

            /* Mark the request as finished. */
            RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);

            pahReqs[cRequestsCompleted++] = (RTFILEAIOREQ)pReqInt;
        }

        /*
         * Done Yet? If not advance and try again.
         */
        if (cDone >= cMinReqs)
            break;
        cMinReqs -= cDone;
        cReqs    -= cDone;

        if (cMillies != RT_INDEFINITE_WAIT)
        {
            /* The API doesn't return ETIMEDOUT, so we have to fix that ourselves. */
            uint64_t NanoTS = RTTimeNanoTS();
            uint64_t cMilliesElapsed = (NanoTS - StartNanoTS) / 1000000;
            if (cMilliesElapsed >= cMillies)
            {
                rc = VERR_TIMEOUT;
                break;
            }

            /* The syscall supposedly updates it, but we're paranoid. :-) */
            Timeout.tv_sec  = (cMillies - (RTMSINTERVAL)cMilliesElapsed) / 1000;
            Timeout.tv_nsec = (cMillies - (RTMSINTERVAL)cMilliesElapsed) % 1000 * 1000000;
        }
    }

    /*
     * Update the context state and set the return value.
     */
    *pcReqs = cRequestsCompleted;
    ASMAtomicSubS32(&pCtxInt->cRequests, cRequestsCompleted);
    Assert(pCtxInt->hThreadWait == RTThreadSelf());
    ASMAtomicWriteHandle(&pCtxInt->hThreadWait, NIL_RTTHREAD);

    /*
     * Clear the wakeup flag and set rc.
     */
    if (    pCtxInt->fWokenUp
        &&  RT_SUCCESS(rc))
    {
        ASMAtomicXchgBool(&pCtxInt->fWokenUp, false);
        rc = VERR_INTERRUPTED;
    }

    return rc;
}
/**
 * Creates a a new instance.
 *
 * @returns VBox status code.
 * @param   ppDbgc      Where to store the pointer to the instance data.
 * @param   pBack       Pointer to the backend.
 * @param   fFlags      The flags.
 */
int dbgcCreate(PDBGC *ppDbgc, PDBGCBACK pBack, unsigned fFlags)
{
    /*
     * Validate input.
     */
    AssertPtrReturn(pBack, VERR_INVALID_POINTER);
    AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);

    /*
     * Allocate and initialize.
     */
    PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
    if (!pDbgc)
        return VERR_NO_MEMORY;

    dbgcInitCmdHlp(pDbgc);
    pDbgc->pBack            = pBack;
    pDbgc->pVM              = NULL;
    pDbgc->pUVM             = NULL;
    pDbgc->idCpu            = 0;
    pDbgc->hDbgAs           = DBGF_AS_GLOBAL;
    pDbgc->pszEmulation     = "CodeView/WinDbg";
    pDbgc->paEmulationCmds  = &g_aCmdsCodeView[0];
    pDbgc->cEmulationCmds   = g_cCmdsCodeView;
    pDbgc->paEmulationFuncs = &g_aFuncsCodeView[0];
    pDbgc->cEmulationFuncs  = g_cFuncsCodeView;
    //pDbgc->fLog             = false;
    pDbgc->fRegCtxGuest     = true;
    pDbgc->fRegTerse        = true;
    //pDbgc->cPagingHierarchyDumps = 0;
    //pDbgc->DisasmPos        = {0};
    //pDbgc->SourcePos        = {0};
    //pDbgc->DumpPos          = {0};
    pDbgc->pLastPos          = &pDbgc->DisasmPos;
    //pDbgc->cbDumpElement    = 0;
    //pDbgc->cVars            = 0;
    //pDbgc->paVars           = NULL;
    //pDbgc->pPlugInHead      = NULL;
    //pDbgc->pFirstBp         = NULL;
    //pDbgc->abSearch         = {0};
    //pDbgc->cbSearch         = 0;
    pDbgc->cbSearchUnit       = 1;
    pDbgc->cMaxSearchHits     = 1;
    //pDbgc->SearchAddr       = {0};
    //pDbgc->cbSearchRange    = 0;

    //pDbgc->uInputZero       = 0;
    //pDbgc->iRead            = 0;
    //pDbgc->iWrite           = 0;
    //pDbgc->cInputLines      = 0;
    //pDbgc->fInputOverflow   = false;
    pDbgc->fReady           = true;
    pDbgc->pszScratch       = &pDbgc->achScratch[0];
    //pDbgc->iArg             = 0;
    //pDbgc->rcOutput         = 0;
    //pDbgc->rcCmd            = 0;

    dbgcEvalInit();

    *ppDbgc = pDbgc;
    return VINF_SUCCESS;
}
VBGLR3DECL(int) VbglR3DnDProcessNextMessage(CPVBGLR3DNDHGCMEVENT pEvent)
{
    /* Validate input */
    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);

    uint32_t       uMsg       = 0;
    uint32_t       uNumParms  = 0;
    const uint32_t ccbFormats = _64K;
    const uint32_t ccbData    = _1M;
    int rc = vbglR3DnDQueryNextHostMessageType(g_clientId, &uMsg, &uNumParms, true);
    if (RT_SUCCESS(rc))
    {
        DO(("Got message %d\n", uMsg));
        switch(uMsg)
        {
            case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
            case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
            case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
            {
                pEvent->uType = uMsg;
                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
                if (!pEvent->pszFormats)
                    return VERR_NO_MEMORY;
                rc = vbglR3DnDHGProcessActionMessage(g_clientId,
                                                     uMsg,
                                                     &pEvent->uScreenId,
                                                     &pEvent->u.a.uXpos,
                                                     &pEvent->u.a.uYpos,
                                                     &pEvent->u.a.uDefAction,
                                                     &pEvent->u.a.uAllActions,
                                                     pEvent->pszFormats,
                                                     ccbFormats,
                                                     &pEvent->cbFormats);
                break;
            }
            case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
            {
                pEvent->uType = uMsg;
                rc = vbglR3DnDHGProcessLeaveMessage(g_clientId);
                break;
            }
            case DragAndDropSvc::HOST_DND_HG_SND_DATA:
            {
                pEvent->uType = uMsg;
                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
                if (!pEvent->pszFormats)
                    return VERR_NO_MEMORY;
                pEvent->u.b.pvData = RTMemAlloc(ccbData);
                if (!pEvent->u.b.pvData)
                {
                    RTMemFree(pEvent->pszFormats);
                    pEvent->pszFormats = NULL;
                    return VERR_NO_MEMORY;
                }
                rc = vbglR3DnDHGProcessSendDataMessage(g_clientId,
                                                       &pEvent->uScreenId,
                                                       pEvent->pszFormats,
                                                       ccbFormats,
                                                       &pEvent->cbFormats,
                                                       &pEvent->u.b.pvData,
                                                       ccbData,
                                                       &pEvent->u.b.cbData);
                break;
            }
#ifdef VBOX_WITH_DRAG_AND_DROP_GH
            case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
            {
                pEvent->uType = uMsg;
                rc = vbglR3DnDGHProcessRequestPendingMessage(g_clientId,
                                                             &pEvent->uScreenId);
                break;
            }
            case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
            {
                pEvent->uType = uMsg;
                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
                if (!pEvent->pszFormats)
                    return VERR_NO_MEMORY;
                rc = vbglR3DnDGHProcessDroppedMessage(g_clientId,
                                                      pEvent->pszFormats,
                                                      ccbFormats,
                                                      &pEvent->cbFormats,
                                                      &pEvent->u.a.uDefAction);
                break;
            }
#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
            case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
            {
                pEvent->uType = uMsg;
                rc = vbglR3DnDHGProcessCancelMessage(g_clientId);
                if (RT_SUCCESS(rc))
                    rc = VERR_CANCELLED;
                break;
            }
            default: AssertMsgFailedReturn(("Message %u isn't expected in this context", uMsg), VERR_INVALID_PARAMETER); break;
        }
    }
    return rc;
}
Beispiel #20
0
/**
 * Initializes a file object but does *not* open the file on the guest
 * yet. This is done in the dedidcated openFile call.
 *
 * @return  IPRT status code.
 * @param   pConsole                Pointer to console object.
 * @param   pSession                Pointer to session object.
 * @param   uFileID                 Host-based file ID (part of the context ID).
 * @param   openInfo                File opening information.
 */
int GuestFile::init(Console *pConsole, GuestSession *pSession,
                    ULONG uFileID, const GuestFileOpenInfo &openInfo)
{
    LogFlowThisFunc(("pConsole=%p, pSession=%p, uFileID=%RU32, strPath=%s\n",
                     pConsole, pSession, uFileID, openInfo.mFileName.c_str()));

    AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
    AssertPtrReturn(pSession, VERR_INVALID_POINTER);

    /* Enclose the state transition NotReady->InInit->Ready. */
    AutoInitSpan autoInitSpan(this);
    AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);

    int vrc = bindToSession(pConsole, pSession, uFileID /* Object ID */);
    if (RT_SUCCESS(vrc))
    {
        mSession = pSession;

        mData.mID = uFileID;
        mData.mInitialSize = 0;
        mData.mStatus = FileStatus_Undefined;
        mData.mOpenInfo = openInfo;

        unconst(mEventSource).createObject();
        HRESULT hr = mEventSource->init();
        if (FAILED(hr))
            vrc = VERR_COM_UNEXPECTED;
    }

    if (RT_SUCCESS(vrc))
    {
        try
        {
            GuestFileListener *pListener = new GuestFileListener();
            ComObjPtr<GuestFileListenerImpl> thisListener;
            HRESULT hr = thisListener.createObject();
            if (SUCCEEDED(hr))
                hr = thisListener->init(pListener, this);

            if (SUCCEEDED(hr))
            {
                com::SafeArray <VBoxEventType_T> eventTypes;
                eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
                eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
                eventTypes.push_back(VBoxEventType_OnGuestFileRead);
                eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
                hr = mEventSource->RegisterListener(thisListener,
                                                    ComSafeArrayAsInParam(eventTypes),
                                                    TRUE /* Active listener */);
                if (SUCCEEDED(hr))
                {
                    vrc = baseInit();
                    if (RT_SUCCESS(vrc))
                    {
                        mLocalListener = thisListener;
                    }
                }
                else
                    vrc = VERR_COM_UNEXPECTED;
            }
            else
                vrc = VERR_COM_UNEXPECTED;
        }
        catch(std::bad_alloc &)
        {
            vrc = VERR_NO_MEMORY;
        }
    }

    if (RT_SUCCESS(vrc))
    {
        /* Confirm a successful initialization when it's the case. */
        autoInitSpan.setSucceeded();
    }
    else
        autoInitSpan.setFailed();

    LogFlowFuncLeaveRC(vrc);
    return vrc;
}
QVariant& UISettingsSerializerProgress::data()
{
    AssertPtrReturn(m_pSerializer, m_data);
    return m_pSerializer->data();
}
Beispiel #22
0
int GuestFile::i_onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
{
    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);

    LogFlowThisFuncEnter();

    if (pSvcCbData->mParms < 3)
        return VERR_INVALID_PARAMETER;

    int vrc = VINF_SUCCESS;

    int idx = 1; /* Current parameter index. */
    CALLBACKDATA_FILE_NOTIFY dataCb;
    /* pSvcCb->mpaParms[0] always contains the context ID. */
    pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.uType);
    pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.rc);

    FileStatus_T fileStatus = FileStatus_Undefined;
    int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */

    LogFlowFunc(("uType=%RU32, guestRc=%Rrc\n",
                 dataCb.uType, guestRc));

    if (RT_FAILURE(guestRc))
    {
        int rc2 = i_setFileStatus(FileStatus_Error, guestRc);
        AssertRC(rc2);

        rc2 = signalWaitEventInternal(pCbCtx,
                                      guestRc, NULL /* pPayload */);
        AssertRC(rc2);

        return VINF_SUCCESS; /* Report to the guest. */
    }

    switch (dataCb.uType)
    {
        case GUEST_FILE_NOTIFYTYPE_ERROR:
        {
            int rc2 = i_setFileStatus(FileStatus_Error, guestRc);
            AssertRC(rc2);

            break;
        }

        case GUEST_FILE_NOTIFYTYPE_OPEN:
        {
            if (pSvcCbData->mParms == 4)
            {
                pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.open.uHandle);

                AssertMsg(mData.mID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID),
                          ("File ID %RU32 does not match context ID %RU32\n", mData.mID,
                           VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));

                /* Set the process status. */
                int rc2 = i_setFileStatus(FileStatus_Open, guestRc);
                AssertRC(rc2);
            }
            else
                vrc = VERR_NOT_SUPPORTED;

            break;
        }

        case GUEST_FILE_NOTIFYTYPE_CLOSE:
        {
            int rc2 = i_setFileStatus(FileStatus_Closed, guestRc);
            AssertRC(rc2);

            break;
        }

        case GUEST_FILE_NOTIFYTYPE_READ:
        {
            if (pSvcCbData->mParms == 4)
            {
                pSvcCbData->mpaParms[idx++].getPointer(&dataCb.u.read.pvData,
                                                       &dataCb.u.read.cbData);
                uint32_t cbRead = dataCb.u.read.cbData;

                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

                mData.mOffCurrent += cbRead;

                alock.release();

                com::SafeArray<BYTE> data((size_t)cbRead);
                data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead);

                fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent,
                                       cbRead, ComSafeArrayAsInParam(data));
            }
            else
                vrc = VERR_NOT_SUPPORTED;
            break;
        }

        case GUEST_FILE_NOTIFYTYPE_WRITE:
        {
            if (pSvcCbData->mParms == 4)
            {
                pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.write.cbWritten);

                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

                mData.mOffCurrent += dataCb.u.write.cbWritten;
                uint64_t uOffCurrent = mData.mOffCurrent;

                alock.release();

                fireGuestFileWriteEvent(mEventSource, mSession, this, uOffCurrent,
                                        dataCb.u.write.cbWritten);
            }
            else
                vrc = VERR_NOT_SUPPORTED;
            break;
        }

        case GUEST_FILE_NOTIFYTYPE_SEEK:
        {
            if (pSvcCbData->mParms == 4)
            {
                pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.seek.uOffActual);

                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

                mData.mOffCurrent = dataCb.u.seek.uOffActual;

                alock.release();

                fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
                                                dataCb.u.seek.uOffActual, 0 /* Processed */);
            }
            else
                vrc = VERR_NOT_SUPPORTED;
            break;
        }

        case GUEST_FILE_NOTIFYTYPE_TELL:
        {
            if (pSvcCbData->mParms == 4)
            {
                pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.tell.uOffActual);

                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

                mData.mOffCurrent = dataCb.u.tell.uOffActual;

                alock.release();

                fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
                                                dataCb.u.tell.uOffActual, 0 /* Processed */);
            }
            else
                vrc = VERR_NOT_SUPPORTED;
            break;
        }

        default:
            vrc = VERR_NOT_SUPPORTED;
            break;
    }

    if (RT_SUCCESS(vrc))
    {
        GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb));
        int rc2 = signalWaitEventInternal(pCbCtx, guestRc, &payload);
        AssertRC(rc2);
    }

    LogFlowThisFunc(("uType=%RU32, guestRc=%Rrc\n",
                     dataCb.uType, dataCb.rc));

    LogFlowFuncLeaveRC(vrc);
    return vrc;
}
/**
 * Search for content of specified type in guest clipboard buffer and put
 * it into newly allocated buffer.
 *
 * @param   pPasteboard     Guest PasteBoard reference.
 * @param   fFormat         Data formats we are looking for.
 * @param   ppvData         Where to return pointer to the received data. M
 * @param   pcbData         Where to return the size of the data.
 * @param   pcbAlloc        Where to return the size of the memory block
 *                          *ppvData pointes to. (Usually greater than *cbData
 *                           because the allocation is page aligned.)
 * @returns IPRT status code.
 */
static int vbclClipboardReadGuestData(PasteboardRef pPasteboard, CFStringRef sFormat, void **ppvData, uint32_t *pcbData,
                                      uint32_t *pcbAlloc)
{
    ItemCount cItems, iItem;
    OSStatus  rc;

    void     *pvData  = NULL;
    uint32_t  cbData  = 0;
    uint32_t  cbAlloc = 0;

    AssertPtrReturn(ppvData, VERR_INVALID_POINTER);
    AssertPtrReturn(pcbData, VERR_INVALID_POINTER);
    AssertPtrReturn(pcbAlloc, VERR_INVALID_POINTER);

    rc = PasteboardGetItemCount(pPasteboard, &cItems);
    AssertReturn(rc == noErr, VERR_INVALID_PARAMETER);
    AssertReturn(cItems > 0, VERR_INVALID_PARAMETER);

    /* Walk through all the items in PasteBoard in order to find
       that one that correcponds to requested data format. */
    for (iItem = 1; iItem <= cItems; iItem++)
    {
        PasteboardItemID iItemID;
        CFDataRef        flavorData;

        /* Now, get the item's flavors that corresponds to requested type. */
        rc = PasteboardGetItemIdentifier(pPasteboard, iItem, &iItemID);
        AssertReturn(rc == noErr, VERR_INVALID_PARAMETER);
        rc = PasteboardCopyItemFlavorData(pPasteboard, iItemID, sFormat, &flavorData);
        if (rc == noErr)
        {
            void *flavorDataPtr = (void *)CFDataGetBytePtr(flavorData);
            cbData = CFDataGetLength(flavorData);
            if (flavorDataPtr && cbData > 0)
            {
                cbAlloc = RT_ALIGN_32(cbData, PAGE_SIZE);
                pvData = RTMemPageAllocZ(cbAlloc);
                if (pvData)
                    memcpy(pvData, flavorDataPtr, cbData);
            }

            CFRelease(flavorData);

            /* Found first matching item, no more search. */
            break;
        }

    }

    /* Found match */
    if (pvData)
    {
        *ppvData  = pvData;
        *pcbData  = cbData;
        *pcbAlloc = cbAlloc;

        return VINF_SUCCESS;
    }

    return VERR_INVALID_PARAMETER;
}
Beispiel #24
0
 HRESULT init(GuestFile *pFile)
 {
     AssertPtrReturn(pFile, E_POINTER);
     mFile = pFile;
     return S_OK;
 }
/**
 * Reads a guest property.
 *
 * @returns VBox status code, fully bitched.
 *
 * @param   u32ClientId         The HGCM client ID for the guest property session.
 * @param   pszPropName         The property name.
 * @param   ppszValue           Where to return the value.  This is always set
 *                              to NULL.  Free it using RTStrFree().
 * @param   ppszFlags           Where to return the value flags. Free it
 *                              using RTStrFree().  Optional.
 * @param   puTimestamp         Where to return the timestamp.  This is only set
 *                              on success.  Optional.
 */
int VBoxServiceReadProp(uint32_t u32ClientId, const char *pszPropName,
                        char **ppszValue, char **ppszFlags, uint64_t *puTimestamp)
{
    AssertPtrReturn(pszPropName, VERR_INVALID_POINTER);
    AssertPtrReturn(ppszValue, VERR_INVALID_POINTER);

    uint32_t    cbBuf = _1K;
    void       *pvBuf = NULL;
    int         rc;

    *ppszValue = NULL;

    for (unsigned cTries = 0; cTries < 10; cTries++)
    {
        /*
         * (Re-)Allocate the buffer and try read the property.
         */
        RTMemFree(pvBuf);
        pvBuf = RTMemAlloc(cbBuf);
        if (!pvBuf)
        {
            VBoxServiceError("Guest Property: Failed to allocate %zu bytes\n", cbBuf);
            rc = VERR_NO_MEMORY;
            break;
        }
        char    *pszValue;
        char    *pszFlags;
        uint64_t uTimestamp;
        rc = VbglR3GuestPropRead(u32ClientId, pszPropName,
                                 pvBuf, cbBuf,
                                 &pszValue, &uTimestamp, &pszFlags, NULL);
        if (RT_FAILURE(rc))
        {
            if (rc == VERR_BUFFER_OVERFLOW)
            {
                /* try again with a bigger buffer. */
                cbBuf *= 2;
                continue;
            }
            if (rc == VERR_NOT_FOUND)
                VBoxServiceVerbose(2, "Guest Property: %s not found\n", pszPropName);
            else
                VBoxServiceError("Guest Property: Failed to query \"%s\": %Rrc\n", pszPropName, rc);
            break;
        }

        VBoxServiceVerbose(2, "Guest Property: Read \"%s\" = \"%s\", timestamp %RU64n\n",
                           pszPropName, pszValue, uTimestamp);
        *ppszValue = RTStrDup(pszValue);
        if (!*ppszValue)
        {
            VBoxServiceError("Guest Property: RTStrDup failed for \"%s\"\n", pszValue);
            rc = VERR_NO_MEMORY;
            break;
        }

        if (puTimestamp)
            *puTimestamp = uTimestamp;
        if (ppszFlags)
            *ppszFlags = RTStrDup(pszFlags);
        break; /* done */
    }

    RTMemFree(pvBuf);
    return rc;
}
RTDECL(int) RTCrX509Certificate_VerifySignature(PCRTCRX509CERTIFICATE pThis, PCRTASN1OBJID pAlgorithm,
                                                PCRTASN1DYNTYPE pParameters, PCRTASN1BITSTRING pPublicKey,
                                                PRTERRINFO pErrInfo)
{
    /*
     * Validate the input a little.
     */
    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
    AssertReturn(RTCrX509Certificate_IsPresent(pThis), VERR_INVALID_PARAMETER);

    AssertPtrReturn(pAlgorithm, VERR_INVALID_POINTER);
    AssertReturn(RTAsn1ObjId_IsPresent(pAlgorithm), VERR_INVALID_POINTER);

    if (pParameters)
    {
        AssertPtrReturn(pParameters, VERR_INVALID_POINTER);
        if (pParameters->enmType == RTASN1TYPE_NULL)
            pParameters = NULL;
    }

    AssertPtrReturn(pPublicKey, VERR_INVALID_POINTER);
    AssertReturn(RTAsn1BitString_IsPresent(pPublicKey), VERR_INVALID_POINTER);

    /*
     * Check if the algorithm matches.
     */
    const char *pszCipherOid = RTCrPkixGetCiperOidFromSignatureAlgorithm(&pThis->SignatureAlgorithm.Algorithm);
    if (!pszCipherOid)
        return RTErrInfoSetF(pErrInfo, VERR_CR_X509_UNKNOWN_CERT_SIGN_ALGO,
                             "Certificate signature algorithm not known: %s",
                             pThis->SignatureAlgorithm.Algorithm.szObjId);

    if (RTAsn1ObjId_CompareWithString(pAlgorithm, pszCipherOid) != 0)
        return RTErrInfoSetF(pErrInfo, VERR_CR_X509_CERT_SIGN_ALGO_MISMATCH,
                             "Certificate signature cipher algorithm mismatch: cert uses %s (%s) while key uses %s",
                             pszCipherOid, pThis->SignatureAlgorithm.Algorithm.szObjId, pAlgorithm->szObjId);

    /*
     * Wrap up the public key.
     */
    RTCRKEY hPubKey;
    int rc = RTCrKeyCreateFromPublicAlgorithmAndBits(&hPubKey, pAlgorithm, pPublicKey, pErrInfo, NULL);
    if (RT_FAILURE(rc))
        return rc;

    /*
     * Here we should recode the to-be-signed part as DER, but we'll ASSUME
     * that it's already in DER encoding and only does this if there the
     * encoded bits are missing.
     */
    if (   pThis->TbsCertificate.SeqCore.Asn1Core.uData.pu8
        && pThis->TbsCertificate.SeqCore.Asn1Core.cb > 0)
        rc = RTCrPkixPubKeyVerifySignature(&pThis->SignatureAlgorithm.Algorithm, hPubKey, pParameters, &pThis->SignatureValue,
                                           RTASN1CORE_GET_RAW_ASN1_PTR(&pThis->TbsCertificate.SeqCore.Asn1Core),
                                           RTASN1CORE_GET_RAW_ASN1_SIZE(&pThis->TbsCertificate.SeqCore.Asn1Core),
                                           pErrInfo);
    else
    {
        uint32_t cbEncoded;
        rc = RTAsn1EncodePrepare((PRTASN1CORE)&pThis->TbsCertificate.SeqCore.Asn1Core, RTASN1ENCODE_F_DER, &cbEncoded, pErrInfo);
        if (RT_SUCCESS(rc))
        {
            void *pvTbsBits = RTMemTmpAlloc(cbEncoded);
            if (pvTbsBits)
            {
                rc = RTAsn1EncodeToBuffer(&pThis->TbsCertificate.SeqCore.Asn1Core, RTASN1ENCODE_F_DER,
                                          pvTbsBits, cbEncoded, pErrInfo);
                if (RT_SUCCESS(rc))
                    rc = RTCrPkixPubKeyVerifySignature(&pThis->SignatureAlgorithm.Algorithm, hPubKey, pParameters,
                                                       &pThis->SignatureValue, pvTbsBits, cbEncoded, pErrInfo);
                else
                    AssertRC(rc);
                RTMemTmpFree(pvTbsBits);
            }
            else
                rc = VERR_NO_TMP_MEMORY;
        }
    }

    /* Free the public key. */
    uint32_t cRefs = RTCrKeyRelease(hPubKey);
    Assert(cRefs == 0); NOREF(cRefs);

    return rc;
}
Beispiel #27
0
RTDECL(int) RTZipGzipDecompressIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSIOSTREAM phVfsIosOut)
{
    AssertPtrReturn(hVfsIosIn, VERR_INVALID_HANDLE);
    AssertReturn(!(fFlags & ~RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR), VERR_INVALID_PARAMETER);
    AssertPtrReturn(phVfsIosOut, VERR_INVALID_POINTER);

    uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosIn);
    AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);

    /*
     * Create the decompression I/O stream.
     */
    RTVFSIOSTREAM    hVfsIos;
    PRTZIPGZIPSTREAM pThis;
    int rc = RTVfsNewIoStream(&g_rtZipGzipOps, sizeof(RTZIPGZIPSTREAM), RTFILE_O_READ, NIL_RTVFS, NIL_RTVFSLOCK,
                              &hVfsIos, (void **)&pThis);
    if (RT_SUCCESS(rc))
    {
        pThis->hVfsIos      = hVfsIosIn;
        pThis->offStream    = 0;
        pThis->fDecompress  = true;
        pThis->SgSeg.pvSeg  = &pThis->abBuffer[0];
        pThis->SgSeg.cbSeg  = sizeof(pThis->abBuffer);
        RTSgBufInit(&pThis->SgBuf, &pThis->SgSeg, 1);

        memset(&pThis->Zlib, 0, sizeof(pThis->Zlib));
        pThis->Zlib.opaque  = pThis;
        rc = inflateInit2(&pThis->Zlib,
                          fFlags & RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR
                          ? MAX_WBITS
                          : MAX_WBITS + 16 /* autodetect gzip header */);
        if (rc >= 0)
        {
            /*
             * Read the gzip header from the input stream to check that it's
             * a gzip stream as specified by the user.
             *
             * Note!. Since we've told zlib to check for the gzip header, we
             *        prebuffer what we read in the input buffer so it can
             *        be handed on to zlib later on.
             */
            rc = RTVfsIoStrmRead(pThis->hVfsIos, pThis->abBuffer, sizeof(RTZIPGZIPHDR), true /*fBlocking*/, NULL /*pcbRead*/);
            if (RT_SUCCESS(rc))
            {
                /* Validate the header and make a copy of it. */
                PCRTZIPGZIPHDR pHdr = (PCRTZIPGZIPHDR)pThis->abBuffer;
                if (   pHdr->bId1 == RTZIPGZIPHDR_ID1
                    && pHdr->bId2 == RTZIPGZIPHDR_ID2
                    && !(pHdr->fFlags & ~RTZIPGZIPHDR_FLG_VALID_MASK))
                {
                    if (pHdr->bCompressionMethod == RTZIPGZIPHDR_CM_DEFLATE)
                        rc = VINF_SUCCESS;
                    else
                        rc = VERR_ZIP_UNSUPPORTED_METHOD;
                }
                else if (   (fFlags & RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR)
                         && (RT_MAKE_U16(pHdr->bId2, pHdr->bId1) % 31) == 0
                         && (pHdr->bId1 & 0xf) == RTZIPGZIPHDR_CM_DEFLATE )
                {
                    pHdr = NULL;
                    rc = VINF_SUCCESS;
                }
                else
                    rc = VERR_ZIP_BAD_HEADER;
                if (RT_SUCCESS(rc))
                {
                    pThis->Zlib.avail_in = sizeof(RTZIPGZIPHDR);
                    pThis->Zlib.next_in  = &pThis->abBuffer[0];
                    if (pHdr)
                    {
                        pThis->Hdr = *pHdr;
                        /* Parse on if there are names or comments. */
                        if (pHdr->fFlags & (RTZIPGZIPHDR_FLG_NAME | RTZIPGZIPHDR_FLG_COMMENT))
                        {
                            /** @todo Can implement this when someone needs the
                             *        name or comment for something useful. */
                        }
                    }
                    if (RT_SUCCESS(rc))
                    {
                        *phVfsIosOut = hVfsIos;
                        return VINF_SUCCESS;
                    }
                }
            }
        }
        else
            rc = rtZipGzipConvertErrFromZlib(pThis, rc); /** @todo cleaning up in this situation is going to go wrong. */
        RTVfsIoStrmRelease(hVfsIos);
    }
    else
        RTVfsIoStrmRelease(hVfsIosIn);
    return rc;
}
RTDECL(int) RTCrPkcs7VerifySignedData(PCRTCRPKCS7CONTENTINFO pContentInfo, uint32_t fFlags,
                                      RTCRSTORE hAdditionalCerts, RTCRSTORE hTrustedCerts,
                                      PCRTTIMESPEC pValidationTime, PFNRTCRPKCS7VERIFYCERTCALLBACK pfnVerifyCert, void *pvUser,
                                      PRTERRINFO pErrInfo)
{
    /*
     * Check the input.
     */
    if (pfnVerifyCert)
        AssertPtrReturn(pfnVerifyCert, VERR_INVALID_POINTER);
    else
        pfnVerifyCert = RTCrPkcs7VerifyCertCallbackDefault;

    if (!RTCrPkcs7ContentInfo_IsSignedData(pContentInfo))
        return RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_NOT_SIGNED_DATA, "Not PKCS #7 SignedData.");
    PCRTCRPKCS7SIGNEDDATA pSignedData = pContentInfo->u.pSignedData;
    int rc = RTCrPkcs7SignedData_CheckSanity(pSignedData, 0, pErrInfo, "");
    if (RT_FAILURE(rc))
        return rc;

    /*
     * Hash the content info.
     */
    /* Exactly what the content is, for some stupid reason unnecessarily
       complicated.  Figure it out here as we'll need it for the OpenSSL code
       path as well. */
    void const *pvContent = pSignedData->ContentInfo.Content.Asn1Core.uData.pv;
    uint32_t    cbContent = pSignedData->ContentInfo.Content.Asn1Core.cb;
    if (pSignedData->ContentInfo.Content.pEncapsulated)
    {
        pvContent = pSignedData->ContentInfo.Content.pEncapsulated->uData.pv;
        cbContent = pSignedData->ContentInfo.Content.pEncapsulated->cb;
    }

    /* Check that there aren't too many or too few hash algorithms for our
       implementation and purposes. */
    RTCRDIGEST     ahDigests[2];
    uint32_t const cDigests = pSignedData->DigestAlgorithms.cItems;
    if (!cDigests) /** @todo we might have to support this... */
        return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_NO_DIGEST_ALGORITHMS, "No digest algorithms");

    if (cDigests > RT_ELEMENTS(ahDigests))
        return RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_TOO_MANY_DIGEST_ALGORITHMS,
                             "Too many digest algorithm: cAlgorithms=%u", cDigests);

    /* Create the message digest calculators. */
    rc = VERR_CR_PKCS7_NO_DIGEST_ALGORITHMS;
    uint32_t i;
    for (i = 0; i < cDigests; i++)
    {
        rc = RTCrDigestCreateByObjId(&ahDigests[i], &pSignedData->DigestAlgorithms.paItems[i].Algorithm);
        if (RT_FAILURE(rc))
        {
            rc = RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_DIGEST_CREATE_ERROR, "Error creating digest for '%s': %Rrc",
                               pSignedData->DigestAlgorithms.paItems[i].Algorithm.szObjId, rc);
            break;
        }
    }
    if (RT_SUCCESS(rc))
    {
        /* Hash the content. */
        for (i = 0; i < cDigests && RT_SUCCESS(rc); i++)
        {
            rc = RTCrDigestUpdate(ahDigests[i], pvContent, cbContent);
            if (RT_SUCCESS(rc))
                rc = RTCrDigestFinal(ahDigests[i], NULL, 0);
        }
        if (RT_SUCCESS(rc))
        {
            /*
             * Validate the signed infos.
             */
            uint32_t fPrimaryVccFlags = !(fFlags & RTCRPKCS7VERIFY_SD_F_USAGE_TIMESTAMPING)
                                      ? RTCRPKCS7VCC_F_SIGNED_DATA : RTCRPKCS7VCC_F_TIMESTAMP;
            rc = VERR_CR_PKCS7_NO_SIGNER_INFOS;
            for (i = 0; i < pSignedData->SignerInfos.cItems; i++)
            {
                PCRTCRPKCS7SIGNERINFO   pSignerInfo = &pSignedData->SignerInfos.paItems[i];
                RTCRDIGEST              hThisDigest = NIL_RTCRDIGEST; /* (gcc maybe incredible stupid.) */
                rc = rtCrPkcs7VerifyFindDigest(&hThisDigest, pSignedData, pSignerInfo, ahDigests, pErrInfo);
                if (RT_FAILURE(rc))
                    break;

                /*
                 * See if we can find a trusted signing time.
                 * (Note that while it would make sense splitting up this function,
                 * we need to carry a lot of arguments around, so better not.)
                 */
                bool                    fDone              = false;
                PCRTCRPKCS7SIGNERINFO   pSigningTimeSigner = NULL;
                PCRTASN1TIME            pSignedTime;
                while (   !fDone
                       && (pSignedTime = RTCrPkcs7SignerInfo_GetSigningTime(pSignerInfo, &pSigningTimeSigner)) != NULL)
                {
                    RTTIMESPEC ThisValidationTime;
                    if (RT_LIKELY(RTTimeImplode(&ThisValidationTime, &pSignedTime->Time)))
                    {
                        if (pSigningTimeSigner == pSignerInfo)
                        {
                            if (fFlags & RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY)
                                continue;
                            rc = rtCrPkcs7VerifySignerInfo(pSignerInfo, pSignedData, hThisDigest, fFlags,
                                                           hAdditionalCerts, hTrustedCerts, &ThisValidationTime,
                                                           pfnVerifyCert, fPrimaryVccFlags | RTCRPKCS7VCC_F_TIMESTAMP,
                                                           pvUser, pErrInfo);
                        }
                        else
                        {
                            rc = VINF_SUCCESS;
                            if (!(fFlags & RTCRPKCS7VERIFY_SD_F_USE_SIGNING_TIME_UNVERIFIED))
                                rc = rtCrPkcs7VerifyCounterSignerInfo(pSigningTimeSigner, pSignerInfo, pSignedData, fFlags,
                                                                      hAdditionalCerts, hTrustedCerts, &ThisValidationTime,
                                                                      pfnVerifyCert, RTCRPKCS7VCC_F_TIMESTAMP, pvUser, pErrInfo);
                            if (RT_SUCCESS(rc))
                                rc = rtCrPkcs7VerifySignerInfo(pSignerInfo, pSignedData, hThisDigest, fFlags, hAdditionalCerts,
                                                               hTrustedCerts, &ThisValidationTime,
                                                               pfnVerifyCert, fPrimaryVccFlags, pvUser, pErrInfo);
                        }
                        fDone = RT_SUCCESS(rc)
                             || (fFlags & RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT);
                    }
                    else
                    {
                        rc = RTErrInfoSet(pErrInfo, VERR_INTERNAL_ERROR_3, "RTTimeImplode failed");
                        fDone = true;
                    }
                }

                /*
                 * If not luck, check for microsoft timestamp counter signatures.
                 */
                if (!fDone && !(fFlags & RTCRPKCS7VERIFY_SD_F_IGNORE_MS_TIMESTAMP))
                {
                    PCRTCRPKCS7CONTENTINFO pSignedTimestamp = NULL;
                    pSignedTime = RTCrPkcs7SignerInfo_GetMsTimestamp(pSignerInfo, &pSignedTimestamp);
                    if (pSignedTime)
                    {
                        RTTIMESPEC ThisValidationTime;
                        if (RT_LIKELY(RTTimeImplode(&ThisValidationTime, &pSignedTime->Time)))
                        {
                            rc = VINF_SUCCESS;
                            if (!(fFlags & RTCRPKCS7VERIFY_SD_F_USE_MS_TIMESTAMP_UNVERIFIED))
                                rc = RTCrPkcs7VerifySignedData(pSignedTimestamp,
                                                               fFlags | RTCRPKCS7VERIFY_SD_F_IGNORE_MS_TIMESTAMP
                                                               | RTCRPKCS7VERIFY_SD_F_USAGE_TIMESTAMPING,
                                                               hAdditionalCerts, hTrustedCerts, &ThisValidationTime,
                                                               pfnVerifyCert, pvUser, pErrInfo);

                            if (RT_SUCCESS(rc))
                                rc = rtCrPkcs7VerifySignerInfo(pSignerInfo, pSignedData, hThisDigest, fFlags, hAdditionalCerts,
                                                               hTrustedCerts, &ThisValidationTime,
                                                               pfnVerifyCert, fPrimaryVccFlags, pvUser, pErrInfo);
                            fDone = RT_SUCCESS(rc)
                                 || (fFlags & RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_MS_TIMESTAMP_IF_PRESENT);
                        }
                        else
                        {
                            rc = RTErrInfoSet(pErrInfo, VERR_INTERNAL_ERROR_3, "RTTimeImplode failed");
                            fDone = true;
                        }

                    }
                }

                /*
                 * No valid signing time found, use the one specified instead.
                 */
                if (!fDone)
                    rc = rtCrPkcs7VerifySignerInfo(pSignerInfo, pSignedData, hThisDigest, fFlags, hAdditionalCerts, hTrustedCerts,
                                                   pValidationTime, pfnVerifyCert, fPrimaryVccFlags, pvUser, pErrInfo);
                RTCrDigestRelease(hThisDigest);
                if (RT_FAILURE(rc))
                    break;
            }
        }
        else
            rc = RTErrInfoSetF(pErrInfo, VERR_CR_PKCS7_DIGEST_CALC_ERROR,
                               "Hashing content failed unexpectedly (i=%u): %Rrc", i, rc);

        /* Clean up digests. */
        i = cDigests;
    }
    while (i-- > 0)
    {
        int rc2 = RTCrDigestRelease(ahDigests[i]);
        AssertRC(rc2);
    }


#ifdef IPRT_WITH_OPENSSL
    /*
     * Verify using OpenSSL and combine the results (should be identical).
     */
    /** @todo figure out how to verify MS timstamp signatures using OpenSSL. */
    if (fFlags & RTCRPKCS7VERIFY_SD_F_USAGE_TIMESTAMPING)
        return rc;
    int rcOssl = rtCrPkcs7VerifySignedDataUsingOpenSsl(pContentInfo, fFlags, hAdditionalCerts, hTrustedCerts,
                                                       pvContent, cbContent, RT_SUCCESS(rc) ? pErrInfo : NULL);
    if (RT_SUCCESS(rcOssl) && RT_SUCCESS(rc))
        return rc;
//    AssertMsg(RT_FAILURE_NP(rcOssl) && RT_FAILURE_NP(rc), ("%Rrc, %Rrc\n", rcOssl, rc));
    if (RT_FAILURE(rc))
        return rc;
    return rcOssl;
#else
    return rc;
#endif
}
RTDECL(int) RTPowerNotificationRegister(PFNRTPOWERNOTIFICATION pfnCallback, void *pvUser)
{
    PRTPOWERNOTIFYREG   pCur;
    PRTPOWERNOTIFYREG   pNew;
    RTSPINLOCKTMP       Tmp = RTSPINLOCKTMP_INITIALIZER;

    /*
     * Validation.
     */
    AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
    AssertReturn(g_hRTPowerNotifySpinLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
    RT_ASSERT_PREEMPTIBLE();

    RTSpinlockAcquire(g_hRTPowerNotifySpinLock, &Tmp);
    for (pCur = g_pRTPowerCallbackHead; pCur; pCur = pCur->pNext)
        if (    pCur->pvUser == pvUser
            &&  pCur->pfnCallback == pfnCallback)
            break;
    RTSpinlockRelease(g_hRTPowerNotifySpinLock, &Tmp);
    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 = (PRTPOWERNOTIFYREG)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_hRTPowerNotifySpinLock, &Tmp);

    pCur = g_pRTPowerCallbackHead;
    if (!pCur)
        g_pRTPowerCallbackHead = pNew;
    else
    {
        for (pCur = g_pRTPowerCallbackHead; ; pCur = pCur->pNext)
            if (    pCur->pvUser == pvUser
                &&  pCur->pfnCallback == pfnCallback)
                break;
            else if (!pCur->pNext)
            {
                pCur->pNext = pNew;
                pCur = NULL;
                break;
            }
    }

    ASMAtomicIncU32(&g_iRTPowerGeneration);

    RTSpinlockRelease(g_hRTPowerNotifySpinLock, &Tmp);

    /* duplicate? */
    if (pCur)
    {
        RTMemFree(pCur);
        AssertMsgFailedReturn(("pCur=%p pfnCallback=%p pvUser=%p\n", pCur, pfnCallback, pvUser), VERR_ALREADY_EXISTS);
    }

    return VINF_SUCCESS;
}
Beispiel #30
0
RTR3DECL(int) RTManifestWriteFiles(const char *pszManifestFile, const char * const *papszFiles, size_t cFiles,
                                   PFNRTPROGRESS pfnProgressCallback, void *pvUser)
{
    /* Validate input */
    AssertPtrReturn(pszManifestFile, VERR_INVALID_POINTER);
    AssertPtrReturn(papszFiles, VERR_INVALID_POINTER);
    AssertPtrNullReturn(pfnProgressCallback, VERR_INVALID_POINTER);

    RTFILE file;
    int rc = RTFileOpen(&file, pszManifestFile, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL);
    if (RT_FAILURE(rc))
        return rc;

    PRTMANIFESTTEST paFiles = 0;
    void *pvBuf = 0;
    do
    {
        paFiles = (PRTMANIFESTTEST)RTMemAllocZ(sizeof(RTMANIFESTTEST) * cFiles);
        if (!paFiles)
        {
            rc = VERR_NO_MEMORY;
            break;
        }

        RTMANIFESTCALLBACKDATA callback = { pfnProgressCallback, pvUser, cFiles, 0 };
        for (size_t i = 0; i < cFiles; ++i)
        {
            paFiles[i].pszTestFile = papszFiles[i];
            /* Calculate the SHA1 digest of every file */
            if (pfnProgressCallback)
            {
                callback.cCurrentFile = i;
                rc = RTSha1DigestFromFile(paFiles[i].pszTestFile, (char**)&paFiles[i].pszTestDigest, rtSHAProgressCallback, &callback);
            }
            else
                rc = RTSha1DigestFromFile(paFiles[i].pszTestFile, (char**)&paFiles[i].pszTestDigest, NULL, NULL);
            if (RT_FAILURE(rc))
                break;
        }

        if (RT_SUCCESS(rc))
        {
            size_t cbSize = 0;
            rc = RTManifestWriteFilesBuf(&pvBuf, &cbSize, paFiles, cFiles);
            if (RT_FAILURE(rc))
                break;

            rc = RTFileWrite(file, pvBuf, cbSize, 0);
        }
    } while (0);

    RTFileClose(file);

    /* Cleanup */
    if (pvBuf)
        RTMemFree(pvBuf);
    for (size_t i = 0; i < cFiles; ++i)
        if (paFiles[i].pszTestDigest)
            RTStrFree((char*)paFiles[i].pszTestDigest);
    RTMemFree(paFiles);

    /* Delete the manifest file on failure */
    if (RT_FAILURE(rc))
        RTFileDelete(pszManifestFile);

    return rc;
}