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; }
/** * 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; }
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; }
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)); } }
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; }
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; }
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; }