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.

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