Changeset 62723 in vbox for trunk/src/VBox/Runtime/generic/RTDirCreateUniqueNumbered-generic.cpp
- Timestamp:
- Jul 30, 2016 12:02:01 AM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/generic/RTDirCreateUniqueNumbered-generic.cpp
r62477 r62723 35 35 #include <iprt/err.h> 36 36 #include <iprt/path.h> 37 #include <iprt/rand.h> 37 38 #include <iprt/string.h> 38 39 39 40 40 RTDECL(int) RTDirCreateUniqueNumbered(char *pszPath, size_t cbSize, RTFMODE fMode, si gned int cchDigits, char chSep)41 RTDECL(int) RTDirCreateUniqueNumbered(char *pszPath, size_t cbSize, RTFMODE fMode, size_t cchDigits, char chSep) 41 42 { 42 43 /* … … 46 47 AssertReturn(cbSize, VERR_BUFFER_OVERFLOW); 47 48 AssertReturn(cchDigits > 0, VERR_INVALID_PARAMETER); 49 AssertReturn(cchDigits < 64, VERR_INVALID_PARAMETER); 48 50 49 /* Check that there is sufficient space. */51 /* Check that there is sufficient space. */ 50 52 char *pszEnd = RTStrEnd(pszPath, cbSize); 51 53 AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW); 52 AssertReturn(cbSize - 1 - (pszEnd - pszPath) >= (size_t)cchDigits + (chSep ? 1 : 0), VERR_BUFFER_OVERFLOW);53 54 size_t cbLeft = cbSize - (pszEnd - pszPath); 55 AssertReturn(cbLeft > (chSep ? 1U : 0U) + cchDigits, VERR_BUFFER_OVERFLOW); 54 56 55 /* First try is to create the path without any numbers. */ 57 /* 58 * First try the pretty name without any numbers appended. 59 */ 56 60 int rc = RTDirCreate(pszPath, fMode, 0); 57 if ( RT_SUCCESS(rc) 58 || rc != VERR_ALREADY_EXISTS) 61 if (RT_SUCCESS(rc)) 59 62 return rc; 63 if (rc == VERR_ALREADY_EXISTS) 64 { 65 /* 66 * Already exist, apply template specification. 67 */ 60 68 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 } 67 135 } 68 136 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. */ 98 138 *pszPath = '\0'; 99 return VERR_ALREADY_EXISTS;139 return rc; 100 140 } 101 141 RT_EXPORT_SYMBOL(RTDirCreateUniqueNumbered);
Note:
See TracChangeset
for help on using the changeset viewer.