diff options
author | Felix Geyer <fgeyer@debian.org> | 2014-04-05 22:17:15 +0200 |
---|---|---|
committer | Felix Geyer <fgeyer@debian.org> | 2014-04-05 22:17:15 +0200 |
commit | 1700c7d32f7d9d101cbba9f1fcb8bb57ed16a727 (patch) | |
tree | 727251ad65172262944f82bb0f28601c3fb6f6b3 /src/VBox/Runtime/r3/linux/sysfs.cpp | |
parent | 1e85aed889b772c2f2daa7a6d9e8bd967aa213d8 (diff) | |
download | virtualbox-upstream.tar.gz |
Imported Upstream version 4.3.10-dfsgupstream/4.3.10-dfsgupstream
Diffstat (limited to 'src/VBox/Runtime/r3/linux/sysfs.cpp')
-rw-r--r-- | src/VBox/Runtime/r3/linux/sysfs.cpp | 164 |
1 files changed, 80 insertions, 84 deletions
diff --git a/src/VBox/Runtime/r3/linux/sysfs.cpp b/src/VBox/Runtime/r3/linux/sysfs.cpp index f5dfc6a57..15309330f 100644 --- a/src/VBox/Runtime/r3/linux/sysfs.cpp +++ b/src/VBox/Runtime/r3/linux/sysfs.cpp @@ -53,8 +53,7 @@ * Constructs the path of a sysfs file from the format parameters passed, * prepending a prefix if the path is relative. * - * @returns The number of characters returned, or -1 and errno set to ERANGE on - * failure. + * @returns The number of characters returned, or an iprt error code on failure. * * @param pszPrefix The prefix to prepend if the path is relative. Must end * in '/'. @@ -70,8 +69,8 @@ static ssize_t rtLinuxConstructPathV(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va) { size_t cchPrefix = strlen(pszPrefix); - AssertReturnStmt(pszPrefix[cchPrefix - 1] == '/', errno = ERANGE, -1); - AssertReturnStmt(cchBuf > cchPrefix + 1, errno = ERANGE, -1); + AssertReturn(pszPrefix[cchPrefix - 1] == '/', VERR_INVALID_PARAMETER); + AssertReturn(cchBuf > cchPrefix + 1, VERR_INVALID_PARAMETER); /** @todo While RTStrPrintfV prevents overflows, it doesn't make it easy to * check for truncations. RTPath should provide some formatters and @@ -80,7 +79,7 @@ static ssize_t rtLinuxConstructPathV(char *pszBuf, size_t cchBuf, size_t cch = RTStrPrintfV(pszBuf, cchBuf, pszFormat, va); if (*pszBuf != '/') { - AssertReturnStmt(cchBuf >= cch + cchPrefix + 1, errno = ERANGE, -1); + AssertReturn(cchBuf >= cch + cchPrefix + 1, VERR_BUFFER_OVERFLOW); memmove(pszBuf + cchPrefix, pszBuf, cch + 1); memcpy(pszBuf, pszPrefix, cchPrefix); cch += cchPrefix; @@ -93,8 +92,8 @@ static ssize_t rtLinuxConstructPathV(char *pszBuf, size_t cchBuf, * Constructs the path of a sysfs file from the format parameters passed, * prepending a prefix if the path is relative. * - * @returns The number of characters returned, or -1 and errno set to ERANGE on - * failure. + * @returns The number of characters returned, or an iprt error code on failure. + * @note Unused. * * @param pszPrefix The prefix to prepend if the path is relative. Must end * in '/'. @@ -131,7 +130,11 @@ static ssize_t rtLinuxConstructPath(char *pszBuf, size_t cchBuf, */ static ssize_t rtLinuxSysFsConstructPath(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va) { - return rtLinuxConstructPathV(pszBuf, cchBuf, "/sys/", pszFormat, va); + ssize_t rc = rtLinuxConstructPathV(pszBuf, cchBuf, "/sys/", pszFormat, va); + if (rc >= 0) + return rc; + errno = ERANGE; + return -1; } @@ -409,125 +412,118 @@ RTDECL(ssize_t) RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, const char } -static ssize_t rtLinuxFindDevicePathRecursive(dev_t DevNum, RTFMODE fMode, const char *pszBasePath, - char *pszBuf, size_t cchBuf) +/** Search for a device node with the number @a DevNum and the type (character + * or block) @a fMode below the path @a pszPath. @a pszPath MUST point to a + * buffer of size at least RTPATH_MAX which will be modified during the function + * execution. On successful return it will contain the path to the device node + * found. */ +/** @note This function previously used a local stack buffer of size RTPATH_MAX + * to construct the path passed to the next recursive call, which used up 4K + * of stack space per iteration and caused a stack overflow on a path with + * too many components. */ +static int rtLinuxFindDevicePathRecursive(dev_t DevNum, RTFMODE fMode, + char *pszPath) { + int rc; + PRTDIR pDir; + size_t const cchPath = strlen(pszPath); + /* * Check assumptions made by the code below. */ - size_t const cchBasePath = strlen(pszBasePath); - AssertReturnStmt(cchBasePath < RTPATH_MAX - 10U, errno = ENAMETOOLONG, -1); - - ssize_t rcRet; - PRTDIR pDir; - int rc = RTDirOpen(&pDir, pszBasePath); + AssertReturn(cchPath < RTPATH_MAX - 10U, VERR_BUFFER_OVERFLOW); + rc = RTDirOpen(&pDir, pszPath); if (RT_SUCCESS(rc)) { - char szPath[RTPATH_MAX]; /** @todo 4K per recursion - can easily be optimized away by passing it along pszBasePath - and only remember the length. */ - memcpy(szPath, pszBasePath, cchBasePath + 1); - for (;;) { RTDIRENTRYEX Entry; - rc = RTDirReadEx(pDir, &Entry, NULL, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); + rc = RTDirReadEx(pDir, &Entry, NULL, RTFSOBJATTRADD_UNIX, + RTPATH_F_ON_LINK); if (RT_FAILURE(rc)) - { - errno = rc == VERR_NO_MORE_FILES - ? ENOENT - : rc == VERR_BUFFER_OVERFLOW - ? EOVERFLOW - : EIO; - rcRet = -1; break; - } if (RTFS_IS_SYMLINK(Entry.Info.Attr.fMode)) continue; - + pszPath[cchPath] = '\0'; + rc = RTPathAppend(pszPath, RTPATH_MAX, Entry.szName); + if (RT_FAILURE(rc)) + break; /* Do the matching. */ if ( Entry.Info.Attr.u.Unix.Device == DevNum && (Entry.Info.Attr.fMode & RTFS_TYPE_MASK) == fMode) - { - rcRet = rtLinuxConstructPath(pszBuf, cchBuf, pszBasePath, "%s", Entry.szName); break; - } - /* Recurse into subdirectories. */ if (!RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode)) continue; if (Entry.szName[0] == '.') continue; - - szPath[cchBasePath] = '\0'; - rc = RTPathAppend(szPath, sizeof(szPath) - 1, Entry.szName); /* -1: for slash */ - if (RT_FAILURE(rc)) - { - errno = ENAMETOOLONG; - rcRet = -1; - break; - } - strcat(&szPath[cchBasePath], "/"); - rcRet = rtLinuxFindDevicePathRecursive(DevNum, fMode, szPath, pszBuf, cchBuf); - if (rcRet >= 0 || errno != ENOENT) + rc = rtLinuxFindDevicePathRecursive(DevNum, fMode, pszPath); + if (RT_SUCCESS(rc) || rc != VERR_NO_MORE_FILES) break; } RTDirClose(pDir); } - else - { - rcRet = -1; - errno = RTErrConvertToErrno(rc); - } - return rcRet; + return rc; } -RTDECL(ssize_t) RTLinuxFindDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf, - const char *pszSuggestion, va_list va) +RTDECL(ssize_t) RTLinuxFindDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf, + size_t cchBuf, const char *pszSuggestion, + va_list va) { - AssertReturnStmt(cchBuf >= 2, errno = EINVAL, -1); - AssertReturnStmt( fMode == RTFS_TYPE_DEV_CHAR - || fMode == RTFS_TYPE_DEV_BLOCK, - errno = EINVAL, -1); + char szFilename[RTPATH_MAX]; + int rc = VINF_TRY_AGAIN; + AssertReturn(cchBuf >= 2, VERR_INVALID_PARAMETER); + AssertReturn( fMode == RTFS_TYPE_DEV_CHAR + || fMode == RTFS_TYPE_DEV_BLOCK, + VERR_INVALID_PARAMETER); if (pszSuggestion) { /* * Construct the filename and read the link. */ - char szFilename[RTPATH_MAX]; - int rc = rtLinuxConstructPathV(szFilename, sizeof(szFilename), "/dev/", pszSuggestion, va); - if (rc == -1) - return -1; - - /* - * Check whether the caller's suggestion was right. - */ - RTFSOBJINFO Info; - rc = RTPathQueryInfo(szFilename, &Info, RTFSOBJATTRADD_UNIX); - if ( RT_SUCCESS(rc) - && Info.Attr.u.Unix.Device == DevNum - && (Info.Attr.fMode & RTFS_TYPE_MASK) == fMode) + rc = rtLinuxConstructPathV(szFilename, sizeof(szFilename), "/dev/", + pszSuggestion, va); + if (rc > 0) { - size_t cchPath = strlen(szFilename); - if (cchPath >= cchBuf) - { - errno = EOVERFLOW; - return -1; - } - memcpy(pszBuf, szFilename, cchPath + 1); - return cchPath; + /* + * Check whether the caller's suggestion was right. + */ + RTFSOBJINFO Info; + rc = RTPathQueryInfo(szFilename, &Info, RTFSOBJATTRADD_UNIX); + if ( rc == VERR_PATH_NOT_FOUND + || rc == VERR_FILE_NOT_FOUND + || ( RT_SUCCESS(rc) + && ( Info.Attr.u.Unix.Device != DevNum + || (Info.Attr.fMode & RTFS_TYPE_MASK) != fMode))) + /* The suggestion was wrong, fall back on the brute force attack. */ + rc = VINF_TRY_AGAIN; } - - /* The suggestion was wrong, fall back on the brute force attack. */ } - return rtLinuxFindDevicePathRecursive(DevNum, fMode, "/dev/", pszBuf, cchBuf); + if (rc == VINF_TRY_AGAIN) + { + RTStrCopy(szFilename, sizeof(szFilename), "/dev/"); + rc = rtLinuxFindDevicePathRecursive(DevNum, fMode, szFilename); + } + if (RT_SUCCESS(rc)) + { + size_t cchPath = strlen(szFilename); + if (cchPath >= cchBuf) + return VERR_BUFFER_OVERFLOW; + memcpy(pszBuf, szFilename, cchPath + 1); + return cchPath; + } + return rc; } -RTDECL(ssize_t) RTLinuxFindDevicePath(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf, - const char *pszSuggestion, ...) +/** @todo Do we really need to return the string length? If the caller is + * interested (the current ones aren't) they can check themselves. */ +RTDECL(ssize_t) RTLinuxFindDevicePath(dev_t DevNum, RTFMODE fMode, char *pszBuf, + size_t cchBuf, const char *pszSuggestion, + ...) { va_list va; va_start(va, pszSuggestion); |