Leaked source code of windows server 2003
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.

2009 lines
51 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. filemap.cxx
  5. Abstract:
  6. contains implementation of MEMMAP_FILE class.
  7. Author:
  8. Madan Appiah (madana) 28-April-1995
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. Shishir Pardikar (shishirp) added: (as of (7/6/96)
  13. 1) Fix crossproces problems on win95 in checksizegrowandremap
  14. 2) Exception handling to deal with badsector being memorymapped
  15. 3) More robust validation at init time
  16. 4) Reinitialization code to really clear the cache
  17. 5) Bug fixes in GrowMap while growing partially filled dword
  18. --*/
  19. #include <cache.hxx>
  20. #define FILE_SIZE_MAX_DIGITS 16
  21. DWORD
  22. ValidateAndCreatePath(
  23. LPTSTR PathName
  24. )
  25. {
  26. DWORD Error, len;
  27. DWORD FileAttribute;
  28. LPTSTR PathDelimit;
  29. //
  30. // check to see the path specified is there.
  31. //
  32. FileAttribute = GetFileAttributes( PathName );
  33. if( FileAttribute != 0xFFFFFFFF ) {
  34. //
  35. // check to see the attribute says it is a dir.
  36. //
  37. if( !(FileAttribute & FILE_ATTRIBUTE_DIRECTORY) ) {
  38. return( ERROR_INVALID_PARAMETER );
  39. }
  40. // We found the file and it is a dir.
  41. // Set the system attribute just in case
  42. // it has been unset.
  43. SetFileAttributes(PathName, FILE_ATTRIBUTE_SYSTEM);
  44. return( ERROR_SUCCESS );
  45. }
  46. Error = GetLastError();
  47. if( (Error != ERROR_FILE_NOT_FOUND) &&
  48. (Error != ERROR_PATH_NOT_FOUND) ) {
  49. return( Error );
  50. }
  51. //
  52. // we did not find the path, so create it.
  53. //
  54. if( CreateDirectory( PathName, NULL ) ) {
  55. //
  56. // done.
  57. //
  58. SetFileAttributes(PathName, FILE_ATTRIBUTE_SYSTEM);
  59. return( ERROR_SUCCESS );
  60. }
  61. Error = GetLastError();
  62. if( Error != ERROR_PATH_NOT_FOUND ) {
  63. return( Error );
  64. }
  65. //
  66. // sub-path is not found, create it first.
  67. //
  68. len = lstrlen( PathName );
  69. if (len < 5) {
  70. SetLastError(ERROR_INVALID_NAME);
  71. return (ERROR_INVALID_NAME);
  72. }
  73. PathDelimit = PathName + len -1 ;
  74. // step back from the trailing backslash
  75. if( *PathDelimit == PATH_CONNECT_CHAR ) {
  76. PathDelimit--;
  77. }
  78. //
  79. // find the last path delimiter.
  80. //
  81. while( PathDelimit > PathName ) {
  82. if( *PathDelimit == PATH_CONNECT_CHAR ) {
  83. break;
  84. }
  85. PathDelimit--;
  86. }
  87. if( PathDelimit == PathName ) {
  88. return( ERROR_INVALID_PARAMETER );
  89. }
  90. *PathDelimit = TEXT('\0');
  91. //
  92. // validate sub-path now.
  93. //
  94. Error = ValidateAndCreatePath( PathName ) ;
  95. //
  96. // replace the connect char anyway.
  97. //
  98. *PathDelimit = PATH_CONNECT_CHAR;
  99. if( Error != ERROR_SUCCESS ) {
  100. return( Error );
  101. }
  102. //
  103. // try to create one more time.
  104. //
  105. if( CreateDirectory( PathName, NULL ) ) {
  106. //
  107. // done.
  108. //
  109. return( ERROR_SUCCESS );
  110. }
  111. Error = GetLastError();
  112. return( Error );
  113. }
  114. DWORD
  115. MEMMAP_FILE::CheckSizeGrowAndRemapAddress(
  116. VOID
  117. )
  118. {
  119. DWORD dwNewFileSize;
  120. #ifdef WIN95_BUG
  121. if( _FileSize == (dwNewFileSize = _HeaderInfo->FileSize )) {
  122. return( ERROR_SUCCESS );
  123. }
  124. #endif //WIN95_BUG
  125. // ideally we would have liked to do as in the above two lines
  126. // this works right on NT but doesn't on win95.
  127. // This is because the filesize is a part of the mapname
  128. // In the initial state the index file size is 8192. So the
  129. // memorymap name is c:_windows_temporaray internet files_8192.
  130. // Both the processes have this map in their address space.
  131. // Process B starts pumping in the data, and at some point the index
  132. // file needs to be grown. Process B, increases the index file to 16384,
  133. // updates the filesize in the header "while it is still mapped in the
  134. // map corresponding to the old filesize" and then remaps to the new map
  135. // with the name c:_windows_temporaray internet files_16384.
  136. // Any subsequent growth is now recorded in this map.
  137. // The old map c:_windows_temporaray internet files_8192 still has only
  138. // the first transition.
  139. // the work around is to actually get the filesize from the filesystem
  140. // This works correctly on win95 and NT both. Optimally, we would
  141. // check for a transition and then get the real size, but we will do that
  142. // after IE30 ships.
  143. //NB!!!!!!! The check below is the basis of our cross process
  144. // cache. All APIs finally make this call before touching the memory
  145. // mapped file. If there is a chneg, they remap it to the new size
  146. // with the sizename as part of the mapping, so they get the latest
  147. // stuff.
  148. // When anyone gets here, they are protected by a crossprocess mutex
  149. if( _FileSize == (dwNewFileSize = GetFileSize(_FileHandle, NULL))) {
  150. return( ERROR_SUCCESS );
  151. }
  152. //
  153. // so other user of the memmap file has increased the file size,
  154. // let's remap our address space so that the new portion is
  155. // visible to us too.
  156. //
  157. DWORD Error;
  158. DWORD OldFileSize;
  159. DWORD OldNumBitMapDWords;
  160. //
  161. // set our internal file size and num bit map entries.
  162. //
  163. OldFileSize = _FileSize;
  164. OldNumBitMapDWords = _NumBitMapDWords;
  165. _FileSize = dwNewFileSize;
  166. Error = RemapAddress();
  167. if( Error != ERROR_SUCCESS ) {
  168. //
  169. // reset the file size.
  170. //
  171. _FileSize = OldFileSize;
  172. _NumBitMapDWords = OldNumBitMapDWords;
  173. }
  174. else {
  175. #if INET_DEBUG
  176. if ((GetFileSize(_FileHandle, NULL)) != (_HeaderInfo->FileSize)) {
  177. TcpsvcsDbgPrint(( DEBUG_FILE_VALIDATE,
  178. "GetFileSize!= (_FileSize)\n" ));
  179. TcpsvcsDbgAssert(FALSE);
  180. }
  181. #endif //INET_DEBG
  182. _NumBitMapDWords =
  183. (_HeaderInfo->NumUrlInternalEntries + (NUM_BITS_IN_DWORD - 1)) /
  184. NUM_BITS_IN_DWORD; // cell
  185. }
  186. return( Error );
  187. }
  188. BOOL
  189. MEMMAP_FILE::ValidateCache(
  190. VOID
  191. )
  192. /*++
  193. This private member function validates the cache file content.
  194. Arguments:
  195. NONE.
  196. Return Value:
  197. TRUE - if the cache is valid.
  198. FALSE - otherwise.
  199. --*/
  200. {
  201. BOOL ReturnCode = FALSE;
  202. int i, k;
  203. DWORD BitPosition, TotalAlloced, MaxAllocedPosition, RunningCounter;
  204. __try {
  205. // validate signatue.
  206. if( memcmp(
  207. _HeaderInfo->FileSignature,
  208. CACHE_SIGNATURE,
  209. MAX_SIG_SIZE * sizeof(TCHAR) ) != 0 ) {
  210. TcpsvcsDbgPrint(( DEBUG_FILE_VALIDATE,
  211. "File signature does not match.\n" ));
  212. goto Cleanup;
  213. }
  214. // Also check the index does not contain entries with a higher
  215. // version than the current machine can handle. This can happen
  216. // due to Windows kludgy concept of roaming, which replicates
  217. // parts of the file system and registry hkcu.
  218. LPSTR pszHighVer = (LPSTR) (_HeaderInfo->dwHeaderData
  219. + CACHE_HEADER_DATA_HIGH_VERSION_STRING);
  220. if (pszHighVer[0] != 'V' || pszHighVer[3] != 0)
  221. memset (pszHighVer, 0, sizeof(DWORD));
  222. else if (!g_szFixup[0] || strcmp (g_szFixup, pszHighVer) < 0)
  223. {
  224. TcpsvcsDbgPrint(( DEBUG_FILE_VALIDATE,
  225. "Cannot handle uplevel index file.\n" ));
  226. goto Cleanup;
  227. }
  228. // check the hash table root offset is valid
  229. if( _HeaderInfo->dwHashTableOffset != 0 ) {
  230. if( _HeaderInfo->dwHashTableOffset > _FileSize ) {
  231. TcpsvcsDbgPrint(( DEBUG_FILE_VALIDATE,
  232. "invalid b-tree root offset.\n" ));
  233. goto Cleanup;
  234. }
  235. }
  236. // check file size.
  237. if( _HeaderInfo->FileSize != _FileSize ) {
  238. TcpsvcsDbgPrint(( DEBUG_FILE_VALIDATE,
  239. "invalid file size.\n" ));
  240. goto Cleanup;
  241. }
  242. // one more file size check.
  243. DWORD ExpectedFileSize;
  244. ExpectedFileSize =
  245. HEADER_ENTRY_SIZE +
  246. _HeaderInfo->NumUrlInternalEntries * _EntrySize;
  247. // cell the size to GlobalMapFileGrowSize.
  248. if( ExpectedFileSize % GlobalMapFileGrowSize ) {
  249. ExpectedFileSize =
  250. ((ExpectedFileSize / GlobalMapFileGrowSize) + 1) *
  251. GlobalMapFileGrowSize;
  252. }
  253. if( _FileSize != ExpectedFileSize ) {
  254. // it is ok if the file size is one block bigger.
  255. TcpsvcsDbgPrint(( DEBUG_FILE_VALIDATE,
  256. "Invalid file size.\n" ));
  257. goto Cleanup;
  258. }
  259. if(_HeaderInfo->NumUrlInternalEntries < _HeaderInfo->NumUrlEntriesAlloced) {
  260. TcpsvcsDbgPrint(( DEBUG_FILE_VALIDATE,
  261. "Invalid alloc entires.\n" ));
  262. goto Cleanup;
  263. }
  264. TotalAlloced = 0;
  265. MaxAllocedPosition = 0;
  266. RunningCounter = 0;
  267. // scan the enire bitmap and do some consistency check for allocated bits
  268. for(i=0; i<BIT_MAP_ARRAY_SIZE; ++i) {
  269. // k goes from 0 to 31
  270. // BitPosition goes from 0x00000001 to 0x80000000
  271. for(BitPosition=1, k=0; k<NUM_BITS_IN_DWORD; ++k, BitPosition <<=1) {
  272. ++RunningCounter;
  273. if(_HeaderInfo->AllocationBitMap[i] & BitPosition) {
  274. ++TotalAlloced;
  275. MaxAllocedPosition = RunningCounter;
  276. }
  277. }
  278. }
  279. // if the max allocated bit is greter than the number of
  280. // possible entries for this filesize,
  281. // or the total allocated bits are greater (the above condition subsumes
  282. // this one, but it is OK to be paranoid)
  283. // or totalbits alloced don't match the count
  284. // there this header is not OK
  285. if ((MaxAllocedPosition > _HeaderInfo->NumUrlInternalEntries)
  286. ||(TotalAlloced > _HeaderInfo->NumUrlInternalEntries)
  287. ||(TotalAlloced != _HeaderInfo->NumUrlEntriesAlloced)) {
  288. TcpsvcsDbgPrint(( DEBUG_FILE_VALIDATE,
  289. "Invalid alloc bitmap\n" ));
  290. goto Cleanup;
  291. }
  292. //
  293. // every thing is fine.
  294. //
  295. ReturnCode = TRUE;
  296. }
  297. __except(EXCEPTION_EXECUTE_HANDLER) {
  298. ReturnCode = FALSE;
  299. _Status = ERROR_WRITE_FAULT;
  300. }
  301. ENDEXCEPT
  302. Cleanup:
  303. if( ReturnCode == FALSE ) {
  304. TcpsvcsDbgPrint(( DEBUG_FILE_VALIDATE, "Invalid Cache, or bad disk\n" ));
  305. }
  306. return( ReturnCode );
  307. }
  308. void MEMMAP_FILE::CloseMapping (void)
  309. {
  310. if (_BaseAddr) // view
  311. {
  312. UnmapViewOfFile(_BaseAddr);
  313. _BaseAddr = NULL;
  314. }
  315. if (_FileMappingHandle) // mapping
  316. {
  317. CloseHandle (_FileMappingHandle);
  318. _FileMappingHandle = NULL;
  319. }
  320. if (_FileHandle) // file
  321. {
  322. CloseHandle (_FileHandle);
  323. _FileHandle = NULL;
  324. }
  325. }
  326. DWORD
  327. MEMMAP_FILE::RemapAddress(
  328. VOID
  329. )
  330. /*++
  331. This private member function remaps the memory mapped file just after
  332. the file size has been modified.
  333. Container must be locked when this function is called.
  334. Arguments:
  335. NONE.
  336. Return Value:
  337. Windows Error Code.
  338. --*/
  339. {
  340. DWORD Error = ERROR_SUCCESS;
  341. PVOID OldBaseAddr;
  342. DWORD OldViewSize;
  343. PVOID VirtualBase;
  344. BOOL BoolError;
  345. LPTSTR MapName = NULL;
  346. SECURITY_ATTRIBUTES* psa = NULL;
  347. CloseMapping();
  348. //
  349. // Create/Open memory mapped file.
  350. //
  351. if (!_PerUser)
  352. {
  353. psa = SHGetAllAccessSA();
  354. }
  355. if (_PerUser || psa)
  356. {
  357. _FileHandle =
  358. CreateFile(
  359. _FileName,
  360. GENERIC_READ | GENERIC_WRITE,
  361. FILE_SHARE_READ | FILE_SHARE_WRITE,
  362. // share this file with others while it is being used.
  363. psa,
  364. OPEN_ALWAYS,
  365. FILE_FLAG_RANDOM_ACCESS,
  366. NULL );
  367. }
  368. else
  369. {
  370. _FileHandle = INVALID_HANDLE_VALUE;
  371. }
  372. if( _FileHandle == INVALID_HANDLE_VALUE ) {
  373. Error = _Status = GetLastError();
  374. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  375. "Reinitialize:File open failed, %ld.\n",_Status));
  376. TcpsvcsDbgAssert( FALSE );
  377. _FileHandle = NULL;
  378. goto Cleanup;
  379. }
  380. #ifndef unix
  381. /*******
  382. * UNIX:
  383. * Mainwin does not support MapName in CreateFileMapping API
  384. * Let us leave the MapName as NULL till this functionality
  385. * is available.
  386. */
  387. //
  388. // make a map name.
  389. //
  390. DWORD MapNameSize;
  391. MapNameSize =
  392. (lstrlen(_FullPathName) +
  393. lstrlen( _FileName) +
  394. 1 +
  395. FILE_SIZE_MAX_DIGITS ) * sizeof(TCHAR) ;
  396. MapName = (LPTSTR) CacheHeap->Alloc( MapNameSize );
  397. if( MapName == NULL ) {
  398. Error = ERROR_NOT_ENOUGH_MEMORY;
  399. goto Cleanup;
  400. }
  401. memcpy(MapName, _FileName, _FullPathNameLen + sizeof(MEMMAP_FILE_NAME));
  402. memcpy(MapName + _FullPathNameLen + sizeof(MEMMAP_FILE_NAME) - 1, DIR_SEPARATOR_STRING, sizeof(DIR_SEPARATOR_STRING));
  403. wsprintf(MapName + lstrlen(MapName), "%u", _FileSize);
  404. #ifndef unix
  405. #define BACKSLASH_CHAR TEXT('\\')
  406. #else
  407. #define BACKSLASH_CHAR TEXT('/')
  408. #endif /* unix */
  409. #define UNDERSCORE_CHAR TEXT('_')
  410. #define TERMINATING_CHAR TEXT('\0')
  411. LPTSTR ScanMapName;
  412. //
  413. // Replace '\' with '_'.
  414. //
  415. ScanMapName = MapName;
  416. while( *ScanMapName != TERMINATING_CHAR ) {
  417. if( *ScanMapName == BACKSLASH_CHAR ) {
  418. *ScanMapName = UNDERSCORE_CHAR;
  419. }
  420. ScanMapName++;
  421. }
  422. #endif /* !unix */
  423. //
  424. // re-create memory mapping.
  425. //
  426. _FileMappingHandle = OpenFileMapping(FILE_MAP_WRITE, FALSE, MapName);
  427. if (_FileMappingHandle == NULL && (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_NAME))
  428. {
  429. _FileMappingHandle =
  430. CreateFileMapping(
  431. _FileHandle,
  432. psa,
  433. PAGE_READWRITE,
  434. 0, // high dword of max memory mapped file size.
  435. #if defined(UNIX) && defined(ux10)
  436. 1024 * 1024, // map entire file.
  437. #else
  438. 0, // map entire file.
  439. #endif
  440. MapName);
  441. }
  442. if( _FileMappingHandle == NULL ) {
  443. Error = _Status = GetLastError();
  444. goto Cleanup;
  445. }
  446. //
  447. // remap view region.
  448. //
  449. _BaseAddr =
  450. MapViewOfFileEx(
  451. _FileMappingHandle,
  452. FILE_MAP_WRITE,
  453. 0,
  454. 0,
  455. #if defined(UNIX) && defined(ux10)
  456. 1024 * 1024, // MAP entire file.
  457. #else
  458. 0, // MAP entire file.
  459. #endif
  460. NULL );
  461. #if defined(UNIX) && defined(ux10)
  462. DWORD FilePointer = SetFilePointer(
  463. _FileHandle,
  464. _FileSize,
  465. NULL,
  466. FILE_BEGIN );
  467. if (FilePointer == 0xFFFFFFFF)
  468. {
  469. Error = _Status = GetLastError();
  470. goto Cleanup;
  471. }
  472. BoolError = SetEndOfFile( _FileHandle );
  473. if (BoolError == FALSE)
  474. {
  475. Error = _Status = GetLastError();
  476. goto Cleanup;
  477. }
  478. #endif
  479. if( _BaseAddr == NULL )
  480. {
  481. Error = _Status = GetLastError();
  482. TcpsvcsDbgAssert( FALSE );
  483. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  484. "MapViewOfFile failed to extend address space, %ld.\n",
  485. Error ));
  486. goto Cleanup;
  487. }
  488. //
  489. // reset other pointers.
  490. //
  491. _HeaderInfo = (LPMEMMAP_HEADER)_BaseAddr;
  492. _EntryArray = ((LPBYTE)_BaseAddr + HEADER_ENTRY_SIZE );
  493. _Status = Error = ERROR_SUCCESS;
  494. Cleanup:
  495. if( MapName != NULL ) {
  496. CacheHeap->Free( MapName );
  497. }
  498. return( Error );
  499. }
  500. DWORD
  501. MEMMAP_FILE::GrowMapFile(DWORD dwMapFileGrowSize)
  502. /*++
  503. This private member function extends the memory mapped file and
  504. creates more free url store entries.
  505. Arguments:
  506. NONE.
  507. Return Value:
  508. Windows Error Code.
  509. --*/
  510. {
  511. DWORD Error, i;
  512. BOOL BoolError;
  513. DWORD FilePointer;
  514. DWORD OldNumUrlInternalEntries;
  515. //
  516. // check to see that we have reached the limit.
  517. // we can hold only MAX_URL_ENTRIES url entries.
  518. // so the file size can grow more than
  519. //
  520. // HEADER_ENTRY_SIZE + MAX_URL_ENTRIES * _EntrySize
  521. //
  522. #if INET_DEBUG
  523. if (GetFileSize(_FileHandle, NULL) != (_FileSize)) {
  524. TcpsvcsDbgPrint(( DEBUG_FILE_VALIDATE,
  525. "GetFileSize!= (_FileSize)\n" ));
  526. TcpsvcsDbgAssert(FALSE);
  527. }
  528. #endif //INET_DEBG
  529. //BUGBUG - need to fix this
  530. if( (_FileSize + dwMapFileGrowSize) >=
  531. (HEADER_ENTRY_SIZE +
  532. MAX_URL_ENTRIES * _EntrySize) ) {
  533. //
  534. // best matching error code.
  535. //
  536. Error = ERROR_NOT_ENOUGH_MEMORY;
  537. goto Cleanup;
  538. }
  539. FilePointer = SetFilePointer(
  540. _FileHandle,
  541. dwMapFileGrowSize,
  542. NULL,
  543. FILE_END );
  544. if (FilePointer != (_FileSize + dwMapFileGrowSize))
  545. {
  546. TcpsvcsDbgPrint(( DEBUG_FILE_VALIDATE,
  547. "FilePointer != (_FileSize + dwMapFileGrowSize)\n" ));
  548. TcpsvcsDbgAssert(FALSE);
  549. _Status = GetLastError();
  550. Error = _Status;
  551. goto Cleanup;
  552. }
  553. if( FilePointer == 0xFFFFFFFF ) {
  554. Error = GetLastError();
  555. TcpsvcsDbgAssert(FALSE);
  556. goto Cleanup;
  557. }
  558. BoolError = SetEndOfFile( _FileHandle );
  559. if( BoolError != TRUE ) {
  560. Error = GetLastError();
  561. TcpsvcsDbgAssert(FALSE);
  562. goto Cleanup;
  563. }
  564. #if INET_DEBUG
  565. if (GetFileSize(_FileHandle, NULL) != (_FileSize + dwMapFileGrowSize)) {
  566. TcpsvcsDbgPrint(( DEBUG_FILE_VALIDATE,
  567. "GetFileSize!= (_FileSize + dwMapFileGrowSize)\n" ));
  568. TcpsvcsDbgAssert(FALSE);
  569. }
  570. #endif
  571. //
  572. // adjust internal size parameters.
  573. //
  574. _FileSize += dwMapFileGrowSize;
  575. //
  576. // also set the new file size in the memory mapped file so that
  577. // other user will remap their address space and view the new portion.
  578. //
  579. _HeaderInfo->FileSize = _FileSize;
  580. OldNumUrlInternalEntries = _HeaderInfo->NumUrlInternalEntries;
  581. _HeaderInfo->NumUrlInternalEntries +=
  582. dwMapFileGrowSize / _EntrySize;
  583. _NumBitMapDWords =
  584. (_HeaderInfo->NumUrlInternalEntries + (NUM_BITS_IN_DWORD - 1)) /
  585. NUM_BITS_IN_DWORD; // cell
  586. //
  587. // remap
  588. //
  589. Error = RemapAddress();
  590. if( Error != ERROR_SUCCESS ) {
  591. goto Cleanup;
  592. }
  593. memset(
  594. (_EntryArray + _EntrySize * OldNumUrlInternalEntries),
  595. 0,
  596. dwMapFileGrowSize );
  597. Error = ERROR_SUCCESS;
  598. Cleanup:
  599. return( Error );
  600. }
  601. BOOL MEMMAP_FILE::CheckNextNBits(DWORD& nArrayIndex, DWORD &dwStartMask,
  602. DWORD nBitsRequired, DWORD& nBitsFound)
  603. {
  604. /*++
  605. Determines if the next N bits are unset.
  606. Arguments:
  607. [IN/OUT]
  608. DWORD &nArrayIndex, DWORD &dwMask
  609. [IN]
  610. DWORD nBitsRequired
  611. [OUT]
  612. DWORD &nBitsFound
  613. Return Value:
  614. TRUE if the next N bits were found unset.
  615. FALSE otherwise.
  616. Notes:
  617. This function assumes that the range of bits to be checked lie
  618. within a valid area of the bit map.
  619. --*/
  620. DWORD i, j;
  621. DWORD nIdx = nArrayIndex;
  622. DWORD dwMask = dwStartMask;
  623. BOOL fFound = FALSE;
  624. LPDWORD BitMap = &_HeaderInfo->AllocationBitMap[nIdx];
  625. nBitsFound = 0;
  626. // Check if the next nBitsRequired bits are unset
  627. for (i = 0; i < nBitsRequired; i++)
  628. {
  629. // Is this bit unset?
  630. if ((*BitMap & dwMask) == 0)
  631. {
  632. // Have sufficient unset bits been found?
  633. if (++nBitsFound == nBitsRequired)
  634. {
  635. // Found sufficient bits. Success.
  636. fFound = TRUE;
  637. goto exit;
  638. }
  639. }
  640. // Ran into a set bit. Fail.
  641. else
  642. {
  643. // Indicate the array and bit index
  644. // of the set bit encountered.
  645. nArrayIndex = nIdx;
  646. dwStartMask = dwMask;
  647. goto exit;
  648. }
  649. // Left rotate the bit mask.
  650. dwMask <<= 1;
  651. if (dwMask == 0x0)
  652. {
  653. dwMask = 0x1;
  654. BitMap = &_HeaderInfo->AllocationBitMap[++nIdx];
  655. }
  656. } // Loop nBitsRequired times.
  657. exit:
  658. return fFound;
  659. }
  660. BOOL MEMMAP_FILE::SetNextNBits(DWORD nIdx, DWORD dwMask,
  661. DWORD nBitsRequired)
  662. /*++
  663. Given an array index and bit mask, sets the next N bits.
  664. Arguments:
  665. [IN]
  666. DWORD nIdx, DWORD dwMask, DWORD nBitsRequired
  667. Return Value:
  668. TRUE if the next N bits were found unset, and successfully set.
  669. FALSE if unable to set all the required bits.
  670. Notes:
  671. This function assumes that the range of bits to be set lie
  672. within a valid area of the bit map. If the function returns
  673. false, no bits are set.
  674. --*/
  675. {
  676. DWORD i, j, nBitsSet = 0;
  677. LPDWORD BitMap = &_HeaderInfo->AllocationBitMap[nIdx];
  678. BitMap = &_HeaderInfo->AllocationBitMap[nIdx];
  679. for (i = 0; i < nBitsRequired; i++)
  680. {
  681. // Check that this bit is not already set.
  682. if (*BitMap & dwMask)
  683. {
  684. INET_ASSERT(FALSE);
  685. // Fail. Unset the bits we just set and exit.
  686. for (j = nBitsSet; j > 0; j--)
  687. {
  688. INET_ASSERT((*BitMap & dwMask) == 0);
  689. // Right rotate the bit mask.
  690. dwMask >>= 1;
  691. if (dwMask == 0x0)
  692. {
  693. dwMask = 0x80000000;
  694. BitMap = &_HeaderInfo->AllocationBitMap[--nIdx];
  695. }
  696. *BitMap &= ~dwMask;
  697. }
  698. return FALSE;
  699. }
  700. *BitMap |= dwMask;
  701. nBitsSet++;
  702. // Left rotate the bit mask.
  703. dwMask <<= 1;
  704. if (dwMask == 0x0)
  705. {
  706. dwMask = 0x1;
  707. BitMap = &_HeaderInfo->AllocationBitMap[++nIdx];
  708. }
  709. }
  710. // Success.
  711. return TRUE;
  712. }
  713. DWORD
  714. MEMMAP_FILE::GetAndSetNextFreeEntry(
  715. DWORD nBitsRequired
  716. )
  717. /*++
  718. This private member function computes the first available free entry
  719. index.
  720. Arguments:
  721. DWORD nBitsRequired
  722. Return Value:
  723. Next available free entry Index.
  724. --*/
  725. {
  726. DWORD i, nReturnBit = 0xFFFFFFFF;
  727. // Align if 4k or greater
  728. BOOL fAlign = (nBitsRequired >= NUM_BITS_IN_DWORD ? TRUE : FALSE);
  729. // Scan DWORDS from the beginning of the byte array.
  730. DWORD nArrayIndex = 0;
  731. while (nArrayIndex < _NumBitMapDWords)
  732. {
  733. // Process starting from this DWORD if alignment is not required
  734. // and there are free bits, or alignment is required and all bits
  735. // are free.
  736. if (_HeaderInfo->AllocationBitMap[nArrayIndex] != 0xFFFFFFFF
  737. && (!fAlign || (fAlign && _HeaderInfo->AllocationBitMap[nArrayIndex] == 0)))
  738. {
  739. DWORD nBitIndex = 0;
  740. DWORD dwMask = 0x1;
  741. LPDWORD BitMap = &_HeaderInfo->AllocationBitMap[nArrayIndex];
  742. // Find a candidate slot.
  743. while (nBitIndex < NUM_BITS_IN_DWORD)
  744. {
  745. // Found first bit of a candidate slot.
  746. if ((*BitMap & dwMask) == 0)
  747. {
  748. // Calculate leading bit value.
  749. DWORD nLeadingBit = NUM_BITS_IN_DWORD * nArrayIndex + nBitIndex;
  750. // Don't exceed the number of internal entries.
  751. if (nLeadingBit + nBitsRequired > _HeaderInfo->NumUrlInternalEntries)
  752. {
  753. // Overstepped last internal entry
  754. goto exit;
  755. }
  756. // If we just need one bit, then we're done.
  757. if (nBitsRequired == 1)
  758. {
  759. *BitMap |= dwMask;
  760. nReturnBit = nLeadingBit;
  761. _HeaderInfo->NumUrlEntriesAlloced += 1;
  762. goto exit;
  763. }
  764. // Additional bits required.
  765. DWORD nBitsFound;
  766. DWORD nIdx = nArrayIndex;
  767. // Check the next nBitsRequired bits. Set them if free.
  768. if (CheckNextNBits(nIdx, dwMask, nBitsRequired, nBitsFound))
  769. {
  770. if (SetNextNBits(nIdx, dwMask, nBitsRequired))
  771. {
  772. // Return the offset of the leading bit.
  773. _HeaderInfo->NumUrlEntriesAlloced += nBitsRequired;
  774. nReturnBit = nLeadingBit;
  775. goto exit;
  776. }
  777. // Bad news.
  778. else
  779. {
  780. // The bits are free, but we couldn't set them. Fail.
  781. goto exit;
  782. }
  783. }
  784. else
  785. {
  786. // This slot has insufficient contiguous free bits.
  787. // Update the array index. We break back to looping
  788. // over the bits in the DWORD where the interrupting
  789. // bit was found.
  790. nArrayIndex = nIdx;
  791. nBitIndex = (nBitIndex + nBitsFound) % NUM_BITS_IN_DWORD;
  792. break;
  793. }
  794. } // Found a free leading bit.
  795. else
  796. {
  797. // Continue looking at bits in this DWORD.
  798. nBitIndex++;
  799. dwMask <<= 1;
  800. }
  801. } // Loop over bits in DWORD.
  802. } // If we found a candidate DWORD.
  803. nArrayIndex++;
  804. } // Loop through all DWORDS.
  805. exit:
  806. return nReturnBit;
  807. }
  808. MemMapStatus MEMMAP_FILE::Init(LPTSTR PathName, DWORD EntrySize, BOOL PerUser)
  809. /*++
  810. MEMMAP_FILE object constructor.
  811. Arguments:
  812. PathName : full path name of the memory mapped file.
  813. EntrySize : size of the each entry in this container.
  814. Return Value:
  815. NONE.
  816. --*/
  817. {
  818. DWORD cb;
  819. _EntrySize = EntrySize;
  820. _PerUser = PerUser;
  821. _FullPathName = NULL;
  822. _FileName = NULL;
  823. _FileSize = 0;
  824. _FileHandle = NULL;
  825. _FileMappingHandle = NULL;
  826. _BaseAddr = NULL;
  827. _HeaderInfo = NULL;
  828. _EntryArray = NULL;
  829. _NumBitMapDWords = 0;
  830. // Validate the path and create the path if it is not already there.
  831. _Status = ValidateAndCreatePath( PathName );
  832. if( _Status != ERROR_SUCCESS )
  833. goto Cleanup;
  834. // Path to memory mapped file.
  835. cb = strlen(PathName);
  836. _FullPathName = (LPTSTR)CacheHeap->Alloc(cb + sizeof(DIR_SEPARATOR_STRING));
  837. if( _FullPathName == NULL )
  838. {
  839. _Status = ERROR_NOT_ENOUGH_MEMORY;
  840. INET_ASSERT(FALSE);
  841. goto Cleanup;
  842. }
  843. memcpy(_FullPathName, PathName, cb + 1);
  844. AppendSlashIfNecessary(_FullPathName, &cb);
  845. _FullPathNameLen = cb;
  846. // Construct memory mapped file name.
  847. _FileName = (LPTSTR)CacheHeap->Alloc(cb + sizeof(MEMMAP_FILE_NAME));
  848. if (!_FileName)
  849. {
  850. _Status = ERROR_NOT_ENOUGH_MEMORY;
  851. INET_ASSERT(FALSE);
  852. goto Cleanup;
  853. }
  854. memcpy(_FileName, _FullPathName, cb);
  855. memcpy(_FileName + cb,
  856. MEMMAP_FILE_NAME, sizeof(MEMMAP_FILE_NAME));
  857. SECURITY_ATTRIBUTES* psa = NULL;
  858. if (!_PerUser)
  859. {
  860. psa = SHGetAllAccessSA();
  861. }
  862. if (_PerUser || psa)
  863. {
  864. // Create/Open memory mapped file.
  865. _FileHandle =
  866. CreateFile(
  867. _FileName,
  868. GENERIC_READ | GENERIC_WRITE,
  869. FILE_SHARE_READ | FILE_SHARE_WRITE,
  870. psa,
  871. OPEN_ALWAYS,
  872. FILE_FLAG_RANDOM_ACCESS,
  873. NULL );
  874. }
  875. else
  876. {
  877. _FileHandle = INVALID_HANDLE_VALUE;
  878. }
  879. _Status = GetLastError();
  880. if( _FileHandle == INVALID_HANDLE_VALUE )
  881. {
  882. _FileHandle = NULL;
  883. TcpsvcsDbgAssert(FALSE);
  884. goto Cleanup;
  885. }
  886. else
  887. {
  888. SetFileTime(_FileHandle, NULL, NULL, (LPFILETIME)&dwdwSessionStartTime);
  889. }
  890. // Check to this file is new.
  891. if ( _Status == ERROR_ALREADY_EXISTS )
  892. {
  893. // Old file.
  894. _Status = ERROR_SUCCESS;
  895. _NewFile = FALSE;
  896. _FileSize = GetFileSize( _FileHandle, NULL );
  897. if( _FileSize == 0xFFFFFFFF )
  898. {
  899. _Status = GetLastError();
  900. TcpsvcsDbgAssert(FALSE);
  901. goto Cleanup;
  902. }
  903. if ((_FileSize < GlobalMapFileGrowSize) || ((_FileSize %GlobalMapFileGrowSize) != 0))
  904. {
  905. TcpsvcsDbgAssert(FALSE);
  906. if(!Reinitialize())
  907. {
  908. TcpsvcsDbgAssert(FALSE);
  909. SetLastError(_Status);
  910. goto Cleanup;
  911. }
  912. // Reinitialization results in new file.
  913. _NewFile = TRUE;
  914. }
  915. }
  916. else if( _Status == ERROR_SUCCESS)
  917. {
  918. BOOL BoolError;
  919. DWORD FilePointer;
  920. // New file.
  921. _NewFile = TRUE;
  922. // Set initial file size.
  923. _FileSize = GlobalMapFileGrowSize;
  924. FilePointer = SetFilePointer( _FileHandle, _FileSize, NULL, FILE_BEGIN );
  925. if( FilePointer == 0xFFFFFFFF )
  926. {
  927. _Status = GetLastError();
  928. goto Cleanup;
  929. }
  930. if (FilePointer != _FileSize )
  931. {
  932. TcpsvcsDbgPrint(( DEBUG_FILE_VALIDATE,
  933. "FilePointer != (_FileSize)\n" ));
  934. TcpsvcsDbgAssert(FALSE);
  935. }
  936. BoolError = SetEndOfFile( _FileHandle );
  937. if( BoolError != TRUE )
  938. {
  939. _Status = GetLastError();
  940. goto Cleanup;
  941. }
  942. }
  943. else
  944. {
  945. // We should not reach here.
  946. TcpsvcsDbgAssert(FALSE);
  947. }
  948. _Status = RemapAddress();
  949. if( _Status != ERROR_SUCCESS )
  950. {
  951. TcpsvcsDbgAssert(FALSE);
  952. goto Cleanup;
  953. }
  954. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  955. "Header Size, %ld.\n",
  956. HEADER_ENTRY_SIZE));
  957. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  958. "Size of elements, %ld.\n",
  959. sizeof(MEMMAP_HEADER_SMALL)));
  960. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  961. "Bit Array size, %ld.\n",
  962. BIT_MAP_ARRAY_SIZE));
  963. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  964. "Memmap Header Size, %ld.\n",
  965. sizeof(MEMMAP_HEADER)));
  966. TcpsvcsDbgAssert( HEADER_ENTRY_SIZE >= sizeof(MEMMAP_HEADER) );
  967. // validate the file content if the file is not new.
  968. if( _NewFile != TRUE )
  969. {
  970. if( ValidateCache() == FALSE)
  971. {
  972. if (!Reinitialize())
  973. {
  974. _Status = ERROR_INTERNET_INTERNAL_ERROR;
  975. goto Cleanup;
  976. }
  977. // Succeeded in re-initializing the file, we
  978. // treat this as if we created a new file.
  979. _NewFile = TRUE;
  980. }
  981. }
  982. else
  983. {
  984. // It is a brand new file. Initialize file header.
  985. if(!InitHeaderInfo())
  986. {
  987. // This can happen if there is an exception while
  988. // initializing headers
  989. _Status = ERROR_INTERNET_INTERNAL_ERROR;
  990. goto Cleanup;
  991. }
  992. }
  993. // Compute number of bitmap DWORDs used.
  994. _NumBitMapDWords =
  995. (_HeaderInfo->NumUrlInternalEntries + (NUM_BITS_IN_DWORD - 1)) /
  996. NUM_BITS_IN_DWORD; //cell
  997. // We are done.
  998. _Status = ERROR_SUCCESS;
  999. Cleanup:
  1000. if( _Status != ERROR_SUCCESS )
  1001. {
  1002. INET_ASSERT(FALSE);
  1003. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  1004. "MEMMAP_FILE::Initfailed, %ld\n", _Status ));
  1005. SetLastError(_Status);
  1006. }
  1007. if (_NewFile)
  1008. return MEMMAP_STATUS_REINITIALIZED;
  1009. else
  1010. return MEMMAP_STATUS_OPENED_EXISTING;
  1011. }
  1012. MEMMAP_FILE::~MEMMAP_FILE(
  1013. VOID
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. MEMMAP_FILE object destructor.
  1018. Arguments:
  1019. None.
  1020. Return Value:
  1021. None.
  1022. --*/
  1023. {
  1024. CloseMapping();
  1025. CacheHeap->Free( _FileName );
  1026. CacheHeap->Free( _FullPathName );
  1027. }
  1028. BOOL MEMMAP_FILE::ReAllocateEntry(LPFILEMAP_ENTRY pEntry, DWORD cbBytes)
  1029. /*++
  1030. Routine Description:
  1031. Attempts to reallocate an entry at the location given.
  1032. Arguments:
  1033. LPFILEMAP_ENTRY pEntry: Pointer to location in file map.
  1034. DWORD cbBytes : Number of bytes requested
  1035. Return Value:
  1036. Original value of pEntry if successful. pEntry->nBlocks is set to the new
  1037. value, but all other fields in the entry are unmodified. If insufficient contiguous
  1038. bits are found at the end of the original entry, NULL is returned, indicating failure.
  1039. In this case the entry remains unmodified.
  1040. Notes:
  1041. The Map file should *not* be grown if insufficient additional bits are not found.
  1042. --*/
  1043. {
  1044. // Validate cbBytes
  1045. if (cbBytes > MAX_ENTRY_SIZE)
  1046. {
  1047. INET_ASSERT(FALSE);
  1048. return FALSE;
  1049. }
  1050. // Validate pEntry.
  1051. DWORD cbEntryOffset = (DWORD) PtrDifference(pEntry, _EntryArray);
  1052. if (IsBadOffset(cbEntryOffset))
  1053. {
  1054. INET_ASSERT(FALSE);
  1055. return FALSE;
  1056. }
  1057. // Calculate number of blocks required for this entry.
  1058. DWORD nBlocksRequired = NUMBLOCKS(ROUNDUPBLOCKS(cbBytes));
  1059. // Sufficient space in current slot?
  1060. if (nBlocksRequired <= pEntry->nBlocks)
  1061. {
  1062. // We're done.
  1063. return TRUE;
  1064. }
  1065. else
  1066. {
  1067. // Determine if additional free bits are
  1068. // available at the end of this entry.
  1069. // If not, return NULL.
  1070. // Determine the array and bit indicese of the first
  1071. // free bit immediately following the last set bit of
  1072. // the entry.
  1073. DWORD nTrailingIndex = cbEntryOffset / _EntrySize + pEntry->nBlocks;
  1074. DWORD nArrayIndex = nTrailingIndex / NUM_BITS_IN_DWORD;
  1075. DWORD nBitIndex = nTrailingIndex % NUM_BITS_IN_DWORD;
  1076. DWORD dwMask = 0x1 << nBitIndex;
  1077. DWORD nAdditionalBlocksRequired = nBlocksRequired - pEntry->nBlocks;
  1078. DWORD nBlocksFound;
  1079. // Don't exceed the number of internal entries.
  1080. if (nTrailingIndex + nAdditionalBlocksRequired
  1081. > _HeaderInfo->NumUrlInternalEntries)
  1082. {
  1083. // Overstepped last internal entry. Here we should fail
  1084. // by returning NULL. Note - DO NOT attempt to grow the
  1085. // map file at this point. The caller does not expect this.
  1086. return FALSE;
  1087. }
  1088. if (CheckNextNBits(nArrayIndex, dwMask,
  1089. nAdditionalBlocksRequired, nBlocksFound))
  1090. {
  1091. // We were able to grow the entry.
  1092. SetNextNBits(nArrayIndex, dwMask, nAdditionalBlocksRequired);
  1093. pEntry->nBlocks = nBlocksRequired;
  1094. _HeaderInfo->NumUrlEntriesAlloced += nAdditionalBlocksRequired;
  1095. return TRUE;
  1096. }
  1097. else
  1098. // Couldn't grow the entry.
  1099. return FALSE;
  1100. }
  1101. }
  1102. LPFILEMAP_ENTRY MEMMAP_FILE::AllocateEntry(DWORD cbBytes)
  1103. /*++
  1104. Routine Description:
  1105. Member function that returns an free entry from the cache list. If
  1106. none is available free, it grows the map file, makes more free
  1107. entries.
  1108. Arguments:
  1109. DWORD cbBytes : Number of bytes requested
  1110. DWORD cbOffset: Offset from beginning of bit map where allocation is requested.
  1111. Return Value:
  1112. If NULL, GetStatus() will return actual error code.
  1113. --*/
  1114. {
  1115. LPFILEMAP_ENTRY NewEntry;
  1116. // Validate cbBytes
  1117. if (cbBytes > MAX_ENTRY_SIZE)
  1118. {
  1119. INET_ASSERT(FALSE);
  1120. return 0;
  1121. }
  1122. // Find and mark off a set of contiguous bits
  1123. // spanning the requested number of bytes.
  1124. DWORD nBlocksRequired = NUMBLOCKS(ROUNDUPBLOCKS(cbBytes));
  1125. DWORD FreeEntryIndex = GetAndSetNextFreeEntry(nBlocksRequired);
  1126. // Failed to find space.
  1127. if( FreeEntryIndex == 0xFFFFFFFF )
  1128. {
  1129. // Map file is full, grow it now.
  1130. _Status = GrowMapFile(cbBytes <= GlobalMapFileGrowSize ?
  1131. GlobalMapFileGrowSize : ROUNDUPTOPOWEROF2(cbBytes, ALLOC_PAGES * PAGE_SIZE) );
  1132. // Failed to grow map file.
  1133. if( _Status != ERROR_SUCCESS )
  1134. {
  1135. return NULL;
  1136. }
  1137. // Retry with enlarged map file.
  1138. FreeEntryIndex = GetAndSetNextFreeEntry(nBlocksRequired);
  1139. TcpsvcsDbgAssert( FreeEntryIndex != 0xFFFFFFFF );
  1140. // Failed to allocate bytes after enlarging map file.
  1141. if( FreeEntryIndex == 0xFFFFFFFF )
  1142. {
  1143. return NULL;
  1144. }
  1145. }
  1146. INET_ASSERT( (cbBytes < PAGE_SIZE)
  1147. || ( (cbBytes >= PAGE_SIZE) && !((_EntrySize * FreeEntryIndex) % PAGE_SIZE)) );
  1148. // Cast the memory.
  1149. NewEntry = (LPFILEMAP_ENTRY)
  1150. (_EntryArray + _EntrySize * FreeEntryIndex);
  1151. // Mark the allocated space.
  1152. #ifdef DBG
  1153. ResetEntryData(NewEntry, SIG_ALLOC, nBlocksRequired);
  1154. #else
  1155. NewEntry->dwSig = SIG_ALLOC;
  1156. #endif // DBG
  1157. // Set the number of blocks in the entry.
  1158. NewEntry->nBlocks = nBlocksRequired;
  1159. return NewEntry;
  1160. }
  1161. BOOL MEMMAP_FILE::FreeEntry(LPFILEMAP_ENTRY Entry)
  1162. /*++
  1163. This public member function frees up a file cache entry.
  1164. Arguments:
  1165. UrlEntry : pointer to the entry that being freed.
  1166. Return Value:
  1167. TRUE - if the entry is successfully removed from the cache.
  1168. FALSE - otherwise.
  1169. --*/
  1170. {
  1171. DWORD nIndex, nArrayIndex,
  1172. nOffset, nBlocks, BitMask;
  1173. LPDWORD BitMap;
  1174. //
  1175. // Validate the pointer passed in.
  1176. //
  1177. if( ((LPBYTE)Entry < _EntryArray)
  1178. || ((LPBYTE)Entry >=
  1179. (_EntryArray + _EntrySize *
  1180. _HeaderInfo->NumUrlInternalEntries) ) )
  1181. {
  1182. TcpsvcsDbgAssert(FALSE);
  1183. return FALSE;
  1184. }
  1185. // Compute and check offset (number of bytes from start).
  1186. nOffset = (DWORD) PtrDifference(Entry, _EntryArray);
  1187. if( nOffset % _EntrySize )
  1188. {
  1189. // Pointer does not point to a valid entry.
  1190. TcpsvcsDbgAssert(FALSE);
  1191. return FALSE;
  1192. }
  1193. nBlocks = Entry->nBlocks;
  1194. if (nBlocks > (MAX_ENTRY_SIZE / NORMAL_ENTRY_SIZE))
  1195. {
  1196. INET_ASSERT(FALSE);
  1197. return FALSE;
  1198. }
  1199. // Compute indicese
  1200. nIndex = nOffset / _EntrySize;
  1201. nArrayIndex = nIndex / NUM_BITS_IN_DWORD;
  1202. //
  1203. // Unmark the index bits in the map.
  1204. //
  1205. BitMap = &_HeaderInfo->AllocationBitMap[nArrayIndex];
  1206. BitMask = 0x1 << (nIndex % NUM_BITS_IN_DWORD);
  1207. for (DWORD i = 0; i < nBlocks; i++)
  1208. {
  1209. // Check we don't free unset bits
  1210. if (!(*BitMap & BitMask))
  1211. {
  1212. TcpsvcsDbgPrint(( DEBUG_ERRORS, "Attempted to free unset bits. Ignoring...\n"));
  1213. return FALSE;
  1214. }
  1215. *BitMap &= ~BitMask;
  1216. BitMask <<= 1;
  1217. if (BitMask == 0x0)
  1218. {
  1219. BitMask = 0x1;
  1220. BitMap = &_HeaderInfo->AllocationBitMap[++nArrayIndex];
  1221. }
  1222. }
  1223. // Mark the freed space.
  1224. ResetEntryData(Entry, SIG_FREE, nBlocks);
  1225. // Reduce the count of allocated entries.
  1226. TcpsvcsDbgAssert(_HeaderInfo->NumUrlEntriesAlloced > 0);
  1227. _HeaderInfo->NumUrlEntriesAlloced -= nBlocks;
  1228. return TRUE;
  1229. }
  1230. BOOL
  1231. MEMMAP_FILE::Reinitialize(void)
  1232. /*++
  1233. This member function reinitializes a cache index file
  1234. Arguments:
  1235. Return Value:
  1236. Windows error code
  1237. --*/
  1238. {
  1239. TcpsvcsDbgAssert( _FileHandle != NULL );
  1240. // Close view, mapping, and file.
  1241. CloseMapping();
  1242. BOOL BoolError, fReinited = FALSE;
  1243. DWORD FilePointer;
  1244. // If we're re-initialising, that means we're losing all our cached data.
  1245. // Time to delete all the old stuff
  1246. // But wait -- we only want to do this for the content cache, since we can regen
  1247. // the index from the cookies, and history stores all its info in index file
  1248. // We'll check for "content.ie5" in the path
  1249. if (StrStrI(_FullPathName, "content.ie5"))
  1250. {
  1251. DeleteCachedFilesInDir(_FullPathName);
  1252. }
  1253. SECURITY_ATTRIBUTES* psa = NULL;
  1254. if (!_PerUser)
  1255. {
  1256. psa = SHGetAllAccessSA();
  1257. }
  1258. if (_PerUser || psa)
  1259. {
  1260. // check for exclusive access, we do this by opening the
  1261. // file in exclsive mode, if we succeed we are the only one
  1262. _FileHandle = CreateFile
  1263. (
  1264. _FileName,
  1265. GENERIC_WRITE,
  1266. 0, // no read/write sharing
  1267. psa,
  1268. OPEN_ALWAYS,
  1269. FILE_ATTRIBUTE_NORMAL,
  1270. NULL
  1271. );
  1272. }
  1273. else
  1274. {
  1275. _FileHandle = INVALID_HANDLE_VALUE;
  1276. }
  1277. if (_FileHandle == INVALID_HANDLE_VALUE)
  1278. {
  1279. _FileHandle = NULL;
  1280. }
  1281. else
  1282. {
  1283. DWORD FilePointer = SetFilePointer
  1284. ( _FileHandle, GlobalMapFileGrowSize, NULL, FILE_BEGIN);
  1285. if( FilePointer != 0xFFFFFFFF)
  1286. {
  1287. if (SetEndOfFile (_FileHandle))
  1288. {
  1289. // Success!
  1290. _FileSize = GlobalMapFileGrowSize;
  1291. fReinited = TRUE;
  1292. }
  1293. else
  1294. {
  1295. TcpsvcsDbgPrint(( DEBUG_ERRORS, "SetEndOfFile failed: %u\n",
  1296. GetLastError()));
  1297. }
  1298. }
  1299. // Following will be done by RemapAddress calling CloseMapping
  1300. // CloseHandle (_FileHandle);
  1301. // _FileHandle = NULL
  1302. }
  1303. // Re-attach to the file.
  1304. _Status = RemapAddress();
  1305. if( _Status != ERROR_SUCCESS )
  1306. {
  1307. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  1308. "Reinitialize:Remap failed, %ld.\n",_Status));
  1309. TcpsvcsDbgAssert( FALSE );
  1310. goto Cleanup;
  1311. }
  1312. if (fReinited)
  1313. {
  1314. // if there is an exception due to bad sector, this will set
  1315. // _status to something other than ERROR_SUCCESS
  1316. if(!InitHeaderInfo())
  1317. goto Cleanup;
  1318. _NumBitMapDWords =
  1319. (_HeaderInfo->NumUrlInternalEntries + (NUM_BITS_IN_DWORD - 1)) /
  1320. NUM_BITS_IN_DWORD; // cell
  1321. }
  1322. Cleanup:
  1323. return fReinited;
  1324. }
  1325. BOOL
  1326. MEMMAP_FILE::InitHeaderInfo()
  1327. /*++
  1328. This member function intializes the memorymapped headerinfo
  1329. structure
  1330. Arguments:
  1331. Return Value:
  1332. None
  1333. --*/
  1334. {
  1335. //
  1336. // initialize file header.
  1337. //
  1338. BOOL fSuccess = TRUE;
  1339. __try {
  1340. TcpsvcsDbgAssert( _HeaderInfo != NULL );
  1341. memcpy(_HeaderInfo->FileSignature, CACHE_SIGNATURE, sizeof(CACHE_SIGNATURE));
  1342. _HeaderInfo->FileSize = _FileSize; // set file size in the memmap file.
  1343. _HeaderInfo->dwHashTableOffset = 0;
  1344. _HeaderInfo->CacheSize = (LONGLONG)0;
  1345. _HeaderInfo->CacheLimit = (LONGLONG)0;
  1346. _HeaderInfo->ExemptUsage = (LONGLONG)0;
  1347. _HeaderInfo->nDirCount = 0;
  1348. for (int i = 0; i < DEFAULT_MAX_DIRS; i++)
  1349. {
  1350. _HeaderInfo->DirArray[i].nFileCount = 0;
  1351. _HeaderInfo->DirArray[i].sDirName[0] = '\0';
  1352. }
  1353. _HeaderInfo->NumUrlInternalEntries =
  1354. ((_FileSize - HEADER_ENTRY_SIZE ) /
  1355. _EntrySize );
  1356. _HeaderInfo->NumUrlEntriesAlloced = 0;
  1357. memset( _HeaderInfo->AllocationBitMap, 0, sizeof(_HeaderInfo->AllocationBitMap) );
  1358. memset( _EntryArray, 0, (_FileSize - HEADER_ENTRY_SIZE) );
  1359. memset( _HeaderInfo->dwHeaderData, 0, sizeof(DWORD) * NUM_HEADER_DATA_DWORDS);
  1360. _Status = ERROR_SUCCESS;
  1361. }
  1362. __except(EXCEPTION_EXECUTE_HANDLER) {
  1363. _Status = ERROR_WRITE_FAULT;
  1364. fSuccess = FALSE;
  1365. }
  1366. ENDEXCEPT
  1367. return (fSuccess);
  1368. }
  1369. LPFILEMAP_ENTRY MEMMAP_FILE::FindNextEntry (DWORD* pdwEnum, DWORD dwFilter, GROUPID GroupId, DWORD dwMatch)
  1370. {
  1371. while (1)
  1372. {
  1373. // Get the next item in the hash table.
  1374. HASH_ITEM *pItem = HashGetNextItem (this, (LPBYTE)_BaseAddr, pdwEnum, 0);
  1375. if (!pItem)
  1376. return NULL;
  1377. // continue if search entry within group but hash bit says no group
  1378. // (may avoid unnecessary page hit by pulling non-relevent pEntry)
  1379. if( GroupId && !pItem->HasGroup() )
  1380. continue;
  1381. // Get the entry from the item.
  1382. URL_FILEMAP_ENTRY* pEntry = ValidateUrlOffset (pItem->dwOffset);
  1383. if (!pEntry)
  1384. {
  1385. pItem->MarkFree();
  1386. continue;
  1387. }
  1388. // No filter - continue enum until ERROR_NO_MORE_ITEMS.
  1389. if (!dwFilter)
  1390. continue;
  1391. // IDENTITY_CACHE_ENTRY is an identity-specific entry.
  1392. // We don't want these to be shown inappropriately to a client.
  1393. // We may want to be able to display all of these for debug, though.
  1394. if ((pEntry->CacheEntryType & IDENTITY_CACHE_ENTRY)
  1395. && ((pEntry->dwIdentity != dwMatch)
  1396. || (!pEntry->dwIdentity)))
  1397. continue;
  1398. DWORD cet = pEntry->CacheEntryType & ~IDENTITY_CACHE_ENTRY;
  1399. // Temporary hack to always show 1.1 entries
  1400. // until we have a better way of dealing with them.
  1401. dwFilter |= INCLUDE_BY_DEFAULT_CACHE_ENTRY;
  1402. // Continue enum if no match on cache entry type.
  1403. if ((dwFilter & cet) != cet)
  1404. continue;
  1405. // Continue enum if no match on group.
  1406. if (GroupId )
  1407. {
  1408. if( pItem->HasMultiGroup() )
  1409. {
  1410. // need to search the list
  1411. LIST_GROUP_ENTRY* pListGroup = NULL;
  1412. pListGroup = ValidateListGroupOffset(pEntry->dwGroupOffset);
  1413. if( !pListGroup )
  1414. continue;
  1415. BOOL fFoundOnList = FALSE;
  1416. while( pListGroup && pListGroup->dwGroupOffset )
  1417. {
  1418. GROUP_ENTRY* pGroup = NULL;
  1419. pGroup = ValidateGroupOffset(
  1420. pListGroup->dwGroupOffset, pItem);
  1421. if( !pGroup )
  1422. {
  1423. break;
  1424. }
  1425. if( GroupId == pGroup->gid )
  1426. {
  1427. fFoundOnList = TRUE;
  1428. break;
  1429. }
  1430. if( !pListGroup->dwNext )
  1431. {
  1432. break;
  1433. }
  1434. // next group on list
  1435. pListGroup = ValidateListGroupOffset(pListGroup->dwNext);
  1436. }
  1437. if( !fFoundOnList )
  1438. continue;
  1439. }
  1440. else if( GroupId !=
  1441. ((GROUP_ENTRY*)( (LPBYTE)_BaseAddr +
  1442. pEntry->dwGroupOffset))->gid )
  1443. {
  1444. continue;
  1445. }
  1446. }
  1447. return (LPFILEMAP_ENTRY) (((LPBYTE)_BaseAddr) + pItem->dwOffset);
  1448. }
  1449. }
  1450. BOOL MEMMAP_FILE::IsBadOffset (DWORD dwOffset)
  1451. {
  1452. ASSERT_ISPOWEROF2 (_EntrySize);
  1453. return (dwOffset == 0
  1454. || (dwOffset & (_EntrySize-1))
  1455. || (dwOffset >= _FileSize));
  1456. return FALSE;
  1457. }
  1458. BOOL MEMMAP_FILE::IsBadGroupOffset (DWORD dwOffset)
  1459. {
  1460. return (dwOffset == 0 || (dwOffset >= _FileSize));
  1461. return FALSE;
  1462. }
  1463. GROUP_ENTRY* MEMMAP_FILE::ValidateGroupOffset (DWORD dwOffset, HASH_ITEM* hItem)
  1464. {
  1465. GROUP_ENTRY *pEntry = NULL;
  1466. // if hash item is available, check the group bit first.
  1467. if( hItem && !hItem->HasGroup())
  1468. {
  1469. return NULL;
  1470. }
  1471. // check the offset
  1472. if (IsBadGroupOffset (dwOffset))
  1473. {
  1474. INET_ASSERT (FALSE);
  1475. return NULL;
  1476. }
  1477. //
  1478. // Validate page signature.
  1479. // since we know all the allocated page are aligned with
  1480. // 4K boundary, so from the offset, we can get the
  1481. // the offset of this page by:
  1482. // pageOffset = Offset - Offset(mod)4K
  1483. //
  1484. DWORD dwOffsetInPage = dwOffset & 0x00000FFF;
  1485. FILEMAP_ENTRY* pFM = (FILEMAP_ENTRY*)
  1486. ( (LPBYTE)_BaseAddr + dwOffset - dwOffsetInPage );
  1487. // Get the Group.
  1488. if( pFM->dwSig == SIG_ALLOC && pFM->nBlocks )
  1489. {
  1490. pEntry = (GROUP_ENTRY *) ((LPBYTE) _BaseAddr + dwOffset);
  1491. }
  1492. return pEntry;
  1493. }
  1494. URL_FILEMAP_ENTRY* MEMMAP_FILE::ValidateUrlOffset (DWORD dwOffset)
  1495. {
  1496. // Validate offset.
  1497. if (IsBadOffset (dwOffset))
  1498. {
  1499. INET_ASSERT (FALSE);
  1500. return NULL;
  1501. }
  1502. // Validate signature.
  1503. URL_FILEMAP_ENTRY *pEntry =
  1504. (URL_FILEMAP_ENTRY *) ((LPBYTE) _BaseAddr + dwOffset);
  1505. if (pEntry->dwSig != SIG_URL)
  1506. {
  1507. //INET_ASSERT (FALSE); // commented out for RAID item 33684
  1508. return NULL;
  1509. }
  1510. // TODO: validate entry offsets, string terminations etc.
  1511. return pEntry;
  1512. }
  1513. LIST_GROUP_ENTRY* MEMMAP_FILE::ValidateListGroupOffset (DWORD dwOffset)
  1514. {
  1515. LIST_GROUP_ENTRY *pEntry = NULL;
  1516. // Validate offset.
  1517. if (IsBadGroupOffset (dwOffset))
  1518. {
  1519. INET_ASSERT (FALSE);
  1520. return NULL ;
  1521. }
  1522. //
  1523. // Validate page signature.
  1524. // since we know all the allocated page are aligned with
  1525. // 4K boundary, so from the offset, we can get the
  1526. // the offset of this page by:
  1527. // pageOffset = Offset - Offset(mod)4K
  1528. //
  1529. DWORD dwOffsetInPage = dwOffset & 0x00000FFF;
  1530. FILEMAP_ENTRY* pFM = (FILEMAP_ENTRY*)
  1531. ( (LPBYTE)_BaseAddr + dwOffset - dwOffsetInPage );
  1532. if( pFM->dwSig == SIG_ALLOC && pFM->nBlocks )
  1533. {
  1534. pEntry = (LIST_GROUP_ENTRY*) ((LPBYTE) _BaseAddr + dwOffset);
  1535. }
  1536. return pEntry;
  1537. }