Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

815 lines
22 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. mmfile.cxx
  5. Abstract:
  6. Generic shared memory allocator.
  7. Author:
  8. Adriaan Canter (adriaanc) 01-Aug-1998
  9. --*/
  10. #include "include.hxx"
  11. //--------------------------------------------------------------------
  12. // CMMFile::CMMFile()
  13. //--------------------------------------------------------------------
  14. CMMFile::CMMFile(DWORD cbHeap, DWORD cbEntry)
  15. : _cbHeap(cbHeap), _cbEntry(cbEntry)
  16. {
  17. // BUGBUG - assert this.
  18. // Heap size must be multiple of entry size
  19. // and entry size must be multiple of 2.
  20. if ((_cbHeap % _cbEntry) || _cbEntry % 2)
  21. {
  22. DIGEST_ASSERT(FALSE);
  23. _dwStatus = ERROR_INVALID_PARAMETER;
  24. goto exit;
  25. }
  26. // Max entries and total bytes in bitmap.
  27. _nMaxEntries = _cbHeap / _cbEntry;
  28. _cbBitMap = _nMaxEntries / NUM_BITS_IN_BYTE;
  29. // Total DWORDs in bitmap and total
  30. // bytes in shared memory.
  31. _nBitMapDwords = _cbBitMap / sizeof(DWORD);
  32. _cbTotal = sizeof(MEMMAP_HEADER) + _cbBitMap + _cbHeap;
  33. _pHeader = NULL;
  34. _pBitMap = NULL;
  35. _pHeap = NULL;
  36. // BUGBUG - _hFile -> INVALID_HANDLE_VALUE
  37. _hFile = NULL;
  38. _dwSig = SIG_CMMF;
  39. _dwStatus = ERROR_SUCCESS;
  40. exit:
  41. return;
  42. }
  43. //--------------------------------------------------------------------
  44. // CMMFile::~CMMFile
  45. //--------------------------------------------------------------------
  46. CMMFile::~CMMFile()
  47. {
  48. // BUGBUG - protected
  49. DeInit();
  50. }
  51. //--------------------------------------------------------------------
  52. // Init
  53. //--------------------------------------------------------------------
  54. DWORD CMMFile::Init()
  55. {
  56. BOOL fFirstProc = FALSE;
  57. LPVOID pv;
  58. HANDLE hHandle = (HANDLE) -1;
  59. CHAR szMapName[MAX_PATH];
  60. DWORD cbMapName = MAX_PATH;
  61. // IE5# 89288
  62. // Get map name based on user
  63. if ((_dwStatus = MakeUserObjectName(szMapName,
  64. &cbMapName, MAKE_MAP_NAME)) != ERROR_SUCCESS)
  65. return _dwStatus;
  66. // BUGBUG - security attributes and -1->INVALID_HANDLE_VALUE
  67. // Create the file mapping handle.
  68. _hFile = CreateFileMapping(
  69. hHandle, // 0xffffffff file handle -> backed by paging file.
  70. NULL, // Security attributes.
  71. PAGE_READWRITE // Generic read+write.
  72. | SEC_RESERVE, // Reserve only, don't commit.
  73. 0, // dwMaximumSizeHigh
  74. _cbTotal, // dwMaximumSizeLow
  75. szMapName // Map name.
  76. );
  77. // BUGBUG -> COMMENT HERE
  78. _dwStatus = GetLastError();
  79. // Check for success (can already exist) or failure.
  80. if (_dwStatus == ERROR_SUCCESS)
  81. fFirstProc = TRUE;
  82. else if (_dwStatus != ERROR_ALREADY_EXISTS)
  83. {
  84. DIGEST_ASSERT(FALSE);
  85. goto exit;
  86. }
  87. // bugbug - file_map_write logic.
  88. // Create file mapping view.
  89. pv = MapViewOfFileEx(
  90. _hFile, // File mapping handle.
  91. FILE_MAP_WRITE, // Read and write access.
  92. 0, // High 32 bit offset
  93. 0, // Low 32 bit offset
  94. 0, // Map entire file.
  95. NULL // System chooses base addr.
  96. );
  97. if(!pv)
  98. {
  99. _dwStatus = GetLastError();
  100. DIGEST_ASSERT(FALSE);
  101. goto exit;
  102. }
  103. // Calculate pointers to bitmap and heap.
  104. _pHeader = (LPMEMMAP_HEADER) pv;
  105. _pBitMap = (LPDWORD) ((LPBYTE) pv + sizeof(MEMMAP_HEADER));
  106. _pHeap = ((LPBYTE) _pBitMap + _cbBitMap);
  107. // Initialize MM file if first process.
  108. if (fFirstProc)
  109. {
  110. // Commit header + bitmap.
  111. if (!VirtualAlloc(_pHeader, sizeof(MEMMAP_HEADER) + _cbBitMap,
  112. MEM_COMMIT, PAGE_READWRITE))
  113. {
  114. _dwStatus = GetLastError();
  115. goto exit;
  116. }
  117. //BUGBUG - zero out first.
  118. // Set signature.
  119. memcpy(_pHeader->szSig, MMF_SIG_SZ, MMF_SIG_SIZE);
  120. // Zero out the rest of the header + bitmap.
  121. memset((LPBYTE) _pHeader + MMF_SIG_SIZE, 0,
  122. sizeof(MEMMAP_HEADER) - MMF_SIG_SIZE + _cbBitMap);
  123. }
  124. _dwStatus = ERROR_SUCCESS;
  125. exit:
  126. return _dwStatus;
  127. }
  128. //--------------------------------------------------------------------
  129. // DeInit
  130. //--------------------------------------------------------------------
  131. DWORD CMMFile::DeInit()
  132. {
  133. // BUGBUG - should always close _hFile
  134. if (!UnmapViewOfFile((LPVOID) _pHeader))
  135. {
  136. DIGEST_ASSERT(FALSE);
  137. _dwStatus = GetLastError();
  138. goto exit;
  139. }
  140. if (!CloseHandle(_hFile))
  141. {
  142. DIGEST_ASSERT(FALSE);
  143. _dwStatus = GetLastError();
  144. goto exit;
  145. }
  146. _dwStatus = ERROR_SUCCESS;
  147. exit:
  148. return _dwStatus;
  149. }
  150. //--------------------------------------------------------------------
  151. // CMMFile::CheckNextNBits
  152. //
  153. // Determines if the next N bits are unset.
  154. //
  155. // Arguments:
  156. //
  157. // [IN/OUT]
  158. // DWORD &nArrayIndex, DWORD &dwMask
  159. //
  160. // [IN]
  161. // DWORD nBitsRequired
  162. //
  163. // [OUT]
  164. // DWORD &nBitsFound
  165. //
  166. // Return Value:
  167. //
  168. // TRUE if the next N bits were found unset.
  169. // FALSE otherwise.
  170. //
  171. // Notes:
  172. // This function assumes that the range of bits to be checked lie
  173. // within a valid area of the bit map.
  174. //--------------------------------------------------------------------
  175. BOOL CMMFile::CheckNextNBits(DWORD& nArrayIndex, DWORD& dwStartMask,
  176. DWORD nBitsRequired, DWORD& nBitsFound)
  177. {
  178. DWORD i;
  179. DWORD nIdx = nArrayIndex;
  180. DWORD dwMask = dwStartMask;
  181. BOOL fFound = FALSE;
  182. LPDWORD BitMap = &_pBitMap[nIdx];
  183. nBitsFound = 0;
  184. // Check if the next nBitsRequired bits are unset
  185. for (i = 0; i < nBitsRequired; i++)
  186. {
  187. // Is this bit unset?
  188. if ((*BitMap & dwMask) == 0)
  189. {
  190. // Have sufficient unset bits been found?
  191. if (++nBitsFound == nBitsRequired)
  192. {
  193. // Found sufficient bits. Success.
  194. fFound = TRUE;
  195. goto exit;
  196. }
  197. }
  198. // Ran into a set bit. Fail.
  199. else
  200. {
  201. // Indicate the array and bit index
  202. // of the set bit encountered.
  203. nArrayIndex = nIdx;
  204. dwStartMask = dwMask;
  205. goto exit;
  206. }
  207. // Left rotate the bit mask.
  208. dwMask <<= 1;
  209. if (dwMask == 0x0)
  210. {
  211. dwMask = 0x1;
  212. BitMap = &_pBitMap[++nIdx];
  213. }
  214. } // Loop nBitsRequired times.
  215. exit:
  216. return fFound;
  217. }
  218. //--------------------------------------------------------------------
  219. // CMMFile::SetNextNBits
  220. //
  221. // Given an array index and bit mask, sets the next N bits.
  222. //
  223. // Arguments:
  224. // [IN]
  225. // DWORD nIdx, DWORD dwMask, DWORD nBitsRequired
  226. //
  227. // Return Value:
  228. //
  229. // TRUE if the next N bits were found unset, and successfully set.
  230. // FALSE if unable to set all the required bits.
  231. //
  232. // Notes:
  233. // This function assumes that the range of bits to be set lie
  234. // within a valid area of the bit map. If the function returns
  235. // false, no bits are set.
  236. //--------------------------------------------------------------------
  237. BOOL CMMFile::SetNextNBits(DWORD nIdx, DWORD dwMask,
  238. DWORD nBitsRequired)
  239. {
  240. DWORD i, j, nBitsSet = 0;
  241. LPDWORD BitMap = &_pBitMap[nIdx];
  242. for (i = 0; i < nBitsRequired; i++)
  243. {
  244. // Check that this bit is not already set.
  245. if (*BitMap & dwMask)
  246. {
  247. // Fail. Unset the bits we just set and exit.
  248. for (j = nBitsSet; j > 0; j--)
  249. {
  250. DIGEST_ASSERT((*BitMap & dwMask) == 0);
  251. // Right rotate the bit mask.
  252. dwMask >>= 1;
  253. if (dwMask == 0x0)
  254. {
  255. dwMask = 0x80000000;
  256. BitMap = &_pBitMap[--nIdx];
  257. }
  258. *BitMap &= ~dwMask;
  259. }
  260. return FALSE;
  261. }
  262. *BitMap |= dwMask;
  263. nBitsSet++;
  264. // Left rotate the bit mask.
  265. dwMask <<= 1;
  266. if (dwMask == 0x0)
  267. {
  268. dwMask = 0x1;
  269. BitMap = &_pBitMap[++nIdx];
  270. }
  271. }
  272. // Success.
  273. return TRUE;
  274. }
  275. //--------------------------------------------------------------------
  276. // CMMFile::GetAndSetNextFreeEntry
  277. //
  278. // Computes the first available free entry index.
  279. //
  280. // Arguments:
  281. //
  282. // DWORD nBitsRequired
  283. //
  284. // Return Value:
  285. //
  286. // Next available free entry Index.
  287. //--------------------------------------------------------------------
  288. DWORD CMMFile::GetAndSetNextFreeEntry(DWORD nBitsRequired)
  289. {
  290. DWORD nReturnBit = 0xFFFFFFFF;
  291. // Align if 4k or greater
  292. BOOL fAlign = (nBitsRequired >= NUM_BITS_IN_DWORD ? TRUE : FALSE);
  293. // Scan DWORDS from the beginning of the byte array.
  294. DWORD nArrayIndex = 0;
  295. while (nArrayIndex < _nBitMapDwords)
  296. {
  297. // Process starting from this DWORD if alignment is not required
  298. // and there are free bits, or alignment is required and all bits
  299. // are free.
  300. if (_pBitMap[nArrayIndex] != 0xFFFFFFFF
  301. && (!fAlign || (fAlign && _pBitMap[nArrayIndex] == 0)))
  302. {
  303. DWORD nBitIndex = 0;
  304. DWORD dwMask = 0x1;
  305. LPDWORD BitMap = &_pBitMap[nArrayIndex];
  306. // Find a candidate slot.
  307. while (nBitIndex < NUM_BITS_IN_DWORD)
  308. {
  309. // Found first bit of a candidate slot.
  310. if ((*BitMap & dwMask) == 0)
  311. {
  312. // Calculate leading bit value.
  313. DWORD nLeadingBit = NUM_BITS_IN_DWORD * nArrayIndex + nBitIndex;
  314. // Don't exceed max number of entries.
  315. if (nLeadingBit + nBitsRequired > _nMaxEntries)
  316. {
  317. // Overstepped last internal entry
  318. goto exit;
  319. }
  320. // If we just need one bit, then we're done.
  321. if (nBitsRequired == 1)
  322. {
  323. *BitMap |= dwMask;
  324. nReturnBit = nLeadingBit;
  325. _pHeader->nEntries += 1;
  326. goto exit;
  327. }
  328. // Additional bits required.
  329. DWORD nBitsFound;
  330. DWORD nIdx = nArrayIndex;
  331. // Check the next nBitsRequired bits. Set them if free.
  332. if (CheckNextNBits(nIdx, dwMask, nBitsRequired, nBitsFound))
  333. {
  334. if (SetNextNBits(nIdx, dwMask, nBitsRequired))
  335. {
  336. // Return the offset of the leading bit.
  337. _pHeader->nEntries += nBitsRequired;
  338. nReturnBit = nLeadingBit;
  339. goto exit;
  340. }
  341. // Bad news.
  342. else
  343. {
  344. // The bits are free, but we couldn't set them. Fail.
  345. DIGEST_ASSERT(FALSE);
  346. goto exit;
  347. }
  348. }
  349. else
  350. {
  351. // This slot has insufficient contiguous free bits.
  352. // Update the array index. We break back to looping
  353. // over the bits in the DWORD where the interrupting
  354. // bit was found.
  355. nArrayIndex = nIdx;
  356. nBitIndex = (nBitIndex + nBitsFound) % NUM_BITS_IN_DWORD;
  357. break;
  358. }
  359. } // Found a free leading bit.
  360. else
  361. {
  362. // Continue looking at bits in this DWORD.
  363. nBitIndex++;
  364. dwMask <<= 1;
  365. }
  366. } // Loop over bits in DWORD.
  367. } // If we found a candidate DWORD.
  368. nArrayIndex++;
  369. } // Loop through all DWORDS.
  370. exit:
  371. return nReturnBit;
  372. }
  373. //--------------------------------------------------------------------
  374. // CMMFile::AllocateEntry
  375. //
  376. // Routine Description:
  377. //
  378. // Member function that returns an free entry from the cache list. If
  379. // none is available free, it grows the map file, makes more free
  380. // entries.
  381. //
  382. // Arguments:
  383. //
  384. // DWORD cbBytes : Number of bytes requested
  385. // DWORD cbOffset: Offset from beginning of bit map where allocation is
  386. // requested.
  387. //
  388. // Return Value:
  389. //
  390. //
  391. //--------------------------------------------------------------------
  392. LPMAP_ENTRY CMMFile::AllocateEntry(DWORD cbBytes)
  393. {
  394. LPMAP_ENTRY NewEntry;
  395. // BUGBUG - ASSERT THIS.
  396. // Validate cbBytes
  397. if (cbBytes > MAX_ENTRY_SIZE)
  398. {
  399. return NULL;
  400. }
  401. // Find and mark off a set of contiguous bits
  402. // spanning the requested number of bytes.
  403. DWORD nBlocksRequired = NUMBLOCKS(ROUNDUPBLOCKS(cbBytes), _cbEntry);
  404. DWORD FreeEntryIndex = GetAndSetNextFreeEntry(nBlocksRequired);
  405. // Failed to find space.
  406. if( FreeEntryIndex == 0xFFFFFFFF )
  407. {
  408. DIGEST_ASSERT(FALSE);
  409. return NULL;
  410. }
  411. // Cast the memory.
  412. NewEntry = (LPMAP_ENTRY)
  413. (_pHeap + _cbEntry * FreeEntryIndex);
  414. if (!VirtualAlloc(NewEntry, nBlocksRequired * _cbEntry,
  415. MEM_COMMIT, PAGE_READWRITE))
  416. {
  417. DIGEST_ASSERT(FALSE);
  418. _dwStatus = GetLastError();
  419. return NULL;
  420. }
  421. // Mark the allocated space.
  422. NewEntry->dwSig = SIG_ALLOC;
  423. // Set the number of blocks in the entry.
  424. NewEntry->nBlocks = nBlocksRequired;
  425. return NewEntry;
  426. }
  427. //--------------------------------------------------------------------
  428. // Routine Description:
  429. //
  430. // Attempts to reallocate an entry at the location given.
  431. //
  432. // Arguments:
  433. //
  434. // LPMAP_ENTRY pEntry: Pointer to location in file map.
  435. // DWORD cbBytes : Number of bytes requested
  436. //
  437. // Return Value:
  438. //
  439. // Original value of pEntry if successful. pEntry->nBlocks is set to
  440. // the new value, but all other fields in the entry are unmodified.
  441. // If insufficient contiguous bits are found at the end of the original
  442. // entry, NULL is returned, indicating failure. In this case the entry
  443. // remains unmodified.
  444. //
  445. //--------------------------------------------------------------------
  446. // BUGBUG -> remove ?
  447. BOOL CMMFile::ReAllocateEntry(LPMAP_ENTRY pEntry, DWORD cbBytes)
  448. {
  449. // Validate cbBytes
  450. if (cbBytes > MAX_ENTRY_SIZE)
  451. {
  452. DIGEST_ASSERT(FALSE);
  453. return FALSE;
  454. }
  455. // Validate pEntry.
  456. DWORD cbEntryOffset = (DWORD)((DWORD_PTR) pEntry - (DWORD_PTR) _pBitMap);
  457. if ((cbEntryOffset == 0)
  458. || (cbEntryOffset & (_cbEntry-1))
  459. || (cbEntryOffset >= _cbTotal))
  460. {
  461. DIGEST_ASSERT(FALSE);
  462. return FALSE;
  463. }
  464. // Calculate number of blocks required for this entry.
  465. DWORD nBlocksRequired = NUMBLOCKS(ROUNDUPBLOCKS(cbBytes), _cbEntry);
  466. // Sufficient space in current slot?
  467. if (nBlocksRequired <= pEntry->nBlocks)
  468. {
  469. // We're done.
  470. return TRUE;
  471. }
  472. else
  473. {
  474. // Determine if additional free bits are
  475. // available at the end of this entry.
  476. // If not, return NULL.
  477. // Determine the array and bit indicese of the first
  478. // free bit immediately following the last set bit of
  479. // the entry.
  480. DWORD nTrailingIndex = cbEntryOffset / _cbEntry + pEntry->nBlocks;
  481. DWORD nArrayIndex = nTrailingIndex / NUM_BITS_IN_DWORD;
  482. DWORD nBitIndex = nTrailingIndex % NUM_BITS_IN_DWORD;
  483. DWORD dwMask = 0x1 << nBitIndex;
  484. DWORD nAdditionalBlocksRequired = nBlocksRequired - pEntry->nBlocks;
  485. DWORD nBlocksFound;
  486. // Don't exceed the number of internal entries.
  487. if (nTrailingIndex + nAdditionalBlocksRequired
  488. > _nMaxEntries)
  489. {
  490. // Overstepped last internal entry. Here we should fail
  491. // by returning NULL. Note - DO NOT attempt to grow the
  492. // map file at this point. The caller does not expect this.
  493. return FALSE;
  494. }
  495. if (CheckNextNBits(nArrayIndex, dwMask,
  496. nAdditionalBlocksRequired, nBlocksFound))
  497. {
  498. // We were able to grow the entry.
  499. SetNextNBits(nArrayIndex, dwMask, nAdditionalBlocksRequired);
  500. pEntry->nBlocks = nBlocksRequired;
  501. _pHeader->nEntries += nAdditionalBlocksRequired;
  502. return TRUE;
  503. }
  504. else
  505. // Couldn't grow the entry.
  506. return FALSE;
  507. }
  508. }
  509. //--------------------------------------------------------------------
  510. // CMMFile::FreeEntry
  511. // This public member function frees up a file cache entry.
  512. //
  513. // Arguments:
  514. //
  515. // UrlEntry : pointer to the entry that being freed.
  516. //
  517. // Return Value:
  518. //
  519. // TRUE - if the entry is successfully removed from the cache.
  520. // FALSE - otherwise.
  521. //
  522. //--------------------------------------------------------------------
  523. BOOL CMMFile::FreeEntry(LPMAP_ENTRY Entry)
  524. {
  525. DWORD nIndex, nArrayIndex,
  526. nOffset, nBlocks, BitMask;
  527. LPDWORD BitMap;
  528. // Validate the pointer passed in.
  529. if(((LPBYTE) Entry < _pHeap)
  530. || ((LPBYTE) Entry >= (_pHeap + _cbEntry * _nMaxEntries)))
  531. {
  532. DIGEST_ASSERT(FALSE);
  533. return FALSE;
  534. }
  535. // Compute and check offset (number of bytes from start).
  536. nOffset = (DWORD)((DWORD_PTR)Entry - (DWORD_PTR)_pHeap);
  537. if( nOffset % _cbEntry )
  538. {
  539. // Pointer does not point to a valid entry.
  540. DIGEST_ASSERT(FALSE);
  541. return FALSE;
  542. }
  543. nBlocks = Entry->nBlocks;
  544. if (nBlocks > (MAX_ENTRY_SIZE / _cbEntry))
  545. {
  546. DIGEST_ASSERT(FALSE);
  547. return FALSE;
  548. }
  549. // Compute indicese
  550. nIndex = nOffset / _cbEntry;
  551. nArrayIndex = nIndex / NUM_BITS_IN_DWORD;
  552. // Unmark the index bits in the map.
  553. BitMap = &_pBitMap[nArrayIndex];
  554. BitMask = 0x1 << (nIndex % NUM_BITS_IN_DWORD);
  555. for (DWORD i = 0; i < nBlocks; i++)
  556. {
  557. // Check we don't free unset bits
  558. if (!(*BitMap & BitMask))
  559. {
  560. DIGEST_ASSERT(FALSE);
  561. return FALSE;
  562. }
  563. *BitMap &= ~BitMask;
  564. BitMask <<= 1;
  565. if (BitMask == 0x0)
  566. {
  567. BitMask = 0x1;
  568. BitMap = &_pBitMap[++nArrayIndex];
  569. }
  570. }
  571. // Mark the freed space.
  572. ResetEntryData(Entry, SIG_FREE, nBlocks);
  573. // Reduce the count of allocated entries.
  574. // INET_ASSERT (_HeaderInfo->NumUrlEntriesAlloced > 0);
  575. _pHeader->nEntries -= nBlocks;
  576. return TRUE;
  577. }
  578. //--------------------------------------------------------------------
  579. // CMMFile::SetHeaderData
  580. //--------------------------------------------------------------------
  581. VOID CMMFile::SetHeaderData(DWORD dwHeaderIndex, DWORD dwHeaderValue)
  582. {
  583. _pHeader->dwHeaderData[dwHeaderIndex] = dwHeaderValue;
  584. }
  585. //--------------------------------------------------------------------
  586. // CMMFile::GetHeaderData
  587. //--------------------------------------------------------------------
  588. LPDWORD CMMFile::GetHeaderData(DWORD dwHeaderIndex)
  589. {
  590. return &_pHeader->dwHeaderData[dwHeaderIndex];
  591. }
  592. //--------------------------------------------------------------------
  593. // CMMFile::ResetEntryData
  594. //--------------------------------------------------------------------
  595. VOID CMMFile::ResetEntryData(LPMAP_ENTRY Entry,
  596. DWORD dwResetValue, DWORD nBlocks)
  597. {
  598. for (DWORD i = 0; i < (_cbEntry * nBlocks) / sizeof(DWORD); i++)
  599. {
  600. *((DWORD*) Entry + i) = dwResetValue;
  601. }
  602. }
  603. //--------------------------------------------------------------------
  604. // CMMFile::GetMapPtr
  605. //--------------------------------------------------------------------
  606. DWORD_PTR CMMFile::GetMapPtr()
  607. {
  608. return (DWORD_PTR) _pHeader;
  609. }
  610. //--------------------------------------------------------------------
  611. // CMMFile::GetStatus
  612. //--------------------------------------------------------------------
  613. DWORD CMMFile::GetStatus()
  614. {
  615. return _dwStatus;
  616. }
  617. //--------------------------------------------------------------------
  618. // CMMFile::MakeUserObjectName
  619. // Added in fix for IE5# 89288
  620. // (inet\digest\init.cxx:MakeFullAccessSA: NULL DACL is no protection)
  621. //
  622. // Generates either of the names
  623. // <Local\>SSPIDIGESTMMMAP:username
  624. // <Local\>SSPIDIGESTMUTEX:username
  625. // where Local\ is prepended on NT, username from GetUserName
  626. //--------------------------------------------------------------------
  627. DWORD CMMFile::MakeUserObjectName(LPSTR szName, LPDWORD pcbName,
  628. DWORD dwFlags)
  629. {
  630. DWORD cbLocal, cbRequired,
  631. cbUserName = MAX_PATH, dwError = ERROR_SUCCESS;
  632. CHAR szUserName[MAX_PATH];
  633. DWORD cbNameFixed = (DWORD)((dwFlags == MAKE_MUTEX_NAME ?
  634. sizeof(SZ_MUTEXNAME) - 1 : sizeof(SZ_MAPNAME) - 1));
  635. // Get platform info.
  636. OSVERSIONINFO osInfo;
  637. osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  638. if (!GetVersionEx(&osInfo))
  639. {
  640. dwError = GetLastError();
  641. goto exit;
  642. }
  643. // Prepend "Local\" if on >= NT5
  644. if ((osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
  645. && (osInfo.dwMajorVersion >= 5))
  646. {
  647. // We will prepend "Local\"
  648. cbLocal = sizeof("Local\\") - 1;
  649. }
  650. else
  651. {
  652. // We will not prepend "Local\"
  653. cbLocal = 0;
  654. }
  655. // Get username. Default to "anyuser" if not present.
  656. if (!GetUserName(szUserName, &cbUserName))
  657. {
  658. cbUserName = sizeof("anyuser");
  659. memcpy(szUserName, "anyuser", cbUserName);
  660. }
  661. // Required size for name
  662. // eg <Local\>SSPIDIGESTMUTEX:username
  663. cbRequired = cbLocal + cbNameFixed + cbUserName;
  664. if (cbRequired > *pcbName)
  665. {
  666. *pcbName = cbRequired;
  667. dwError = ERROR_INSUFFICIENT_BUFFER;
  668. goto exit;
  669. }
  670. // <Local\>
  671. // (cbLocal may be 0)
  672. memcpy(szName, "Local\\", cbLocal);
  673. // <Local\>SSPIDIGESTMUTEX:
  674. memcpy(szName + cbLocal,
  675. (dwFlags == MAKE_MUTEX_NAME ? SZ_MUTEXNAME : SZ_MAPNAME),
  676. cbNameFixed);
  677. // <Local\> SSPIDIGESTMUTEX:username
  678. // cbUsername includes null terminator.
  679. memcpy(szName + cbLocal + cbNameFixed,
  680. szUserName, cbUserName);
  681. *pcbName = cbRequired;
  682. exit:
  683. return dwError;
  684. }