VirtualBox

vbox的更動 50705 路徑 trunk/src/VBox/Runtime/r3


忽略:
時間撮記:
2014-3-5 下午01:29:51 (11 年 以前)
作者:
vboxsync
訊息:

Runtime/r3/linux: rewrite device node walking code to use less stack.

檔案:
修改 1 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/VBox/Runtime/r3/linux/sysfs.cpp

    r48935 r50705  
    5454 * prepending a prefix if the path is relative.
    5555 *
    56  * @returns The number of characters returned, or -1 and errno set to ERANGE on
    57  *          failure.
     56 * @returns The number of characters returned, or an iprt error code on failure.
    5857 *
    5958 * @param   pszPrefix  The prefix to prepend if the path is relative.  Must end
     
    7170{
    7271    size_t cchPrefix = strlen(pszPrefix);
    73     AssertReturnStmt(pszPrefix[cchPrefix - 1] == '/', errno = ERANGE, -1);
    74     AssertReturnStmt(cchBuf > cchPrefix + 1, errno = ERANGE, -1);
     72    AssertReturn(pszPrefix[cchPrefix - 1] == '/', VERR_INVALID_PARAMETER);
     73    AssertReturn(cchBuf > cchPrefix + 1, VERR_INVALID_PARAMETER);
    7574
    7675    /** @todo While RTStrPrintfV prevents overflows, it doesn't make it easy to
     
    8180    if (*pszBuf != '/')
    8281    {
    83         AssertReturnStmt(cchBuf >= cch + cchPrefix + 1, errno = ERANGE, -1);
     82        AssertReturn(cchBuf >= cch + cchPrefix + 1, VERR_BUFFER_OVERFLOW);
    8483        memmove(pszBuf + cchPrefix, pszBuf, cch + 1);
    8584        memcpy(pszBuf, pszPrefix, cchPrefix);
     
    9493 * prepending a prefix if the path is relative.
    9594 *
    96  * @returns The number of characters returned, or -1 and errno set to ERANGE on
    97  *        failure.
     95 * @returns The number of characters returned, or an iprt error code on failure.
     96 * @note  Unused.
    9897 *
    9998 * @param   pszPrefix  The prefix to prepend if the path is relative.  Must end
     
    132131static ssize_t rtLinuxSysFsConstructPath(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va)
    133132{
    134     return rtLinuxConstructPathV(pszBuf, cchBuf, "/sys/", pszFormat, va);
     133    ssize_t rc = rtLinuxConstructPathV(pszBuf, cchBuf, "/sys/", pszFormat, va);
     134    if (rc >= 0)
     135        return rc;
     136    errno = ERANGE;
     137    return -1;
    135138}
    136139
     
    410413
    411414
    412 static ssize_t rtLinuxFindDevicePathRecursive(dev_t DevNum, RTFMODE fMode, const char *pszBasePath,
    413                                               char *pszBuf, size_t cchBuf)
    414 {
     415/** Search for a device node with the number @a DevNum and the type (character
     416 * or block) @a fMode below the path @a pszPath.  @a pszPath MUST point to a
     417 * buffer of size at least RTPATH_MAX which will be modified during the function
     418 * execution.  On successful return it will contain the path to the device node
     419 * found. */
     420/** @note This function previously used a local stack buffer of size RTPATH_MAX
     421 *    to construct the path passed to the next recursive call, which used up 4K
     422 *    of stack space per iteration and caused a stack overflow on a path with
     423 *    too many components. */
     424static int rtLinuxFindDevicePathRecursive(dev_t DevNum, RTFMODE fMode,
     425                                          char *pszPath)
     426{
     427    int rc;
     428    PRTDIR  pDir;
     429    size_t const cchPath = strlen(pszPath);
     430
    415431    /*
    416432     * Check assumptions made by the code below.
    417433     */
    418     size_t const cchBasePath = strlen(pszBasePath);
    419     AssertReturnStmt(cchBasePath < RTPATH_MAX - 10U, errno = ENAMETOOLONG, -1);
    420 
    421     ssize_t rcRet;
    422     PRTDIR  pDir;
    423     int rc = RTDirOpen(&pDir, pszBasePath);
     434    AssertReturn(cchPath < RTPATH_MAX - 10U, VERR_BUFFER_OVERFLOW);
     435    rc = RTDirOpen(&pDir, pszPath);
    424436    if (RT_SUCCESS(rc))
    425437    {
    426         char szPath[RTPATH_MAX]; /** @todo 4K per recursion - can easily be optimized away by passing it along pszBasePath
    427                                            and only remember the length. */
    428         memcpy(szPath, pszBasePath, cchBasePath + 1);
    429 
    430438        for (;;)
    431439        {
    432440            RTDIRENTRYEX Entry;
    433             rc = RTDirReadEx(pDir, &Entry, NULL, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
     441            rc = RTDirReadEx(pDir, &Entry, NULL, RTFSOBJATTRADD_UNIX,
     442                             RTPATH_F_ON_LINK);
    434443            if (RT_FAILURE(rc))
    435             {
    436                 errno = rc == VERR_NO_MORE_FILES
    437                       ? ENOENT
    438                       : rc == VERR_BUFFER_OVERFLOW
    439                       ? EOVERFLOW
    440                       : EIO;
    441                 rcRet = -1;
    442444                break;
    443             }
    444445            if (RTFS_IS_SYMLINK(Entry.Info.Attr.fMode))
    445446                continue;
    446 
     447            pszPath[cchPath] = '\0';
     448            rc = RTPathAppend(pszPath, RTPATH_MAX, Entry.szName);
     449            if (RT_FAILURE(rc))
     450                break;
    447451            /* Do the matching. */
    448452            if (   Entry.Info.Attr.u.Unix.Device == DevNum
    449453                && (Entry.Info.Attr.fMode & RTFS_TYPE_MASK) == fMode)
    450             {
    451                 rcRet = rtLinuxConstructPath(pszBuf, cchBuf, pszBasePath, "%s", Entry.szName);
    452454                break;
    453             }
    454 
    455455            /* Recurse into subdirectories. */
    456456            if (!RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode))
     
    458458            if (Entry.szName[0] == '.')
    459459                continue;
    460 
    461             szPath[cchBasePath] = '\0';
    462             rc = RTPathAppend(szPath, sizeof(szPath) - 1, Entry.szName); /* -1: for slash */
    463             if (RT_FAILURE(rc))
    464             {
    465                 errno = ENAMETOOLONG;
    466                 rcRet = -1;
    467                 break;
    468             }
    469             strcat(&szPath[cchBasePath], "/");
    470             rcRet = rtLinuxFindDevicePathRecursive(DevNum, fMode, szPath, pszBuf, cchBuf);
    471             if (rcRet >= 0 || errno != ENOENT)
     460            rc = rtLinuxFindDevicePathRecursive(DevNum, fMode, pszPath);
     461            if (RT_SUCCESS(rc) || rc != VERR_NO_MORE_FILES)
    472462                break;
    473463        }
    474464        RTDirClose(pDir);
    475465    }
    476     else
    477     {
    478         rcRet = -1;
    479         errno = RTErrConvertToErrno(rc);
    480     }
    481     return rcRet;
    482 }
    483 
    484 
    485 RTDECL(ssize_t) RTLinuxFindDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf,
    486                                        const char *pszSuggestion, va_list va)
    487 {
    488     AssertReturnStmt(cchBuf >= 2, errno = EINVAL, -1);
    489     AssertReturnStmt(   fMode == RTFS_TYPE_DEV_CHAR
    490                      || fMode == RTFS_TYPE_DEV_BLOCK,
    491                      errno = EINVAL, -1);
    492 
     466    return rc;
     467}
     468
     469
     470RTDECL(ssize_t) RTLinuxFindDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf,
     471                                       size_t cchBuf, const char *pszSuggestion,
     472                                       va_list va)
     473{
     474    char szFilename[RTPATH_MAX];
     475    int rc = VINF_TRY_AGAIN;
     476
     477    AssertReturn(cchBuf >= 2, VERR_INVALID_PARAMETER);
     478    AssertReturn(   fMode == RTFS_TYPE_DEV_CHAR
     479                 || fMode == RTFS_TYPE_DEV_BLOCK,
     480                 VERR_INVALID_PARAMETER);
    493481    if (pszSuggestion)
    494482    {
     
    496484         * Construct the filename and read the link.
    497485         */
    498         char szFilename[RTPATH_MAX];
    499         int rc = rtLinuxConstructPathV(szFilename, sizeof(szFilename), "/dev/", pszSuggestion, va);
    500         if (rc == -1)
    501             return -1;
    502 
    503         /*
    504          * Check whether the caller's suggestion was right.
    505          */
    506         RTFSOBJINFO Info;
    507         rc = RTPathQueryInfo(szFilename, &Info, RTFSOBJATTRADD_UNIX);
    508         if (   RT_SUCCESS(rc)
    509             && Info.Attr.u.Unix.Device == DevNum
    510             && (Info.Attr.fMode & RTFS_TYPE_MASK) == fMode)
     486        rc = rtLinuxConstructPathV(szFilename, sizeof(szFilename), "/dev/",
     487                                   pszSuggestion, va);
     488        if (rc > 0)
    511489        {
    512             size_t cchPath = strlen(szFilename);
    513             if (cchPath >= cchBuf)
    514             {
    515                 errno = EOVERFLOW;
    516                 return -1;
    517             }
    518             memcpy(pszBuf, szFilename, cchPath + 1);
    519             return cchPath;
     490            /*
     491             * Check whether the caller's suggestion was right.
     492             */
     493            RTFSOBJINFO Info;
     494            rc = RTPathQueryInfo(szFilename, &Info, RTFSOBJATTRADD_UNIX);
     495            if (   rc == VERR_PATH_NOT_FOUND
     496                || rc == VERR_FILE_NOT_FOUND
     497                || (   RT_SUCCESS(rc)
     498                    && (   Info.Attr.u.Unix.Device != DevNum
     499                        || (Info.Attr.fMode & RTFS_TYPE_MASK) != fMode)))
     500            /* The suggestion was wrong, fall back on the brute force attack. */
     501                rc = VINF_TRY_AGAIN;
    520502        }
    521 
    522         /* The suggestion was wrong, fall back on the brute force attack. */
    523     }
    524 
    525     return rtLinuxFindDevicePathRecursive(DevNum, fMode, "/dev/", pszBuf, cchBuf);
    526 }
    527 
    528 
    529 RTDECL(ssize_t) RTLinuxFindDevicePath(dev_t DevNum, RTFMODE fMode, char *pszBuf, size_t cchBuf,
    530                                       const char *pszSuggestion, ...)
     503    }
     504
     505    if (rc == VINF_TRY_AGAIN)
     506    {
     507        RTStrCopy(szFilename, sizeof(szFilename), "/dev/");
     508        rc = rtLinuxFindDevicePathRecursive(DevNum, fMode, szFilename);
     509    }
     510    if (RT_SUCCESS(rc))
     511    {
     512        size_t cchPath = strlen(szFilename);
     513        if (cchPath >= cchBuf)
     514            return VERR_BUFFER_OVERFLOW;
     515        memcpy(pszBuf, szFilename, cchPath + 1);
     516        return cchPath;
     517    }
     518    return rc;
     519}
     520
     521
     522/** @todo Do we really need to return the string length?  If the caller is
     523 * interested (the current ones aren't) they can check themselves. */
     524RTDECL(ssize_t) RTLinuxFindDevicePath(dev_t DevNum, RTFMODE fMode, char *pszBuf,
     525                                      size_t cchBuf, const char *pszSuggestion,
     526                                      ...)
    531527{
    532528    va_list va;
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette