RTDECL(size_t) RTPathStripTrailingSlash(char *pszPath)
{
    size_t off = strlen(pszPath);
    while (off > 1)
    {
        off--;
        switch (pszPath[off])
        {
        case '/':
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
        case '\\':
            if (    off == 2
                    &&  pszPath[1] == ':'
                    &&  RT_C_IS_ALPHA(pszPath[0]))
                return off + 1;
#endif
            pszPath[off] = '\0';
            break;

        default:
            return off + 1;
        }
    }

    return 1;
}
/**
 * Returns the length of the volume name specifier of the given path.
 * If no such specifier zero is returned.
 */
DECLHIDDEN(size_t) rtPathVolumeSpecLen(const char *pszPath)
{
#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
    if (pszPath && *pszPath)
    {
        /* UNC path. */
        /** @todo r=bird: it's UNC and we have to check that the next char isn't a
         *        slash, then skip both the server and the share name. */
        if (    (pszPath[0] == '\\' || pszPath[0] == '/')
            &&  (pszPath[1] == '\\' || pszPath[1] == '/'))
            return strcspn(pszPath + 2, "\\/") + 2;

        /* Drive letter. */
        if (    pszPath[1] == ':'
            &&  RT_C_IS_ALPHA(pszPath[0]))
            return 2;
    }
    return 0;

#else
    /* This isn't quite right when looking at the above stuff, but it works assuming that '//' does not mean UNC. */
    /// @todo (dmik) well, it's better to consider there's no volume name
    //  at all on *nix systems
    NOREF(pszPath);
    return 0;
//    return pszPath && pszPath[0] == '/';
#endif
}
static int dbgfR3LoadLinuxSystemMap(PVM pVM, FILE *pFile, RTGCUINTPTR ModuleAddress, RTGCUINTPTR AddressDelta)
{
    char szLine[4096];
    while (fgets(szLine, sizeof(szLine), pFile))
    {
        /* parse the line: <address> <type> <name> */
        const char *psz = dbgfR3Strip(szLine);
        char *pszEnd = NULL;
        uint64_t u64Address;
        int rc = RTStrToUInt64Ex(psz, &pszEnd, 16, &u64Address);
        RTGCUINTPTR Address = u64Address;
        if (    RT_SUCCESS(rc)
            &&  (*pszEnd == ' ' || *pszEnd == '\t')
            &&  Address == u64Address
            &&  u64Address != 0
            &&  u64Address != (RTGCUINTPTR)~0)
        {
            pszEnd++;
            if (    RT_C_IS_ALPHA(*pszEnd)
                &&  (pszEnd[1] == ' ' || pszEnd[1] == '\t'))
            {
                psz = dbgfR3Strip(pszEnd + 2);
                if (*psz)
                {
                    int rc2 = DBGFR3SymbolAdd(pVM, ModuleAddress, Address + AddressDelta, 0, psz);
                    if (RT_FAILURE(rc2))
                        Log2(("DBGFR3SymbolAdd(,, %RGv, 0, '%s') -> %Rrc\n", Address, psz, rc2));
                }
            }
        }
    }
    return VINF_SUCCESS;
}
Exemple #4
0
/**
 * Get's the C word starting at the current position minus one.
 *
 * @returns Pointer to the word on success and the stream position advanced to
 *          the end of it.
 *          NULL on failure, stream position normally unchanged.
 * @param   pStream             The stream to get the C word from.
 * @param   pcchWord            Where to return the word length.
 */
const char *ScmStreamCGetWordM1(PSCMSTREAM pStream, size_t *pcchWord)
{
    /* Check stream state. */
    AssertReturn(!pStream->fWriteOrRead, NULL);
    AssertReturn(RT_SUCCESS(pStream->rc), NULL);
    AssertReturn(pStream->fFullyLineated, NULL);

    /* Get the number of chars left on the line and locate the current char. */
    size_t const    iLine   = pStream->iLine;
    size_t const    cchLeft = pStream->paLines[iLine].cch + pStream->paLines[iLine].off - (pStream->off - 1);
    const char     *psz     = &pStream->pch[pStream->off - 1];

    /* Is it a leading C character. */
    if (!RT_C_IS_ALPHA(*psz) && *psz != '_')
        return NULL;

    /* Find the end of the word. */
    char    ch;
    size_t  off = 1;
    while (     off < cchLeft
           &&  (   (ch = psz[off]) == '_'
                || RT_C_IS_ALNUM(ch)))
        off++;

    pStream->off += off - 1;
    *pcchWord = off;
    return psz;
}
/**
 * Figures the length of the root part of the path.
 *
 * @returns length of the root specifier.
 * @retval  0 if none.
 *
 * @param   pszPath         The path to investigate.
 *
 * @remarks Unnecessary root slashes will not be counted. The caller will have
 *          to deal with it where it matters.  (Unlike rtPathRootSpecLen which
 *          counts them.)
 */
static size_t rtPathRootSpecLen2(const char *pszPath)
{
    /* fend of wildlife. */
    if (!pszPath)
        return 0;

    /* Root slash? */
    if (RTPATH_IS_SLASH(pszPath[0]))
    {
#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
        /* UNC? */
        if (    RTPATH_IS_SLASH(pszPath[1])
            &&  pszPath[2] != '\0'
            &&  !RTPATH_IS_SLASH(pszPath[2]))
        {
            /* Find the end of the server name. */
            const char *pszEnd = pszPath + 2;
            pszEnd += 2;
            while (   *pszEnd != '\0'
                   && !RTPATH_IS_SLASH(*pszEnd))
                pszEnd++;
            if (RTPATH_IS_SLASH(*pszEnd))
            {
                pszEnd++;
                while (RTPATH_IS_SLASH(*pszEnd))
                    pszEnd++;

                /* Find the end of the share name */
                while (   *pszEnd != '\0'
                       && !RTPATH_IS_SLASH(*pszEnd))
                    pszEnd++;
                if (RTPATH_IS_SLASH(*pszEnd))
                    pszEnd++;
                return pszPath - pszEnd;
            }
        }
#endif
        return 1;
    }

#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
    /* Drive specifier? */
    if (   pszPath[0] != '\0'
        && pszPath[1] == ':'
        && RT_C_IS_ALPHA(pszPath[0]))
    {
        if (RTPATH_IS_SLASH(pszPath[2]))
            return 3;
        return 2;
    }
#endif
    return 0;
}
Exemple #6
0
void CollectorLinux::addRaidDisks(const char *pcszDevice, DiskList& listDisks)
{
    FILE *f = fopen("/proc/mdstat", "r");
    if (f)
    {
        char szBuf[128];
        while (fgets(szBuf, sizeof(szBuf), f))
        {
            char *pszBufName = szBuf;

            char *pszBufData = strchr(pszBufName, ' ');
            if (!pszBufData)
            {
                LogRel(("CollectorLinux::addRaidDisks() failed to parse disk stats: %s\n", szBuf));
                continue;
            }
            *pszBufData++ = '\0';
            if (!strcmp(pcszDevice, pszBufName))
            {
                while (*pszBufData == ':')         ++pszBufData; /* Skip delimiter */
                while (*pszBufData == ' ')         ++pszBufData; /* Skip spaces */
                while (RT_C_IS_ALNUM(*pszBufData)) ++pszBufData; /* Skip status */
                while (*pszBufData == ' ')         ++pszBufData; /* Skip spaces */
                while (RT_C_IS_ALNUM(*pszBufData)) ++pszBufData; /* Skip type */

                while (*pszBufData != '\0')
                {
                    while (*pszBufData == ' ') ++pszBufData; /* Skip spaces */
                    char *pszDisk = pszBufData;
                    while (RT_C_IS_ALPHA(*pszBufData))
                        ++pszBufData;
                    if (*pszBufData)
                    {
                        *pszBufData++ = '\0';
                        listDisks.push_back(RTCString(pszDisk));
                        while (*pszBufData != '\0' && *pszBufData != ' ')
                            ++pszBufData;
                    }
                    else
                        listDisks.push_back(RTCString(pszDisk));
                }
                break;
            }
        }
        fclose(f);
    }
}
/**
 * Figures out the length of the root (or drive) specifier in @a pszPath.
 *
 * For UNC names, we consider the root specifier to include both the server and
 * share names.
 *
 * @returns The length including all slashes.  0 if relative path.
 *
 * @param   pszPath         The path to examine.
 */
DECLHIDDEN(size_t) rtPathRootSpecLen(const char *pszPath)
{
    /*
     * If it's an absolute path, threat the root or volume specification as
     * component 0.  UNC is making this extra fun on OS/2 and Windows as usual.
     */
    size_t off = 0;
    if (RTPATH_IS_SLASH(pszPath[0]))
    {
#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
        if (   RTPATH_IS_SLASH(pszPath[1])
            && !RTPATH_IS_SLASH(pszPath[2])
            && pszPath[2])
        {
            /* UNC server name */
            off = 2;
            while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
                off++;
            while (RTPATH_IS_SLASH(pszPath[off]))
                off++;

            /* UNC share */
            while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
                off++;
        }
        else
#endif
        {
            off = 1;
        }
        while (RTPATH_IS_SLASH(pszPath[off]))
            off++;
    }
#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
    else if (RT_C_IS_ALPHA(pszPath[0]) && pszPath[1] == ':')
    {
        off = 2;
        while (RTPATH_IS_SLASH(pszPath[off]))
            off++;
    }
#endif
    Assert(!RTPATH_IS_SLASH(pszPath[off]));

    return off;
}
Exemple #8
0
static void test3(void)
{
    RTTestISub("> 127");
    for (int ch = 128; ch < 2000000; ch++)
    {
        RTTESTI_CHECK(!RT_C_IS_CNTRL(ch));
        RTTESTI_CHECK(!RT_C_IS_SPACE(ch));
        RTTESTI_CHECK(!RT_C_IS_BLANK(ch));
        RTTESTI_CHECK(!RT_C_IS_PRINT(ch));
        RTTESTI_CHECK(!RT_C_IS_PUNCT(ch));
        RTTESTI_CHECK(!RT_C_IS_GRAPH(ch));
        RTTESTI_CHECK(!RT_C_IS_DIGIT(ch));
        RTTESTI_CHECK(!RT_C_IS_XDIGIT(ch));
        RTTESTI_CHECK(!RT_C_IS_ODIGIT(ch));
        RTTESTI_CHECK(!RT_C_IS_ALPHA(ch));
        RTTESTI_CHECK(!RT_C_IS_UPPER(ch));
        RTTESTI_CHECK(!RT_C_IS_LOWER(ch));
    }
}
Exemple #9
0
static void test2(void)
{
    RTTestISub("< 0");
    for (int ch = -1; ch > -2000000; ch--)
    {
        RTTESTI_CHECK(!RT_C_IS_CNTRL(ch));
        RTTESTI_CHECK(!RT_C_IS_SPACE(ch));
        RTTESTI_CHECK(!RT_C_IS_BLANK(ch));
        RTTESTI_CHECK(!RT_C_IS_PRINT(ch));
        RTTESTI_CHECK(!RT_C_IS_PUNCT(ch));
        RTTESTI_CHECK(!RT_C_IS_GRAPH(ch));
        RTTESTI_CHECK(!RT_C_IS_DIGIT(ch));
        RTTESTI_CHECK(!RT_C_IS_XDIGIT(ch));
        RTTESTI_CHECK(!RT_C_IS_ODIGIT(ch));
        RTTESTI_CHECK(!RT_C_IS_ALPHA(ch));
        RTTESTI_CHECK(!RT_C_IS_UPPER(ch));
        RTTESTI_CHECK(!RT_C_IS_LOWER(ch));
    }
}
RTDECL(int) RTPathAppendEx(char *pszPath, size_t cbPathDst, const char *pszAppend, size_t cchAppendMax)
{
    char *pszPathEnd = RTStrEnd(pszPath, cbPathDst);
    AssertReturn(pszPathEnd, VERR_INVALID_PARAMETER);

    /*
     * Special cases.
     */
    if (!pszAppend)
        return VINF_SUCCESS;
    size_t cchAppend = RTStrNLen(pszAppend, cchAppendMax);
    if (!cchAppend)
        return VINF_SUCCESS;
    if (pszPathEnd == pszPath)
    {
        if (cchAppend >= cbPathDst)
            return VERR_BUFFER_OVERFLOW;
        memcpy(pszPath, pszAppend, cchAppend);
        pszPath[cchAppend] = '\0';
        return VINF_SUCCESS;
    }

    /*
     * Balance slashes and check for buffer overflow.
     */
    if (!RTPATH_IS_SLASH(pszPathEnd[-1]))
    {
        if (!RTPATH_IS_SLASH(pszAppend[0]))
        {
#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
            if (    (size_t)(pszPathEnd - pszPath) == 2
                &&  pszPath[1] == ':'
                &&  RT_C_IS_ALPHA(pszPath[0]))
            {
                if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cbPathDst)
                    return VERR_BUFFER_OVERFLOW;
            }
            else
#endif
            {
                if ((size_t)(pszPathEnd - pszPath) + 1 + cchAppend >= cbPathDst)
                    return VERR_BUFFER_OVERFLOW;
                *pszPathEnd++ = RTPATH_SLASH;
            }
        }
        else
        {
            /* One slash is sufficient at this point. */
            while (cchAppend > 1 && RTPATH_IS_SLASH(pszAppend[1]))
                pszAppend++, cchAppend--;

            if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cbPathDst)
                return VERR_BUFFER_OVERFLOW;
        }
    }
    else
    {
        /* No slashes needed in the appended bit. */
        while (cchAppend && RTPATH_IS_SLASH(*pszAppend))
            pszAppend++, cchAppend--;

        /* In the leading path we can skip unnecessary trailing slashes, but
           be sure to leave one. */
        size_t const cchRoot = rtPathRootSpecLen2(pszPath);
        while (     (size_t)(pszPathEnd - pszPath) > RT_MAX(1, cchRoot)
               &&   RTPATH_IS_SLASH(pszPathEnd[-2]))
            pszPathEnd--;

        if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cbPathDst)
            return VERR_BUFFER_OVERFLOW;
    }

    /*
     * What remains now is the just the copying.
     */
    memcpy(pszPathEnd, pszAppend, cchAppend);
    pszPathEnd[cchAppend] = '\0';
    return VINF_SUCCESS;
}
RTDECL(RTTHREADNATIVESTATE) RTThreadGetNativeState(RTTHREAD hThread)
{
    RTTHREADNATIVESTATE enmRet  = RTTHREADNATIVESTATE_INVALID;
    PRTTHREADINT        pThread = rtThreadGet(hThread);
    if (pThread)
    {
        enmRet = RTTHREADNATIVESTATE_UNKNOWN;

        char szName[512];
        RTStrPrintf(szName, sizeof(szName), "/proc/self/task/%u/stat", pThread->tid);
        int fd = open(szName, O_RDONLY, 0);
        if (fd >= 0)
        {
            ssize_t cch = read(fd, szName, sizeof(szName) - 1);
            close(fd);
            if (cch > 0)
            {
                szName[cch] = '\0';

                /* skip the pid, the (comm name) and stop at the status char. */
                const char *psz = szName;
                while (   *psz
                       && (   *psz != ')'
                           || !RT_C_IS_SPACE(psz[1])
                           || !RT_C_IS_ALPHA(psz[2])
                           || !RT_C_IS_SPACE(psz[3])
                          )
                      )
                    psz++;
                if (*psz == ')')
                {
                    switch (psz[2])
                    {
                        case 'R':   /* running */
                            enmRet = RTTHREADNATIVESTATE_RUNNING;
                            break;

                        case 'S':   /* sleeping */
                        case 'D':   /* disk sleeping */
                            enmRet = RTTHREADNATIVESTATE_BLOCKED;
                            break;

                        case 'T':   /* stopped or tracking stop */
                            enmRet = RTTHREADNATIVESTATE_SUSPENDED;
                            break;

                        case 'Z':   /* zombie */
                        case 'X':   /* dead */
                            enmRet = RTTHREADNATIVESTATE_TERMINATED;
                            break;

                        default:
                            AssertMsgFailed(("state=%c\n", psz[2]));
                            enmRet = RTTHREADNATIVESTATE_UNKNOWN;
                            break;
                    }
                }
                else
                    AssertMsgFailed(("stat='%s'\n", szName));
            }
        }
        rtThreadRelease(pThread);
    }
    return enmRet;
}
Exemple #12
0
RTDECL(int) RTUriFilePathEx(const char *pszUri, uint32_t fPathStyle, char **ppszPath, size_t cbPath, size_t *pcchPath)
{
    /*
     * Validate and adjust input.
     */
    if (pcchPath)
    {
        AssertPtrReturn(pcchPath, VERR_INVALID_POINTER);
        *pcchPath = ~(size_t)0;
    }
    AssertPtrReturn(ppszPath, VERR_INVALID_POINTER);
    AssertReturn(!(fPathStyle & ~RTPATH_STR_F_STYLE_MASK) && fPathStyle != RTPATH_STR_F_STYLE_RESERVED, VERR_INVALID_FLAGS);
    if (fPathStyle == RTPATH_STR_F_STYLE_HOST)
        fPathStyle = RTPATH_STYLE;
    AssertPtrReturn(pszUri, VERR_INVALID_POINTER);

    /*
     * Check that this is a file URI.
     */
    if (RTStrNICmp(pszUri, RT_STR_TUPLE("file:")) == 0)
    { /* likely */ }
    else
        return VERR_URI_NOT_FILE_SCHEME;

    /*
     * We may have a number of variations here, mostly thanks to
     * various windows software.  First the canonical variations:
     *     - file:///C:/Windows/System32/kernel32.dll
     *     - file:///C|/Windows/System32/kernel32.dll
     *     - file:///C:%5CWindows%5CSystem32%5Ckernel32.dll
     *     - file://localhost/C:%5CWindows%5CSystem32%5Ckernel32.dll
     *     - file://cifsserver.dev/systemshare%5CWindows%5CSystem32%5Ckernel32.dll
     *     - file://cifsserver.dev:139/systemshare%5CWindows%5CSystem32%5Ckernel32.dll  (not quite sure here, but whatever)
     *
     * Legacy variant without any slashes after the schema:
     *     - file:C:/Windows/System32/kernel32.dll
     *     - file:C|/Windows/System32%5Ckernel32.dll
     *     - file:~/.bashrc
     *            \--path-/
     *
     * Legacy variant with exactly one slashes after the schema:
     *     - file:/C:/Windows/System32%5Ckernel32.dll
     *     - file:/C|/Windows/System32/kernel32.dll
     *     - file:/usr/bin/env
     *            \---path---/
     *
     * Legacy variant with two slashes after the schema and an unescaped DOS path:
     *     - file://C:/Windows/System32\kernel32.dll (**)
     *     - file://C|/Windows/System32\kernel32.dll
     *                \---path---------------------/
     *              -- authority, with ':' as non-working port separator
     *
     * Legacy variant with exactly four slashes after the schema and an unescaped DOS path.
     *     - file:////C:/Windows\System32\user32.dll
     *
     * Legacy variant with four or more slashes after the schema and an unescaped UNC path:
     *     - file:////cifsserver.dev/systemshare/System32%\kernel32.dll
     *     - file://///cifsserver.dev/systemshare/System32\kernel32.dll
     *              \---path--------------------------------------------/
     *
     * The the two unescaped variants shouldn't be handed to rtUriParse, which
     * is good as we cannot actually handle the one marked by (**).  So, handle
     * those two special when parsing.
     */
    RTURIPARSED Parsed;
    int         rc;
    size_t      cSlashes = 0;
    while (pszUri[5 + cSlashes] == '/')
        cSlashes++;
    if (   (cSlashes == 2 || cSlashes == 4)
        && RT_C_IS_ALPHA(pszUri[5 + cSlashes])
        && (pszUri[5 + cSlashes + 1] == ':' || pszUri[5 + cSlashes + 1] == '|'))
    {
        RT_ZERO(Parsed); /* RTURIPARSED_F_CONTAINS_ESCAPED_CHARS is now clear. */
        Parsed.offPath = 5 + cSlashes;
        Parsed.cchPath = strlen(&pszUri[Parsed.offPath]);
        rc = RTStrValidateEncoding(&pszUri[Parsed.offPath]);
    }
    else if (cSlashes >= 4)
    {
        RT_ZERO(Parsed);
        Parsed.fFlags  = cSlashes > 4 ? RTURIPARSED_F_CONTAINS_ESCAPED_CHARS : 0;
        Parsed.offPath = 5 + cSlashes - 2;
        Parsed.cchPath = strlen(&pszUri[Parsed.offPath]);
        rc = RTStrValidateEncoding(&pszUri[Parsed.offPath]);
    }
    else
        rc = rtUriParse(pszUri, &Parsed);
    if (RT_SUCCESS(rc))
    {
        /*
         * Ignore localhost as hostname (it's implicit).
         */
        static char const s_szLocalhost[] = "localhost";
        if (    Parsed.cchAuthorityHost == sizeof(s_szLocalhost) - 1U
            &&  RTStrNICmp(&pszUri[Parsed.offAuthorityHost], RT_STR_TUPLE(s_szLocalhost)) == 0)
        {
            Parsed.cchAuthorityHost = 0;
            Parsed.cchAuthority     = 0;
        }

        /*
         * Ignore leading path slash/separator if we detect a DOS drive letter
         * and we don't have a host name.
         */
        if (   Parsed.cchPath >= 3
            && Parsed.cchAuthorityHost    == 0
            && pszUri[Parsed.offPath]     == '/'           /* Leading path slash/separator. */
            && (   pszUri[Parsed.offPath + 2] == ':'       /* Colon after drive letter. */
                || pszUri[Parsed.offPath + 2] == '|')      /* Colon alternative. */
            && RT_C_IS_ALPHA(pszUri[Parsed.offPath + 1]) ) /* Drive letter. */
        {
            Parsed.offPath++;
            Parsed.cchPath--;
        }

        /*
         * Calculate the size of the encoded result.
         *
         * Since we're happily returning "C:/Windows/System32/kernel.dll"
         * style paths when the caller requested UNIX style paths, we will
         * return straight UNC paths too ("//cifsserver/share/dir/file").
         */
        size_t cchDecodedHost = 0;
        size_t cbResult;
        if (Parsed.fFlags & RTURIPARSED_F_CONTAINS_ESCAPED_CHARS)
        {
            cchDecodedHost = rtUriCalcDecodedLength(&pszUri[Parsed.offAuthorityHost], Parsed.cchAuthorityHost);
            cbResult = cchDecodedHost + rtUriCalcDecodedLength(&pszUri[Parsed.offPath], Parsed.cchPath) + 1;
        }
        else
        {
            cchDecodedHost = 0;
            cbResult = Parsed.cchAuthorityHost + Parsed.cchPath + 1;
        }
        if (pcchPath)
            *pcchPath = cbResult - 1;
        if (cbResult > 1)
        {
            /*
             * Prepare the necessary buffer space for the result.
             */
            char  *pszDst;
            char  *pszFreeMe = NULL;
            if (!cbPath || *ppszPath == NULL)
            {
                cbPath = RT_MAX(cbPath, cbResult);
                *ppszPath = pszFreeMe = pszDst = RTStrAlloc(cbPath);
                AssertReturn(pszDst, VERR_NO_STR_MEMORY);
            }
            else if (cbResult <= cbPath)
                pszDst = *ppszPath;
            else
                return VERR_BUFFER_OVERFLOW;

            /*
             * Compose the result.
             */
            if (Parsed.fFlags & RTURIPARSED_F_CONTAINS_ESCAPED_CHARS)
            {
                rc = rtUriDecodeIntoBuffer(&pszUri[Parsed.offAuthorityHost],Parsed.cchAuthorityHost,
                                           pszDst, cchDecodedHost + 1);
                Assert(RT_SUCCESS(rc) && strlen(pszDst) == cchDecodedHost);
                if (RT_SUCCESS(rc))
                    rc = rtUriDecodeIntoBuffer(&pszUri[Parsed.offPath], Parsed.cchPath,
                                               &pszDst[cchDecodedHost], cbResult - cchDecodedHost);
                Assert(RT_SUCCESS(rc) && strlen(pszDst) == cbResult - 1);
            }
            else
            {
                memcpy(pszDst, &pszUri[Parsed.offAuthorityHost], Parsed.cchAuthorityHost);
                memcpy(&pszDst[Parsed.cchAuthorityHost], &pszUri[Parsed.offPath], Parsed.cchPath);
                pszDst[cbResult - 1] = '\0';
            }
            if (RT_SUCCESS(rc))
            {
                /*
                 * Convert colon DOS driver letter colon alternative.
                 * We do this regardless of the desired path style.
                 */
                if (   RT_C_IS_ALPHA(pszDst[0])
                    && pszDst[1] == '|')
                    pszDst[1] = ':';

                /*
                 * Fix slashes.
                 */
                if (fPathStyle == RTPATH_STR_F_STYLE_DOS)
                    RTPathChangeToDosSlashes(pszDst, true);
                else if (fPathStyle == RTPATH_STR_F_STYLE_UNIX)
                    RTPathChangeToUnixSlashes(pszDst, true); /** @todo not quite sure how this actually makes sense... */
                else
                    AssertFailed();
                return rc;
            }

            /* bail out */
            RTStrFree(pszFreeMe);
        }
        else
            rc = VERR_PATH_ZERO_LENGTH;
    }
    return rc;
}
Exemple #13
0
static int rtUriParse(const char *pszUri, PRTURIPARSED pParsed)
{
    /*
     * Validate the input and clear the output.
     */
    AssertPtrReturn(pParsed, VERR_INVALID_POINTER);
    RT_ZERO(*pParsed);
    pParsed->uAuthorityPort = UINT32_MAX;

    AssertPtrReturn(pszUri, VERR_INVALID_POINTER);

    size_t const cchUri = strlen(pszUri);
    if (RT_LIKELY(cchUri >= 3)) { /* likely */ }
    else return cchUri ? VERR_URI_TOO_SHORT : VERR_URI_EMPTY;

    /*
     * Validating escaped text sequences is much simpler if we know that
     * that the base URI string is valid.  Also, we don't necessarily trust
     * the developer calling us to remember to do this.
     */
    int rc = RTStrValidateEncoding(pszUri);
    AssertRCReturn(rc, rc);

    /*
     * RFC-3986, section 3.1:
     *      scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
     *
     * The scheme ends with a ':', which we also skip here.
     */
    size_t off = 0;
    char ch = pszUri[off++];
    if (RT_LIKELY(RT_C_IS_ALPHA(ch))) { /* likely */ }
    else return VERR_URI_INVALID_SCHEME;
    for (;;)
    {
        ch = pszUri[off];
        if (ch == ':')
            break;
        if (RT_LIKELY(RT_C_IS_ALNUM(ch) || ch == '.' || ch == '-' || ch == '+')) { /* likely */ }
        else return VERR_URI_INVALID_SCHEME;
        off++;
    }
    pParsed->cchScheme = off;

    /* Require the scheme length to be at least two chars so we won't confuse
       it with a path starting with a DOS drive letter specification. */
    if (RT_LIKELY(off >= 2)) { /* likely */ }
    else return VERR_URI_INVALID_SCHEME;

    off++;                              /* (skip colon) */

    /*
     * Find the end of the path, we'll need this several times.
     * Also, while we're potentially scanning the whole thing, check for '%'.
     */
    size_t const offHash         = RTStrOffCharOrTerm(&pszUri[off], '#') + off;
    size_t const offQuestionMark = RTStrOffCharOrTerm(&pszUri[off], '?') + off;

    if (memchr(pszUri, '%', cchUri) != NULL)
        pParsed->fFlags |= RTURIPARSED_F_CONTAINS_ESCAPED_CHARS;

    /*
     * RFC-3986, section 3.2:
     *      The authority component is preceeded by a double slash ("//")...
     */
    if (   pszUri[off] == '/'
        && pszUri[off + 1] == '/')
    {
        off += 2;
        pParsed->offAuthority = pParsed->offAuthorityUsername = pParsed->offAuthorityPassword = pParsed->offAuthorityHost = off;
        pParsed->fFlags |= RTURIPARSED_F_HAVE_AUTHORITY;

        /*
         * RFC-3986, section 3.2:
         *      ...and is terminated by the next slash ("/"), question mark ("?"),
         *       or number sign ("#") character, or by the end of the URI.
         */
        const char *pszAuthority = &pszUri[off];
        size_t      cchAuthority = RTStrOffCharOrTerm(pszAuthority, '/');
        cchAuthority = RT_MIN(cchAuthority, offHash - off);
        cchAuthority = RT_MIN(cchAuthority, offQuestionMark - off);
        pParsed->cchAuthority     = cchAuthority;

        /* The Authority can be empty, like for: file:///usr/bin/grep  */
        if (cchAuthority > 0)
        {
            pParsed->cchAuthorityHost = cchAuthority;

            /*
             * If there is a userinfo part, it is ended by a '@'.
             */
            const char *pszAt = (const char *)memchr(pszAuthority, '@', cchAuthority);
            if (pszAt)
            {
                size_t cchTmp = pszAt - pszAuthority;
                pParsed->offAuthorityHost += cchTmp + 1;
                pParsed->cchAuthorityHost -= cchTmp + 1;

                /* If there is a password part, it's separated from the username with a colon. */
                const char *pszColon = (const char *)memchr(pszAuthority, ':', cchTmp);
                if (pszColon)
                {
                    pParsed->cchAuthorityUsername = pszColon - pszAuthority;
                    pParsed->offAuthorityPassword = &pszColon[1] - pszUri;
                    pParsed->cchAuthorityPassword = pszAt - &pszColon[1];
                }
                else
                {
                    pParsed->cchAuthorityUsername = cchTmp;
                    pParsed->offAuthorityPassword = off + cchTmp;
                }
            }

            /*
             * If there is a port part, its after the last colon in the host part.
             */
            const char *pszColon = (const char *)memrchr(&pszUri[pParsed->offAuthorityHost], ':', pParsed->cchAuthorityHost);
            if (pszColon)
            {
                size_t cchTmp = &pszUri[pParsed->offAuthorityHost + pParsed->cchAuthorityHost] - &pszColon[1];
                pParsed->cchAuthorityHost -= cchTmp + 1;

                pParsed->uAuthorityPort = 0;
                while (cchTmp-- > 0)
                {
                    ch = *++pszColon;
                    if (   RT_C_IS_DIGIT(ch)
                        && pParsed->uAuthorityPort < UINT32_MAX / UINT32_C(10))
                    {
                        pParsed->uAuthorityPort *= 10;
                        pParsed->uAuthorityPort += ch - '0';
                    }
                    else
                        return VERR_URI_INVALID_PORT_NUMBER;
                }
            }
        }

        /* Skip past the authority. */
        off += cchAuthority;
    }
    else
        pParsed->offAuthority = pParsed->offAuthorityUsername = pParsed->offAuthorityPassword = pParsed->offAuthorityHost = off;

    /*
     * RFC-3986, section 3.3: Path
     *      The path is terminated by the first question mark ("?")
     *      or number sign ("#") character, or by the end of the URI.
     */
    pParsed->offPath = off;
    pParsed->cchPath = RT_MIN(offHash, offQuestionMark) - off;
    off += pParsed->cchPath;

    /*
     * RFC-3986, section 3.4: Query
     *      The query component is indicated by the first question mark ("?")
     *      character and terminated by a number sign ("#") character or by the
     *      end of the URI.
     */
    if (   off == offQuestionMark
        && off < cchUri)
    {
        Assert(pszUri[offQuestionMark] == '?');
        pParsed->offQuery = ++off;
        pParsed->cchQuery = offHash - off;
        off = offHash;
    }
    else
    {
        Assert(!pszUri[offQuestionMark]);
        pParsed->offQuery = off;
    }

    /*
     * RFC-3986, section 3.5: Fragment
     *      A fragment identifier component is indicated by the presence of a
     *      number sign ("#") character and terminated by the end of the URI.
     */
    if (   off == offHash
        && off < cchUri)
    {
        pParsed->offFragment = ++off;
        pParsed->cchFragment = cchUri - off;
    }
    else
    {
        Assert(!pszUri[offHash]);
        pParsed->offFragment = off;
    }

    /*
     * If there are any escape sequences, validate them.
     *
     * This is reasonably simple as we already know that the string is valid UTF-8
     * before they get decoded.  Thus we only have to validate the escaped sequences.
     */
    if (pParsed->fFlags & RTURIPARSED_F_CONTAINS_ESCAPED_CHARS)
    {
        const char *pchSrc  = (const char *)memchr(pszUri, '%', cchUri);
        AssertReturn(pchSrc, VERR_INTERNAL_ERROR);
        do
        {
            char        szUtf8Seq[8];
            unsigned    cchUtf8Seq = 0;
            unsigned    cchNeeded  = 0;
            size_t      cchLeft    = &pszUri[cchUri] - pchSrc;
            do
            {
                if (cchLeft >= 3)
                {
                    char chHigh = pchSrc[1];
                    char chLow  = pchSrc[2];
                    if (   RT_C_IS_XDIGIT(chHigh)
                        && RT_C_IS_XDIGIT(chLow))
                    {
                        uint8_t b = RT_C_IS_DIGIT(chHigh) ? chHigh - '0' : (chHigh & ~0x20) - 'A' + 10;
                        b <<= 4;
                        b |= RT_C_IS_DIGIT(chLow) ? chLow - '0' : (chLow & ~0x20) - 'A' + 10;

                        if (!(b & 0x80))
                        {
                            /* We don't want the string to be terminated prematurely. */
                            if (RT_LIKELY(b != 0)) { /* likely */ }
                            else return VERR_URI_ESCAPED_ZERO;

                            /* Check that we're not expecting more UTF-8 bytes. */
                            if (RT_LIKELY(cchNeeded == 0)) { /* likely */ }
                            else return VERR_URI_MISSING_UTF8_CONTINUATION_BYTE;
                        }
                        /* Are we waiting UTF-8 bytes? */
                        else if (cchNeeded > 0)
                        {
                            if (RT_LIKELY(!(b & 0x40))) { /* likely */ }
                            else return VERR_URI_INVALID_ESCAPED_UTF8_CONTINUATION_BYTE;

                            szUtf8Seq[cchUtf8Seq++] = (char)b;
                            if (--cchNeeded == 0)
                            {
                                szUtf8Seq[cchUtf8Seq] = '\0';
                                rc = RTStrValidateEncoding(szUtf8Seq);
                                if (RT_FAILURE(rc))
                                    return VERR_URI_ESCAPED_CHARS_NOT_VALID_UTF8;
                                cchUtf8Seq = 0;
                            }
                        }
                        /* Start a new UTF-8 sequence. */
                        else
                        {
                            if ((b & 0xf8) == 0xf0)
                                cchNeeded = 3;
                            else if ((b & 0xf0) == 0xe0)
                                cchNeeded = 2;
                            else if ((b & 0xe0) == 0xc0)
                                cchNeeded = 1;
                            else
                                return VERR_URI_INVALID_ESCAPED_UTF8_LEAD_BYTE;
                            szUtf8Seq[0] = (char)b;
                            cchUtf8Seq = 1;
                        }
                        pchSrc  += 3;
                        cchLeft -= 3;
                    }
                    else
                        return VERR_URI_INVALID_ESCAPE_SEQ;
                }
                else
                    return VERR_URI_INVALID_ESCAPE_SEQ;
            } while (cchLeft > 0 && pchSrc[0] == '%');

            /* Check that we're not expecting more UTF-8 bytes. */
            if (RT_LIKELY(cchNeeded == 0)) { /* likely */ }
            else return VERR_URI_MISSING_UTF8_CONTINUATION_BYTE;

            /* next */
            pchSrc = (const char *)memchr(pchSrc, '%', cchLeft);
        } while (pchSrc);
    }

    pParsed->u32Magic = RTURIPARSED_MAGIC;
    return VINF_SUCCESS;
}
/**
 * Probe the type of a symbol information file.
 *
 * @returns The file type.
 * @param   pFile   File handle.
 */
SYMFILETYPE dbgfR3ModuleProbe(FILE *pFile)
{
    char szHead[4096];
    size_t cchHead = fread(szHead, 1, sizeof(szHead) - 1, pFile);
    if (cchHead > 0)
    {
        szHead[cchHead] = '\0';
        if (strstr(szHead, "Preferred load address is"))
            return SYMFILETYPE_MS_MAP;

        if (    strstr(szHead, "Archive member included because of")
            ||  strstr(szHead, "Memory Configuration")
            ||  strstr(szHead, "Linker script and memory map"))
            return SYMFILETYPE_LD_MAP;

        if (   RT_C_IS_XDIGIT(szHead[0])
            && RT_C_IS_XDIGIT(szHead[1])
            && RT_C_IS_XDIGIT(szHead[2])
            && RT_C_IS_XDIGIT(szHead[3])
            && RT_C_IS_XDIGIT(szHead[4])
            && RT_C_IS_XDIGIT(szHead[5])
            && RT_C_IS_XDIGIT(szHead[6])
            && RT_C_IS_XDIGIT(szHead[7])
            && szHead[8] == ' '
            && RT_C_IS_ALPHA(szHead[9])
            && szHead[10] == ' '
            && (RT_C_IS_ALPHA(szHead[11]) || szHead[11] == '_' || szHead[11] == '$')
            )
            return SYMFILETYPE_LINUX_SYSTEM_MAP;

        if (   RT_C_IS_XDIGIT(szHead[0])
            && RT_C_IS_XDIGIT(szHead[1])
            && RT_C_IS_XDIGIT(szHead[2])
            && RT_C_IS_XDIGIT(szHead[3])
            && RT_C_IS_XDIGIT(szHead[4])
            && RT_C_IS_XDIGIT(szHead[5])
            && RT_C_IS_XDIGIT(szHead[6])
            && RT_C_IS_XDIGIT(szHead[7])
            && RT_C_IS_XDIGIT(szHead[8])
            && RT_C_IS_XDIGIT(szHead[9])
            && RT_C_IS_XDIGIT(szHead[10])
            && RT_C_IS_XDIGIT(szHead[11])
            && RT_C_IS_XDIGIT(szHead[12])
            && RT_C_IS_XDIGIT(szHead[13])
            && RT_C_IS_XDIGIT(szHead[14])
            && RT_C_IS_XDIGIT(szHead[15])
            && szHead[16] == ' '
            && RT_C_IS_ALPHA(szHead[17])
            && szHead[18] == ' '
            && (RT_C_IS_ALPHA(szHead[19]) || szHead[19] == '_' || szHead[19] == '$')
            )
            return SYMFILETYPE_LINUX_SYSTEM_MAP;

        if (strstr(szHead, "Microsoft C/C++ MSF") == szHead)
            return SYMFILETYPE_PDB;

        if (strstr(szHead, "ELF") == szHead + 1)
            return SYMFILETYPE_ELF;

        if (   strstr(szHead, "MZ") == szHead
            || strstr(szHead, "PE") == szHead
            || strstr(szHead, "LE") == szHead
            || strstr(szHead, "LX") == szHead
            || strstr(szHead, "NE") == szHead)
            return SYMFILETYPE_MZ;


        if (strstr(szHead, "file format"))
            return SYMFILETYPE_OBJDUMP;
    }

    return SYMFILETYPE_UNKNOWN;
}