VirtualBox

Ignore:
Timestamp:
Jul 30, 2016 12:02:01 AM (8 years ago)
Author:
vboxsync
Message:

RTDirCreateUniqueNumbered: Changed the implementation to count from zero and only do 20 sequential tries before switching to random numbers. Also, don't bother retrying more than 10000 times. Corrected the cchDigits parameter (nobody counts in signed int!).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/generic/RTDirCreateUniqueNumbered-generic.cpp

    r62477 r62723  
    3535#include <iprt/err.h>
    3636#include <iprt/path.h>
     37#include <iprt/rand.h>
    3738#include <iprt/string.h>
    3839
    3940
    40 RTDECL(int) RTDirCreateUniqueNumbered(char *pszPath, size_t cbSize, RTFMODE fMode, signed int cchDigits, char chSep)
     41RTDECL(int) RTDirCreateUniqueNumbered(char *pszPath, size_t cbSize, RTFMODE fMode, size_t cchDigits, char chSep)
    4142{
    4243    /*
     
    4647    AssertReturn(cbSize, VERR_BUFFER_OVERFLOW);
    4748    AssertReturn(cchDigits > 0, VERR_INVALID_PARAMETER);
     49    AssertReturn(cchDigits < 64, VERR_INVALID_PARAMETER);
    4850
    49     /* Check that there is sufficient space. */
     51    /* Check that there is sufficient space.  */
    5052    char *pszEnd = RTStrEnd(pszPath, cbSize);
    5153    AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW);
    52     AssertReturn(cbSize - 1 - (pszEnd - pszPath) >= (size_t)cchDigits + (chSep ? 1 : 0), VERR_BUFFER_OVERFLOW);
    5354    size_t cbLeft = cbSize - (pszEnd - pszPath);
     55    AssertReturn(cbLeft > (chSep ? 1U : 0U) + cchDigits, VERR_BUFFER_OVERFLOW);
    5456
    55     /* First try is to create the path without any numbers. */
     57    /*
     58     * First try the pretty name without any numbers appended.
     59     */
    5660    int rc = RTDirCreate(pszPath, fMode, 0);
    57     if (   RT_SUCCESS(rc)
    58         || rc != VERR_ALREADY_EXISTS)
     61    if (RT_SUCCESS(rc))
    5962        return rc;
     63    if (rc == VERR_ALREADY_EXISTS)
     64    {
     65        /*
     66         * Already exist, apply template specification.
     67         */
    6068
    61     /* If the separator value isn't zero, add it. */
    62     if (chSep != '\0')
    63     {
    64         cbLeft--;
    65         *pszEnd++ = chSep;
    66         *pszEnd   = '\0';
     69        /* Max 10000 tries (like RTDirCreateTemp), but stop earlier if we haven't got enough digits to work with.  */
     70        uint32_t cMaxTries;
     71        switch (cchDigits)
     72        {
     73            case 1:  cMaxTries =    30; break;
     74            case 2:  cMaxTries =   300; break;
     75            case 3:  cMaxTries =  2000; break;
     76            default: cMaxTries = 10000; break;
     77        }
     78
     79        static uint64_t const s_aEndSeqs[] =
     80        {
     81            UINT64_C(0),
     82            UINT64_C(9),
     83            UINT64_C(99),
     84            UINT64_C(999),
     85            UINT64_C(9999),
     86            UINT64_C(99999),
     87            UINT64_C(999999),
     88            UINT64_C(9999999),
     89            UINT64_C(99999999),
     90            UINT64_C(999999999),
     91            UINT64_C(9999999999),
     92            UINT64_C(99999999999),
     93            UINT64_C(999999999999),
     94            UINT64_C(9999999999999),
     95            UINT64_C(99999999999999),
     96            UINT64_C(999999999999999),
     97            UINT64_C(9999999999999999),
     98            UINT64_C(99999999999999999),
     99            UINT64_C(999999999999999999),
     100            UINT64_C(9999999999999999999),
     101        };
     102        uint64_t const uEndSeq = cchDigits < RT_ELEMENTS(s_aEndSeqs) ? s_aEndSeqs[cchDigits] : UINT64_MAX;
     103
     104        /* Add separator if requested. */
     105        if (chSep != '\0')
     106        {
     107            *pszEnd++ = chSep;
     108            *pszEnd   = '\0';
     109            cbLeft--;
     110        }
     111
     112        Assert(cbLeft > cchDigits);
     113        uint64_t iSeq = UINT64_MAX;
     114        for (uint32_t iTry = 0; iTry <= cMaxTries; iTry++)
     115        {
     116            /* Try sequentially first for a little bit, then switch to random numbers. */
     117            if (iTry > 20)
     118                iSeq = RTRandU64Ex(0, uEndSeq);
     119            else
     120            {
     121                iSeq++;
     122                if (iSeq < UINT64_MAX)
     123                    iSeq %= uEndSeq + 1;
     124            }
     125            ssize_t cchRet = RTStrFormatU64(pszEnd, cbLeft, iSeq, 10 /*uiBase*/,
     126                                            (int)cchDigits /*cchWidth*/, 0 /*cchPrecision*/, RTSTR_F_WIDTH | RTSTR_F_ZEROPAD);
     127            Assert((size_t)cchRet == cchDigits); NOREF(cchRet);
     128
     129            rc = RTDirCreate(pszPath, fMode, 0);
     130            if (RT_SUCCESS(rc))
     131                return rc;
     132            if (rc != VERR_ALREADY_EXISTS)
     133                break;
     134        }
    67135    }
    68136
    69     /* How many tries? Stay within somewhat sane limits. */
    70     uint32_t cMaxTries;
    71     if (cchDigits >= 8)
    72         cMaxTries = 100 * _1M;
    73     else
    74     {
    75         cMaxTries = 10;
    76         for (int a = 0; a < cchDigits - 1; ++a)
    77             cMaxTries *= 10;
    78     }
    79 
    80     /* Try cMaxTries - 1 times to create a directory with appended numbers. */
    81     uint32_t i = 1;
    82     while (i < cMaxTries)
    83     {
    84         /* Format the number with leading zero's. */
    85         ssize_t rc2 = RTStrFormatU32(pszEnd, cbLeft, i, 10, cchDigits, 0, RTSTR_F_WIDTH | RTSTR_F_ZEROPAD);
    86         if (RT_FAILURE((int) rc2))
    87         {
    88             *pszPath = '\0';
    89             return (int)rc2;
    90         }
    91         rc = RTDirCreate(pszPath, fMode, 0);
    92         if (RT_SUCCESS(rc))
    93             return rc;
    94         ++i;
    95     }
    96 
    97     /* We've given up. */
     137    /* We've given up or failed. */
    98138    *pszPath = '\0';
    99     return VERR_ALREADY_EXISTS;
     139    return rc;
    100140}
    101141RT_EXPORT_SYMBOL(RTDirCreateUniqueNumbered);
Note: See TracChangeset for help on using the changeset viewer.

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