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.

1524 lines
46 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name: filemgr.cxx
  4. Abstract:
  5. Manages cache file & directory creation/deletion.
  6. Author:
  7. Adriaan Canter (adriaanc) 04-02-97
  8. Modifications:
  9. Ahsan Kabir (akabir) 25-Sept-97 made minor alterations.
  10. --*/
  11. #include <cache.hxx>
  12. #define WWW_DOT "www."
  13. #define MAP_KEY_TO_PATH 0
  14. #define MAP_PATH_TO_KEY 1
  15. //
  16. //==================== CFileMgr Public Functions =============================
  17. //
  18. /*-----------------------------------------------------------------------------
  19. CFileMgr::CFileMgr
  20. ----------------------------------------------------------------------------*/
  21. CFileMgr::CFileMgr(MEMMAP_FILE* mmFile, DWORD dwOptions) : _mmFile(mmFile), _dwOptions(dwOptions)
  22. {
  23. INET_ASSERT(_mmFile);
  24. // GetFullPathNameLen includes trailing backslash.
  25. _cbBasePathLen = _mmFile->GetFullPathNameLen();
  26. }
  27. /*-----------------------------------------------------------------------------
  28. CFileMgr::~CFileMgr
  29. ----------------------------------------------------------------------------*/
  30. CFileMgr::~CFileMgr()
  31. {}
  32. /*-----------------------------------------------------------------------------
  33. virtual CFileMgr::Init
  34. ----------------------------------------------------------------------------*/
  35. BOOL CFileMgr::Init()
  36. {
  37. return TRUE;
  38. }
  39. /*-----------------------------------------------------------------------------
  40. virtual GetDirLen
  41. Returns length of cache dir path.
  42. ----------------------------------------------------------------------------*/
  43. DWORD CFileMgr::GetDirLen(DWORD nKey)
  44. {
  45. return _cbBasePathLen;
  46. }
  47. /*-----------------------------------------------------------------------------
  48. virtual CFileMgr::CreateUniqueFile
  49. Generates cache files.
  50. ----------------------------------------------------------------------------*/
  51. DWORD CFileMgr::CreateUniqueFile(LPCSTR szUrl, LPTSTR szFileName,
  52. LPTSTR szFileExtension, HANDLE *phfHandle, BOOL fCreatePerUser)
  53. {
  54. return CreateUniqueFile((LPCSTR) szUrl, (LPTSTR) _mmFile->GetFullPathName(),
  55. (LPTSTR) szFileName, (LPTSTR) szFileExtension, (HANDLE*) phfHandle, fCreatePerUser);
  56. }
  57. /*-----------------------------------------------------------------------------
  58. virtual CFileMgr::NotifyCommit
  59. No-op.
  60. ----------------------------------------------------------------------------*/
  61. BOOL CFileMgr::NotifyCommit(DWORD nDirIndex)
  62. {
  63. return TRUE;
  64. }
  65. /*-----------------------------------------------------------------------------
  66. CFileMgr::DeleteCache
  67. ----------------------------------------------------------------------------*/
  68. BOOL CFileMgr::DeleteCache(LPSTR szRoot)
  69. {
  70. BOOL fHasCacheVu = IsValidCacheSubDir(szRoot);
  71. if ( fHasCacheVu)
  72. DisableCacheVu(szRoot);
  73. if (DeleteCachedFilesInDir(szRoot) == ERROR_SUCCESS)
  74. {
  75. SetFileAttributes(szRoot, FILE_ATTRIBUTE_DIRECTORY);
  76. RemoveDirectory(szRoot);
  77. }
  78. if( fHasCacheVu)
  79. EnableCacheVu( szRoot);
  80. return TRUE;
  81. }
  82. /*-----------------------------------------------------------------------------
  83. CFileMgr::Cleanup
  84. ----------------------------------------------------------------------------*/
  85. BOOL CFileMgr::Cleanup()
  86. {
  87. return TRUE;
  88. }
  89. /*-----------------------------------------------------------------------------
  90. virtual CFileMgr::GetDirIndex
  91. ----------------------------------------------------------------------------*/
  92. BOOL CFileMgr::GetDirIndex(LPSTR szFilePath, LPDWORD pnIndex)
  93. {
  94. *pnIndex = NOT_A_CACHE_SUBDIRECTORY;
  95. return TRUE;
  96. }
  97. /*-----------------------------------------------------------------------------
  98. virtual CFileMgr::GetFilePathFromEntry
  99. Retrieves the full path to the cache subdirectory for a cache entry.
  100. Maps the directory index from the URL_FILEMAP_ENTRY pointer passed in
  101. to a string containing the full path.
  102. ----------------------------------------------------------------------------*/
  103. BOOL CFileMgr::GetFilePathFromEntry(URL_FILEMAP_ENTRY *pEntry,
  104. LPSTR szSubDirPath, LPDWORD pcb)
  105. {
  106. INET_ASSERT(pEntry && szSubDirPath && pcb && *pcb);
  107. // "[email protected]"
  108. LPTSTR szFile = (LPTSTR) OFFSET_TO_POINTER(pEntry, pEntry->InternalFileNameOffset);
  109. // Lengths of path and file.
  110. DWORD cbFile = strlen(szFile);
  111. DWORD cbPath = _mmFile->GetFullPathNameLen();
  112. // Don't overflow output buffer.
  113. DWORD cbSubDirPath = cbPath + cbFile;
  114. if (cbSubDirPath + 1 > *pcb)
  115. {
  116. INET_ASSERT(FALSE);
  117. return FALSE;
  118. }
  119. // "C:\Windows\Profiles\anyuser\Cookies\"
  120. memcpy(szSubDirPath, _mmFile->GetFullPathName(), cbPath);
  121. // "C:\Windows\Profiles\anyuser\Cookies\[email protected]"
  122. memcpy(szSubDirPath + cbPath, szFile, cbFile + 1);
  123. *pcb = cbSubDirPath;
  124. return TRUE;
  125. }
  126. /*-----------------------------------------------------------------------------
  127. virtual CFileMgr::DeleteOneCachedFile
  128. Deletes a single cache file given the absolute path.
  129. ----------------------------------------------------------------------------*/
  130. BOOL CFileMgr::DeleteOneCachedFile(LPSTR lpszFileName,
  131. DWORD dostEntry, DWORD nIndex)
  132. {
  133. return ::DeleteOneCachedFile(lpszFileName, dostEntry);
  134. }
  135. /*-----------------------------------------------------------------------------
  136. virtual BOOL CreateDirWithSecureName( LPSTR);
  137. Creates a cache directory with a given name to allow existing directories
  138. to be copied into another cache file. Just the eight letters of the new
  139. directory are given.
  140. ----------------------------------------------------------------------------*/
  141. BOOL CFileMgr::CreateDirWithSecureName( LPSTR szDirName)
  142. {
  143. return _mmFile->CreateDirWithSecureName( szDirName);
  144. }
  145. //
  146. //================== CFileMgr Protected Functions =============================
  147. //
  148. /*-----------------------------------------------------------------------------
  149. CFileMgr::GetStoreDirectory
  150. Returns "%windir%\web\" - ie "C:\Windows\Web\" and length. There
  151. is currently only ONE store directory and this is it.
  152. ----------------------------------------------------------------------------*/
  153. BOOL CFileMgr::GetStoreDirectory(LPSTR szPath, LPDWORD pcbPath)
  154. {
  155. DWORD cb;
  156. // Hardwired to "%windir%\Web\"
  157. if ((cb = GetWindowsDirectory(szPath, MAX_PATH)) && cb<=MAX_PATH)
  158. {
  159. AppendSlashIfNecessary(szPath, &cb);
  160. memcpy(szPath + cb, WEBDIR_STRING, sizeof(WEBDIR_STRING));
  161. cb += sizeof(WEBDIR_STRING) - 1;
  162. *pcbPath = cb;
  163. return TRUE;
  164. }
  165. INET_ASSERT(FALSE);
  166. return FALSE;
  167. }
  168. /*-----------------------------------------------------------------------------
  169. CFileMgr::MapStoreKey
  170. Maps path to storage directory key (stored in the FILEMAP_ENTRY::DirIndex)
  171. or storage directory key to path (ie C:\Windows\Web\). There is currently
  172. only one key and it is INSTALLED_DIRECTORY_KEY. Mapping depends on dwFlag.
  173. ----------------------------------------------------------------------------*/
  174. BOOL CFileMgr::MapStoreKey(LPSTR szPath, LPDWORD pcbPath,
  175. LPDWORD dwKey, DWORD dwFlag)
  176. {
  177. DWORD cb;
  178. BOOL fReturn = FALSE;
  179. CHAR szStoreDir[MAX_PATH];
  180. // Must be able to get store dir in any case.
  181. if (GetStoreDirectory(szStoreDir, &cb))
  182. {
  183. // Mapping a path to a key requested.
  184. if (dwFlag == MAP_PATH_TO_KEY)
  185. {
  186. // Path matches?
  187. if ((*pcbPath == cb)
  188. && !strnicmp(szStoreDir, szPath, cb))
  189. {
  190. // We only map one directory for now.
  191. *dwKey = INSTALLED_DIRECTORY_KEY;
  192. fReturn = TRUE;
  193. }
  194. }
  195. // Mapping a key to a path requested.
  196. else if (dwFlag == MAP_KEY_TO_PATH)
  197. {
  198. if (*dwKey == INSTALLED_DIRECTORY_KEY)
  199. {
  200. memcpy(szPath, szStoreDir, cb+1);
  201. *pcbPath = cb;
  202. fReturn = TRUE;
  203. }
  204. }
  205. }
  206. //INET_ASSERT(fReturn);
  207. return fReturn;
  208. }
  209. /*-----------------------------------------------------------------------------
  210. CreateUniqueFile
  211. Routine Description:
  212. Arguments:
  213. UrlName : pointer to url name.
  214. Path : pointer to cache path.
  215. FileName : pointer to a buffer that receives the full path name of the
  216. newly created file.
  217. Extension : if specified the extension is used to make random file.
  218. Return Value:
  219. Windows Error Code.
  220. ----------------------------------------------------------------------------*/
  221. DWORD CFileMgr::CreateUniqueFile(LPCSTR UrlName, LPTSTR Path,
  222. LPTSTR FileName, LPTSTR Extension,
  223. HANDLE *phfHandle, BOOL fCreatePerUser)
  224. {
  225. DWORD cbPath, cbName, cbFull;
  226. cbPath = strlen(Path);
  227. DWORD Error=ERROR_SUCCESS, len, lenExt=0;
  228. TCHAR RandomFileName[MAX_PATH];
  229. TCHAR FullFileName[MAX_PATH];
  230. HANDLE FileHandle;
  231. DWORD dwCollision = 0, dwTotalCollissionCount;
  232. char szHost[MAX_PATH], szExtraInfo[MAX_PATH];
  233. URL_COMPONENTS sUrl;
  234. char *pszUrlPath = (char *) ALLOCATE_FIXED_MEMORY(INTERNET_MAX_PATH_LENGTH);
  235. LPTSTR FileNamePtr = FileName, lpT;
  236. BOOL fUseFileName = FALSE, fPrettyName = FALSE;
  237. DWORD cbFileName;
  238. CHAR szExt[MAX_PATH];
  239. *szExt = '\0';
  240. if (phfHandle)
  241. *phfHandle = INVALID_HANDLE_VALUE;
  242. if (pszUrlPath == NULL)
  243. {
  244. Error = ERROR_NOT_ENOUGH_MEMORY;
  245. goto Cleanup;
  246. }
  247. // If a filename has been passed in attempt to use it.
  248. if (FileName[0] != '\0')
  249. {
  250. // Various checks to determine validity of name.
  251. // First strip any trailing whitespace.
  252. cbFileName = strlen(FileName);
  253. StripTrailingWhiteSpace(FileName, &cbFileName);
  254. // Check length.
  255. if (cbFileName < MAX_PATH)
  256. {
  257. // '.' and '..' are illegal.
  258. if (memcmp(FileName, ".", sizeof("."))
  259. && memcmp(FileName, "..", sizeof("..")))
  260. {
  261. // slashes and backslashes are illegal.
  262. LPTSTR ptr = FileName;
  263. while (*ptr != '\0')
  264. {
  265. if (IsDBCSLeadByte(*ptr))
  266. ++ptr;
  267. else
  268. if (*ptr == '\\' || *ptr == '/')
  269. break;
  270. ptr++;
  271. }
  272. // Filename has no slashes in it.
  273. if (!*ptr)
  274. {
  275. // Preliminary judgment. Creating
  276. // this file could possibly fail,
  277. // depending on further tests.
  278. fUseFileName = TRUE;
  279. }
  280. }
  281. }
  282. }
  283. // Preliminary checks indicate valid filename.
  284. if (fUseFileName)
  285. {
  286. // Attempt to parse a file extension.
  287. CHAR* pExt = StrChr(FileName, '.');
  288. // Found a file extension delimiter.
  289. if (pExt)
  290. {
  291. // '.' but no extension (eg "foo.")
  292. if (*(pExt + 1) == '\0')
  293. {
  294. *pExt = '\0';
  295. len = cbFileName - 1;
  296. }
  297. // '.' at beginning (eg ".foo") Valid file, no extension.
  298. else if (pExt == FileName)
  299. {
  300. len = cbFileName;
  301. }
  302. // Common case (eg foo.bar)
  303. else
  304. {
  305. // Separate out the file extension w/o '.'
  306. lenExt = (DWORD) (cbFileName - (pExt - FileName) - 1); // 64BIT
  307. memcpy(szExt, pExt+1, lenExt + 1);
  308. // Filename without extension.
  309. *pExt = '\0';
  310. len = (DWORD) (pExt - FileName); // 64BIT
  311. }
  312. }
  313. // No file extension found
  314. else
  315. {
  316. len = cbFileName;
  317. }
  318. fPrettyName = TRUE;
  319. goto have_file_name;
  320. }
  321. // No or bad filename passed in.
  322. else
  323. {
  324. // Copy over any extension passed in,
  325. // limiting the length as necessary.
  326. if (Extension)
  327. {
  328. lenExt = strlen(Extension);
  329. if (lenExt >= MAX_PATH)
  330. {
  331. lenExt = MAX_PATH - 1;
  332. }
  333. memcpy(szExt, Extension, lenExt);
  334. szExt[lenExt] = '\0';
  335. }
  336. else
  337. {
  338. *szExt = '\0';
  339. lenExt = 3;
  340. }
  341. }
  342. memset(&sUrl, 0, sizeof(sUrl));
  343. sUrl.dwStructSize = sizeof(sUrl);
  344. sUrl.lpszHostName = szHost;
  345. sUrl.dwHostNameLength = sizeof(szHost);
  346. sUrl.lpszUrlPath = pszUrlPath;
  347. sUrl.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
  348. sUrl.lpszExtraInfo = szExtraInfo;
  349. sUrl.dwExtraInfoLength = sizeof(szExtraInfo);
  350. if (InternetCrackUrl(UrlName, lstrlen(UrlName), 0, &sUrl)) {
  351. fPrettyName = TRUE;
  352. if ((sUrl.dwUrlPathLength == 1) && (pszUrlPath[0] == '/')) {
  353. FileNamePtr = szHost;
  354. len = sUrl.dwHostNameLength;
  355. // strip out www., this info is redundant
  356. if (!strnicmp(FileNamePtr, WWW_DOT, sizeof(WWW_DOT)-1)) {
  357. len -= (sizeof(WWW_DOT)-1);
  358. // copy the NULL terminator too
  359. memmove(FileNamePtr, FileNamePtr+sizeof(WWW_DOT)-1,len+1);
  360. }
  361. }
  362. else {
  363. FileNamePtr = pszUrlPath;
  364. len = sUrl.dwUrlPathLength;
  365. // if there is a terminating slash let us fix it.
  366. // len-1 wont' break because we know the url is more than 1 char
  367. // Above assumption not valid.
  368. if (len && (FileNamePtr[len-1] == '/'))
  369. {
  370. FileNamePtr[len-1] = 0;
  371. --len;
  372. }
  373. // get the tail
  374. if (lpT=StrRChrA(FileNamePtr, FileNamePtr+len-1, '/'))
  375. {
  376. ++lpT;
  377. len = len - (DWORD)PtrDifference(lpT, FileNamePtr);
  378. //
  379. // truncate the FileNamePtr if it is too long -
  380. // the "fudge-factor" number is to allow room for stuff like "[%d]"
  381. // in the URL -- this number doesn't have to be accurate since
  382. // the worst-case scenario is us using a random (ugly) filename.
  383. //
  384. unsigned int newlen;
  385. if(GlobalTruncateFileName)
  386. newlen = /*excel limit*/218 - (cbPath + lenExt + 2 + /*fudge-factor*/5);
  387. else
  388. newlen = MAX_PATH - (cbPath + lenExt + 2 + /*fudge-factor*/5);
  389. if ((newlen > 2) && (newlen < len))
  390. {
  391. // For UTF-8, we don't want to chop in the middle of a %XX
  392. if (lpT[newlen - 2] == '%')
  393. newlen -= 2;
  394. else if (lpT[newlen - 1] == '%')
  395. newlen -= 1;
  396. len = newlen;
  397. lpT[len] = '\0';
  398. }
  399. // copy the NULL terminator as well
  400. memmove(FileNamePtr, lpT, len+1);
  401. }
  402. // Special hack for cookies: Ensure that the username is
  403. // prepended on to the filename. The preceding filename
  404. // generation code does not generate this for cookies
  405. // which specify paths in addition to domains.
  406. if (!memcmp(UrlName, COOKIE_PREFIX, sizeof(COOKIE_PREFIX) - 1))
  407. {
  408. // This is a cookie url of the form Cookie:username@domain/path
  409. if (GetWininetUserName())
  410. {
  411. DWORD cb = vdwCurrentUserLen;
  412. if (len + cb + 1 < MAX_PATH)
  413. {
  414. if (memcmp(FileNamePtr, vszCurrentUser, cb)
  415. || FileNamePtr[cb] != '@'
  416. || FileNamePtr[cb+1] == '\0')
  417. {
  418. memmove(FileNamePtr + cb + 1, FileNamePtr, len+1);
  419. FileNamePtr[cb] = '@';
  420. memcpy(FileNamePtr, vszCurrentUser, cb);
  421. len += cb + 1;
  422. }
  423. }
  424. }
  425. }
  426. }
  427. if (lpT=StrRChrA(FileNamePtr, FileNamePtr+len-1, '.'))
  428. {
  429. *lpT = 0;
  430. len = (DWORD) PtrDifference(lpT, FileNamePtr);
  431. }
  432. // convert all invalid char (including '%') to '_'
  433. for(lpT = FileNamePtr; *lpT; ++lpT)
  434. {
  435. if (IsDBCSLeadByte(*lpT))
  436. ++lpT;
  437. else if ((strchr(vszInvalidFilenameChars, *lpT)))
  438. *lpT = '_';
  439. }
  440. if ((cbPath+len+lenExt+2) > MAX_PATH) {
  441. fPrettyName = FALSE;
  442. }
  443. }
  444. else {
  445. fPrettyName = FALSE;
  446. }
  447. have_file_name:
  448. for(dwTotalCollissionCount = 0;
  449. dwTotalCollissionCount < MAX_COLLISSION_ATTEMPTS;
  450. dwTotalCollissionCount++) {
  451. //
  452. // make a random file name.
  453. //
  454. if (!fPrettyName)
  455. {
  456. // If fUseFileName is TRUE, it means we've attempted to create
  457. // a file using the filename passed in and failed. We still want
  458. // to create a cache file, but since the extension parsed from the
  459. // filename is also suspect, we want to create a cache filename
  460. // without any passed in extension, or NULL.
  461. if (fUseFileName)
  462. {
  463. if (Extension)
  464. {
  465. lenExt = strlen(Extension);
  466. memcpy(szExt, Extension, lenExt+1);
  467. }
  468. else
  469. {
  470. lenExt = 0;
  471. *szExt = '\0';
  472. }
  473. }
  474. Error = MakeRandomFileName(UrlName, RandomFileName, szExt);
  475. }
  476. else {
  477. DWORD digit;
  478. DWORD cb = strlen(FileNamePtr);
  479. memcpy(RandomFileName, FileNamePtr, cb+1);
  480. lpT = RandomFileName+len;
  481. // Always decorate the cache file name with [1-99]
  482. // We use square brackets instead of parens because
  483. // NT cmd shell barfs on parens.
  484. if (++dwCollision > 99)
  485. {
  486. fPrettyName = FALSE;
  487. continue;
  488. }
  489. #ifndef UNIX
  490. if (fCreatePerUser && GlobalIdentity)
  491. {
  492. lpT += wsprintf (lpT, "[%d][%d]", GlobalIdentity, dwCollision);
  493. }
  494. else
  495. {
  496. lpT += wsprintf (lpT, "[%d]", dwCollision);
  497. }
  498. #else
  499. /* Square brackets cause problems on UNIX */
  500. lpT += wsprintf (lpT, "(%d)", dwCollision);
  501. #endif /* UNIX */
  502. if (*szExt)
  503. {
  504. *lpT++ = '.';
  505. memcpy(lpT, szExt, lenExt + 1);
  506. }
  507. Error = ERROR_SUCCESS;
  508. }
  509. if (Error != ERROR_SUCCESS) {
  510. INET_ASSERT(FALSE);
  511. goto Cleanup;
  512. }
  513. cbName = strlen(RandomFileName);
  514. cbFull = cbPath + cbName + 1;
  515. if (cbFull > MAX_PATH)
  516. {
  517. INET_ASSERT(FALSE);
  518. Error = ERROR_FILENAME_EXCED_RANGE;
  519. goto Cleanup;
  520. }
  521. #ifndef UNIX
  522. // Hack for special DOS filenames:
  523. // aux.*, com[0-9].*, con.*, lpt[0-9].*,
  524. // nul.* and prn.* on non-NT platforms.
  525. if (!IsPlatformWinNT())
  526. {
  527. DWORD cbMajor = cbName - lenExt;
  528. if (cbMajor == 4 || cbMajor == 5)
  529. {
  530. switch(tolower(*RandomFileName))
  531. {
  532. // Test for aux.*
  533. case 'a':
  534. if (!strnicmp(RandomFileName + 1, "ux.", 3))
  535. {
  536. continue;
  537. }
  538. break;
  539. // Test for com[0-9].* and con.*
  540. case 'c':
  541. if (tolower(RandomFileName[1]) == 'o')
  542. {
  543. CHAR c = tolower(RandomFileName[2]);
  544. if (c == 'm')
  545. {
  546. if (isdigit(RandomFileName[3])
  547. && RandomFileName[4] == '.')
  548. {
  549. continue;
  550. }
  551. }
  552. else if (c == 'n')
  553. {
  554. if (RandomFileName[3] == '.')
  555. {
  556. continue;
  557. }
  558. }
  559. }
  560. break;
  561. // Test for lpt[0-9].*
  562. case 'l':
  563. {
  564. if (!strnicmp(RandomFileName + 1, "pt", 2)
  565. && isdigit(RandomFileName[3])
  566. && RandomFileName[4] == '.')
  567. {
  568. continue;
  569. }
  570. break;
  571. }
  572. // Test for nul.*
  573. case 'n':
  574. {
  575. if (!strnicmp(RandomFileName + 1, "ul.", 3))
  576. {
  577. continue;
  578. }
  579. break;
  580. }
  581. // Test for prn.*
  582. case 'p':
  583. {
  584. if (!strnicmp(RandomFileName + 1, "rn.", 3))
  585. {
  586. continue;
  587. }
  588. break;
  589. }
  590. }
  591. }
  592. }
  593. #endif /* !UNIX */
  594. // Make full path name.
  595. memcpy(FullFileName, Path, cbPath);
  596. memcpy(FullFileName + cbPath, RandomFileName, cbName + 1);
  597. // Check if this file exists.
  598. if (GetFileAttributes(FullFileName)!=0xffffffff)
  599. {
  600. // A file or dir by this name exists.
  601. // This will also take care of special DOS filenames
  602. // on NT, which return !0xffffffff.
  603. continue;
  604. }
  605. FileHandle = CreateFile(
  606. FullFileName,
  607. GENERIC_WRITE,
  608. FILE_SHARE_READ | FILE_SHARE_WRITE,
  609. NULL,
  610. CREATE_NEW,
  611. FILE_ATTRIBUTE_NORMAL,
  612. NULL );
  613. if( FileHandle != INVALID_HANDLE_VALUE )
  614. {
  615. // successfully create a new file either return handle or close it and return.
  616. if ( phfHandle )
  617. *phfHandle = FileHandle;
  618. else
  619. CloseHandle( FileHandle );
  620. break;
  621. }
  622. else
  623. {
  624. // Couldn't create the file. This is possibly due to the file
  625. // already existing or to the fact that the directory was deleted.
  626. // Check for the existance of the directory:
  627. if (GetFileAttributes(Path) == 0xffffffff)
  628. {
  629. // Directory was deleted. Create one and then
  630. // create the file.
  631. if (CreateDirectory(Path, NULL))
  632. {
  633. // Set system attribute.
  634. SetFileAttributes(Path, FILE_ATTRIBUTE_SYSTEM);
  635. // Enable cachevu in this directory
  636. if (!(GetOptions() & INTERNET_CACHE_CONTAINER_NODESKTOPINIT))
  637. EnableCacheVu(Path);
  638. FileHandle = CreateFile(
  639. FullFileName,
  640. GENERIC_WRITE,
  641. FILE_SHARE_READ | FILE_SHARE_WRITE,
  642. NULL,
  643. CREATE_NEW,
  644. FILE_ATTRIBUTE_NORMAL,
  645. NULL );
  646. // We just created the directory and the
  647. // child file, so the file handle should
  648. // be valid.
  649. if( FileHandle != INVALID_HANDLE_VALUE )
  650. {
  651. // successfully create a new file either return handle or close it and return.
  652. if ( phfHandle )
  653. *phfHandle = FileHandle;
  654. else
  655. CloseHandle( FileHandle );
  656. break;
  657. }
  658. }
  659. }
  660. }
  661. Error = GetLastError();
  662. if( Error != ERROR_FILE_EXISTS )
  663. {
  664. if (!fPrettyName)
  665. {
  666. INET_ASSERT(FALSE);
  667. goto Cleanup;
  668. }
  669. else
  670. {
  671. fPrettyName = FALSE;
  672. Error = ERROR_SUCCESS;
  673. }
  674. }
  675. else {
  676. // We found that the file exists
  677. // if it is zero size, let us just use it.
  678. // this in itself is an unlikely occurrence
  679. // but we any way try to work around the IBM virus software
  680. // ACHTUNG!!! this is a special hack for IBM antivirus software
  681. FileHandle = CreateFile(
  682. FullFileName,
  683. GENERIC_WRITE,
  684. FILE_SHARE_READ | FILE_SHARE_WRITE,
  685. NULL,
  686. OPEN_EXISTING,
  687. FILE_ATTRIBUTE_NORMAL,
  688. NULL );
  689. if (FileHandle != INVALID_HANDLE_VALUE) {
  690. // this looks usable
  691. if (GetFileSize(FileHandle, NULL) == 0)
  692. {
  693. if (phfHandle)
  694. *phfHandle = FileHandle;
  695. else
  696. CloseHandle( FileHandle );
  697. break;
  698. }
  699. CloseHandle( FileHandle );
  700. INET_ASSERT(FALSE);
  701. }
  702. Error = ERROR_DISK_FULL;
  703. goto Cleanup;
  704. }
  705. //
  706. // try another random file.
  707. //
  708. } // end of the for loop
  709. if (dwTotalCollissionCount < MAX_COLLISSION_ATTEMPTS) {
  710. memcpy(FileName, FullFileName, cbFull);
  711. Error = ERROR_SUCCESS;
  712. }
  713. else {
  714. INET_ASSERT(FALSE);
  715. Error = ERROR_DISK_OPERATION_FAILED;
  716. }
  717. Cleanup:
  718. if (pszUrlPath)
  719. FREE_MEMORY(pszUrlPath);
  720. return Error;
  721. }
  722. /*-----------------------------------------------------------------------------
  723. MakeRandomFileName
  724. Routine Description:
  725. Creates a random 8.3 file name. The format of the name will be as
  726. below:
  727. ca(0-99999).(0-999)
  728. Ex ca19200.340
  729. Ex ca19354.tmp - if an extension (tmp) is specified.
  730. Arguments:
  731. UrlName : pointer to an URL string
  732. FileName : pointer to a string buffer where the random file name is
  733. returned. The buffer length must be atleast 8+3+1+1= 13 wchars.
  734. Extension : pointer to an extension string. if this is non-NULL, then
  735. the specified extension is used otherwise random extension as
  736. explained above is used.
  737. Return Value:
  738. none.
  739. ----------------------------------------------------------------------------*/
  740. DWORD CFileMgr::MakeRandomFileName(LPCSTR UrlName,
  741. LPTSTR FileName, LPTSTR Extension)
  742. {
  743. DWORD RandNum;
  744. LPTSTR FileNamePtr = FileName;
  745. static Counter;
  746. DWORD i;
  747. DWORD cbExtension = 0;
  748. if (Extension)
  749. cbExtension = lstrlen(Extension) + 1;
  750. if (cbExtension > (MAX_PATH-(8+1)))
  751. {
  752. return(ERROR_FILENAME_EXCED_RANGE);
  753. }
  754. // Additional special hack for cookie urls.
  755. if (!memcmp(UrlName, COOKIE_PREFIX, sizeof(COOKIE_PREFIX) - 1))
  756. {
  757. // This is a cookie url of the form Cookie:username@domain/path
  758. if (GetWininetUserName())
  759. {
  760. DWORD cb = vdwCurrentUserLen;
  761. if (cb + 8 + cbExtension + 1 < MAX_PATH)
  762. {
  763. memcpy(FileName, vszCurrentUser, cb);
  764. FileName[cb] = '@';
  765. FileNamePtr += (cb + 1);
  766. }
  767. }
  768. }
  769. // Check that the total name doesn't exceed MAX_PATH
  770. // Our total name is 8 chars basename + a dot + the extension + 0
  771. *FileNamePtr++ = L'C';
  772. *FileNamePtr++ = L'A';
  773. //
  774. // generate a six digits random string;
  775. //
  776. //
  777. // We can't use rand() alone to generate a random number because it will
  778. // repeat the same sequence for each new thread that comes in. We can't
  779. // use the TickCount alone because it is a little too predicable. But
  780. // the two combined should be nice. Adding in Counter will take care of
  781. // the case of two brand-new threads coming in at the same time.
  782. //
  783. for ( i = 0; i < 6; i++) {
  784. UINT digit;
  785. RandNum = (GetTickCount() * rand()) + Counter++;
  786. digit = RandNum % 36; // 10 digits + 26 letters
  787. *FileNamePtr++ = ( digit < 10 ) ? (CHAR)('0' + digit) : (CHAR)('A' + (digit - 10));
  788. }
  789. *FileNamePtr++ = L'.';
  790. //
  791. // if an extension is specified, use it.
  792. //
  793. if( Extension != NULL )
  794. {
  795. // if a 0 extension if provided, we will create a
  796. // file with no extension
  797. memcpy(FileNamePtr, Extension, cbExtension);
  798. return ERROR_SUCCESS;
  799. }
  800. // Append default file extension.
  801. memcpy(FileNamePtr, DEFAULT_FILE_EXTENSION, sizeof(DEFAULT_FILE_EXTENSION));
  802. return ERROR_SUCCESS;
  803. }
  804. //
  805. //===================== CSecFileMgr Public Functions ==========================
  806. //
  807. /*-----------------------------------------------------------------------------
  808. CSecFileMgr::CSecFileMgr
  809. ----------------------------------------------------------------------------*/
  810. CSecFileMgr::CSecFileMgr(MEMMAP_FILE* mmFile, DWORD dwOptions) : CFileMgr(mmFile, dwOptions)
  811. {
  812. INET_ASSERT(_mmFile);
  813. // BUGBUG - have to guard against getting out of sync with dirs.
  814. if (_mmFile->GetDirCount() == 0)
  815. Init();
  816. }
  817. /*-----------------------------------------------------------------------------
  818. CSecFileMgr::~CSecFileMgr
  819. ----------------------------------------------------------------------------*/
  820. CSecFileMgr::~CSecFileMgr()
  821. {}
  822. /*-----------------------------------------------------------------------------
  823. CSecFileMgr::Init
  824. ----------------------------------------------------------------------------*/
  825. BOOL CSecFileMgr::Init()
  826. {
  827. if (!(GetOptions() & INTERNET_CACHE_CONTAINER_NODESKTOPINIT))
  828. EnableCacheVu(_mmFile->GetFullPathName());
  829. return CreateAdditionalSubDirectories(DEFAULT_DIR_TABLE_GROW_SIZE);
  830. }
  831. /*-----------------------------------------------------------------------------
  832. GetDirLen()
  833. Returns cache dir path length.
  834. ----------------------------------------------------------------------------*/
  835. DWORD CSecFileMgr::GetDirLen(DWORD nKey)
  836. {
  837. DWORD cb = 0;
  838. if (nKey < DEFAULT_MAX_DIRS)
  839. {
  840. // + 1 to account for trailing backslash.
  841. cb = _cbBasePathLen + DIR_NAME_SIZE + 1;
  842. }
  843. else
  844. {
  845. CHAR szStoreDir[MAX_PATH];
  846. GetStoreDirectory(szStoreDir, &cb);
  847. }
  848. INET_ASSERT(cb);
  849. return cb;
  850. }
  851. /*-----------------------------------------------------------------------------
  852. CSecFileMgr::CreateUniqueFile
  853. Creates a cache file.
  854. ----------------------------------------------------------------------------*/
  855. DWORD CSecFileMgr::CreateUniqueFile(LPCSTR szUrl, LPTSTR szFileName,
  856. LPTSTR szFileExtension, HANDLE *phfHandle, BOOL fCreatePerUser)
  857. {
  858. DWORD nDir, nFiles;
  859. DWORD nDirCount = _mmFile->GetDirCount();
  860. INET_ASSERT(nDirCount <= DEFAULT_MAX_DIRS);
  861. FindMinFilesSubDir(nDir, nFiles);
  862. if (nFiles >= MAX_FILES_PER_CACHE_DIRECTORY
  863. && nDirCount < DEFAULT_MAX_DIRS)
  864. {
  865. if (CreateAdditionalSubDirectories(DEFAULT_DIR_TABLE_GROW_SIZE))
  866. nDir++;
  867. }
  868. // Get the cache path and subdirectory
  869. // from the memory mapped file
  870. CHAR szSubDirPath[MAX_PATH];
  871. DWORD cb = _mmFile->GetFullPathNameLen();
  872. memcpy(szSubDirPath, _mmFile->GetFullPathName(), cb);
  873. _mmFile->GetDirName(nDir, szSubDirPath + cb);
  874. memcpy(szSubDirPath + cb + DIR_NAME_SIZE, DIR_SEPARATOR_STRING, sizeof(DIR_SEPARATOR_STRING));
  875. return CFileMgr::CreateUniqueFile((LPCSTR) szUrl, (LPTSTR) szSubDirPath,
  876. (LPTSTR) szFileName, (LPTSTR) szFileExtension,
  877. (HANDLE*) phfHandle, fCreatePerUser);
  878. }
  879. /*-----------------------------------------------------------------------------
  880. CSecFileMgr::NotifyCommit
  881. Tracks committed cache file counts.
  882. ----------------------------------------------------------------------------*/
  883. BOOL CSecFileMgr::NotifyCommit(DWORD nDirIndex)
  884. {
  885. INET_ASSERT(_mmFile->GetDirCount() <= DEFAULT_MAX_DIRS);
  886. // Regular random subdir
  887. if (nDirIndex < _mmFile->GetDirCount())
  888. {
  889. _mmFile->IncrementFileCount(nDirIndex);
  890. return TRUE;
  891. }
  892. // Not a directory.
  893. else if (nDirIndex == NOT_A_CACHE_SUBDIRECTORY)
  894. {
  895. //INET_ASSERT(FALSE);
  896. //return FALSE;
  897. // May be an absolute path EDITED_CACHE_ENTRY so pass
  898. return TRUE;
  899. }
  900. // Otherwise this had better be an installed directory.
  901. INET_ASSERT(nDirIndex == INSTALLED_DIRECTORY_KEY);
  902. return TRUE;
  903. }
  904. /*-----------------------------------------------------------------------------
  905. CSecFileMgr::Cleanup
  906. ----------------------------------------------------------------------------*/
  907. BOOL CSecFileMgr::Cleanup()
  908. {
  909. CHAR szPath[MAX_PATH];
  910. DWORD cb = _mmFile->GetFullPathNameLen();
  911. memcpy(szPath, _mmFile->GetFullPathName(), cb+1);
  912. if (!AppendSlashIfNecessary(szPath, &cb))
  913. return FALSE;
  914. memcpy(szPath + cb, "*.*", sizeof("*.*"));
  915. WIN32_FIND_DATA fd;
  916. HANDLE handle = FindFirstFile(szPath, &fd);
  917. if (handle == INVALID_HANDLE_VALUE)
  918. return FALSE;
  919. do
  920. {
  921. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  922. && (strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, "..")))
  923. {
  924. memcpy(szPath + cb, fd.cFileName, strlen(fd.cFileName) + 1);
  925. // Only delete directory if it is a valid subdirectory.
  926. if (IsValidCacheSubDir(szPath))
  927. {
  928. if (_mmFile->GetDirIndex(szPath) == NOT_A_CACHE_SUBDIRECTORY)
  929. {
  930. DisableCacheVu(szPath);
  931. if (DeleteCachedFilesInDir(szPath) == ERROR_SUCCESS)
  932. {
  933. SetFileAttributes(szPath, FILE_ATTRIBUTE_DIRECTORY);
  934. RemoveDirectory(szPath);
  935. }
  936. }
  937. }
  938. }
  939. } while (FindNextFile(handle, &fd));
  940. FindClose(handle);
  941. return TRUE;
  942. }
  943. /*-----------------------------------------------------------------------------
  944. CSecFileMgr::GetDirIndex
  945. Returns index of random cache subdirectory from an absolute file path.
  946. ----------------------------------------------------------------------------*/
  947. BOOL CSecFileMgr::GetDirIndex(LPSTR szAbsPath, LPDWORD pnIndex)
  948. {
  949. BOOL fReturn = FALSE;
  950. DWORD idx;
  951. INET_ASSERT(pnIndex);
  952. if (szAbsPath && *szAbsPath)
  953. {
  954. // First look in mem map file for regular dir.
  955. idx = _mmFile->GetDirIndex(szAbsPath);
  956. // If didn't find it in the mem map file,
  957. // check if it is the storage directory.
  958. if (idx == NOT_A_CACHE_SUBDIRECTORY)
  959. {
  960. // First we need to find the path to the file sans \filename.ext
  961. DWORD cbAbsPath = strlen(szAbsPath);
  962. LPSTR ptr = StrRChr(szAbsPath, szAbsPath + cbAbsPath, DIR_SEPARATOR_CHAR);
  963. if (ptr)
  964. {
  965. // Separate path from filename and attempt to map.
  966. // Note - trailing slash is included in path mapped.
  967. DWORD cbPath = (DWORD) (ptr - szAbsPath + 1); // 64BIT
  968. if (MapStoreKey(szAbsPath, &cbPath, &idx, MAP_PATH_TO_KEY))
  969. {
  970. *pnIndex = idx;
  971. fReturn = TRUE;
  972. }
  973. // Must be an EDITED_CACHE_ENTRY set at an absolute path so just update the idx and fail
  974. else
  975. {
  976. *pnIndex = NOT_A_CACHE_SUBDIRECTORY;
  977. }
  978. }
  979. }
  980. // Otherwise, this should be a valid cache subdirectory.
  981. else
  982. {
  983. *pnIndex = idx;
  984. fReturn = TRUE;
  985. }
  986. }
  987. else
  988. {
  989. *pnIndex = NOT_A_CACHE_SUBDIRECTORY;
  990. }
  991. return fReturn;
  992. }
  993. /*-----------------------------------------------------------------------------
  994. CSecFileMgr::GetFilePathFromEntry
  995. Retrieves the full path to the cache subdirectory for a cache entry.
  996. Maps the directory index from the URL_FILEMAP_ENTRY pointer passed in
  997. to a string containing the full path.
  998. ----------------------------------------------------------------------------*/
  999. BOOL CSecFileMgr::GetFilePathFromEntry(URL_FILEMAP_ENTRY *pEntry,
  1000. LPSTR szAbsPath, LPDWORD pcb)
  1001. {
  1002. DWORD cbSubDirPath, cbFile;
  1003. INET_ASSERT(pEntry && szAbsPath && pcb && *pcb);
  1004. // Get file name and length - eg "default.html"
  1005. LPTSTR szFile = (LPTSTR) OFFSET_TO_POINTER(pEntry, pEntry->InternalFileNameOffset);
  1006. cbFile = strlen(szFile);
  1007. // Make real time check?
  1008. if (cbFile && (cbFile < MAX_PATH))
  1009. {
  1010. // Does entry reside in on of the random subdirs?
  1011. if (pEntry->DirIndex != NOT_A_CACHE_SUBDIRECTORY
  1012. && pEntry->DirIndex < DEFAULT_MAX_DIRS)
  1013. {
  1014. // Path length.
  1015. DWORD cbFull = _mmFile->GetFullPathNameLen();
  1016. // Don't overflow output buffer.
  1017. cbSubDirPath =
  1018. cbFull
  1019. + DIR_NAME_SIZE
  1020. + sizeof(DIR_SEPARATOR_STRING) - 1
  1021. + cbFile;
  1022. if (cbSubDirPath + 1 > *pcb)
  1023. {
  1024. // INET_ASSERT(FALSE);
  1025. return FALSE;
  1026. }
  1027. // "C:\Windows\Profiles\anyuser\Temporary Internet Files\"
  1028. memcpy(szAbsPath, _mmFile->GetFullPathName(), cbFull);
  1029. // "C:\Windows\Profiles\anyuser\Temporary Internet Files\XAQRTLY7"
  1030. _mmFile->GetDirName(pEntry->DirIndex, szAbsPath + cbFull);
  1031. // "C:\Windows\Profiles\anyuser\Temporary Internet Files\XAQRTLY7\"
  1032. memcpy(szAbsPath + cbFull + DIR_NAME_SIZE, DIR_SEPARATOR_STRING, sizeof (DIR_SEPARATOR_STRING));
  1033. // "C:\Windows\Profiles\anyuser\Temporary Internet Files\XAQRTLY7\default.htm"
  1034. memcpy(szAbsPath + cbFull + DIR_NAME_SIZE + sizeof(DIR_SEPARATOR_STRING) - 1, szFile, cbFile + 1);
  1035. }
  1036. // There is no cache subdirectory which has been can be mapped
  1037. // from the index. See if there is an existing store mapping.
  1038. else
  1039. {
  1040. if (pEntry->DirIndex == NOT_A_CACHE_SUBDIRECTORY)
  1041. // Assume an ECE absolute path item as AddURL only writes NACS entries with ECE set
  1042. {
  1043. cbSubDirPath = cbFile + 1; // Add terminator to size
  1044. if (cbSubDirPath > *pcb)
  1045. {
  1046. INET_ASSERT(FALSE);
  1047. return FALSE;
  1048. }
  1049. memcpy(szAbsPath, szFile, cbSubDirPath);
  1050. }
  1051. else
  1052. {
  1053. INET_ASSERT(pEntry->DirIndex == INSTALLED_DIRECTORY_KEY);
  1054. DWORD cbPath = 0;
  1055. DWORD dwIndex = INSTALLED_DIRECTORY_KEY;
  1056. if (MapStoreKey(szAbsPath, &cbPath, &dwIndex, MAP_KEY_TO_PATH))
  1057. {
  1058. // "C:\Winnt\Web\"
  1059. cbSubDirPath = cbPath + cbFile;
  1060. if (cbSubDirPath + 1 > *pcb)
  1061. {
  1062. INET_ASSERT(FALSE);
  1063. return FALSE;
  1064. }
  1065. // "C:\Winnt\Web\default.html"
  1066. memcpy(szAbsPath + cbPath, szFile, cbFile + 1);
  1067. }
  1068. else
  1069. {
  1070. INET_ASSERT(FALSE);
  1071. return FALSE;
  1072. }
  1073. }
  1074. }
  1075. // Hand out the absolute path to the file.
  1076. *pcb = cbSubDirPath;
  1077. return TRUE;
  1078. }
  1079. INET_ASSERT(FALSE);
  1080. return FALSE;
  1081. }
  1082. /*-----------------------------------------------------------------------------
  1083. CSecFileMgr::DeleteOneCachedFile
  1084. Deletes one cache file and decrements the file count.
  1085. ----------------------------------------------------------------------------*/
  1086. BOOL CSecFileMgr::DeleteOneCachedFile(LPSTR lpszFileName,
  1087. DWORD dostEntry, DWORD nDirIndex)
  1088. {
  1089. if (!::DeleteOneCachedFile(lpszFileName, dostEntry))
  1090. return FALSE;
  1091. INET_ASSERT(nDirIndex != NOT_A_CACHE_SUBDIRECTORY);
  1092. _mmFile->DecrementFileCount(nDirIndex);
  1093. return TRUE;
  1094. }
  1095. //
  1096. //==================== CSecFileMgr Protected Functions =======================
  1097. //
  1098. /*-----------------------------------------------------------------------------
  1099. CSecFileMgr::CreateRandomDirName
  1100. Creates a random subdirectory name under the root container path.
  1101. ----------------------------------------------------------------------------*/
  1102. BOOL CSecFileMgr::CreateRandomDirName(LPSTR szDirName)
  1103. {
  1104. DWORD RandNum;
  1105. LPSTR ptr = szDirName;
  1106. static Counter;
  1107. INET_ASSERT(szDirName);
  1108. // Stolen from MakeRandomFileName.
  1109. for (DWORD i = 0; i < DIR_NAME_SIZE; i++)
  1110. {
  1111. UINT digit;
  1112. RandNum = (GetTickCount() * rand()) + Counter++;
  1113. // 10 digits + 26 letters
  1114. digit = RandNum % 36;
  1115. *ptr++ = ( digit < 10 ) ? (CHAR)('0' + digit) : (CHAR)('A' + (digit - 10));
  1116. }
  1117. *ptr = '\0';
  1118. return TRUE;
  1119. }
  1120. /*-----------------------------------------------------------------------------
  1121. CSecFileMgr::CreateAdditionalSubDirectories
  1122. Creates nAdditionalDirs random subdirectories, up to DEFAULT_MAX_DIRS.
  1123. ----------------------------------------------------------------------------*/
  1124. BOOL CSecFileMgr::CreateAdditionalSubDirectories(DWORD nAdditionalDirs)
  1125. {
  1126. DWORD nTotalDirs;
  1127. DWORD nDirCount = _mmFile->GetDirCount();
  1128. BOOL bSuccess = TRUE;
  1129. INET_ASSERT(nDirCount <= DEFAULT_MAX_DIRS);
  1130. // Don't create more than the max allowed dirs.
  1131. nTotalDirs = nAdditionalDirs + nDirCount;
  1132. INET_ASSERT(nTotalDirs <= DEFAULT_MAX_DIRS);
  1133. // Create the dir and set the file count to 0.
  1134. DWORD i = nDirCount;
  1135. DWORD nTotalTries = 0;
  1136. do
  1137. {
  1138. if (CreateSubDirectory(i))
  1139. {
  1140. _mmFile->SetFileCount(i, 0);
  1141. _mmFile->IncrementDirCount();
  1142. i++;
  1143. }
  1144. else
  1145. {
  1146. INET_ASSERT(FALSE);
  1147. bSuccess = FALSE;
  1148. }
  1149. if (nTotalTries++ > 100)
  1150. {
  1151. bSuccess = FALSE;
  1152. break;
  1153. }
  1154. } while (i < nTotalDirs);
  1155. return bSuccess;
  1156. }
  1157. /*-----------------------------------------------------------------------------
  1158. CSecFileMgr::CreateSubDirectory(DWORD nIdx)
  1159. Actual creation of subdirectory.
  1160. ----------------------------------------------------------------------------*/
  1161. BOOL CSecFileMgr::CreateSubDirectory(DWORD nIdx)
  1162. {
  1163. CHAR szCacheDir[MAX_PATH];
  1164. CHAR szSubDir[DIR_NAME_SIZE + 1];
  1165. // Generate full path to random dir.
  1166. CreateRandomDirName(szSubDir);
  1167. DWORD cb = _mmFile->GetFullPathNameLen();
  1168. memcpy(szCacheDir, _mmFile->GetFullPathName(), cb);
  1169. memcpy(szCacheDir + cb, szSubDir, DIR_NAME_SIZE + 1);
  1170. // Create the directory and add it to
  1171. // the list of directories in the index.
  1172. if (CreateDirectory(szCacheDir, NULL))
  1173. {
  1174. _mmFile->SetDirName(nIdx, szSubDir);
  1175. // For cachevu must be hidden and system.
  1176. // BUGBUG - sure it must be hidden?
  1177. SetFileAttributes(szCacheDir, FILE_ATTRIBUTE_SYSTEM);
  1178. if (!(GetOptions() & INTERNET_CACHE_CONTAINER_NODESKTOPINIT))
  1179. EnableCacheVu(szCacheDir);
  1180. }
  1181. else
  1182. {
  1183. // Couldn't create the directory.
  1184. INET_ASSERT(FALSE);
  1185. return FALSE;
  1186. }
  1187. return TRUE;
  1188. }
  1189. /*-----------------------------------------------------------------------------
  1190. CSecFileMgr::FindMinFilesSubDir
  1191. Determines the cache subdirectory with the minimum file count for load balancing.
  1192. ----------------------------------------------------------------------------*/
  1193. BOOL CSecFileMgr::FindMinFilesSubDir(DWORD& nMinFileDir, DWORD& nFiles)
  1194. {
  1195. DWORD nDirCount = _mmFile->GetDirCount();
  1196. if (nDirCount == 0 || nDirCount > DEFAULT_MAX_DIRS)
  1197. {
  1198. INET_ASSERT(FALSE);
  1199. _mmFile->SetDirCount(0);
  1200. CreateAdditionalSubDirectories(DEFAULT_DIR_TABLE_GROW_SIZE);
  1201. nDirCount = _mmFile->GetDirCount();
  1202. }
  1203. nMinFileDir = 0;
  1204. DWORD nMinFiles = _mmFile->GetFileCount(0);
  1205. for (DWORD i = 1; i < nDirCount; i++)
  1206. {
  1207. if (_mmFile->GetFileCount(i) < nMinFiles)
  1208. {
  1209. nMinFiles = _mmFile->GetFileCount(i);
  1210. nMinFileDir = i;
  1211. }
  1212. }
  1213. nFiles = _mmFile->GetFileCount(nMinFileDir);
  1214. return TRUE;
  1215. }