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.

1553 lines
30 KiB

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <urlcache.h>
  4. #include <histapi.h>
  5. //#include "cache.hxx"
  6. //#include "history.h"
  7. #include "generic.h"
  8. #define DEFAULT_CEI_BUFFER_SIZE 512
  9. // 1k ~> sizeof (CEI) + lpszSourceUrlName + lpHeaderInfo(~<255) + lpszLocalFileName(<255)
  10. #define ASSERT(x) if (!(x)) DebugBreak();
  11. LPCTSTR lpszHistoryPrefix = "Hist:";
  12. DWORD cbHistoryPrefix = sizeof("Hist:") -1;
  13. LPCTSTR lpszTitleHeader = "Title: ";
  14. DWORD cbTitleHeader = sizeof("Title: ") -1;
  15. LPCTSTR lpszFragmentHeader = "Frags: ";
  16. DWORD cbFragmentHeader = sizeof("Frags: ") -1;
  17. LPCTSTR lpszHistoryFileExtension = "HSD";
  18. LPTSTR szCRLF = "\r\n";
  19. DWORD cbCRLF = sizeof("\r\n") -1;
  20. LPTSTR szSPC = " ";
  21. LPTSTR szPND = "#";
  22. LPTSTR szFRAGB = " (#";
  23. LPTSTR szFRAGE = ")";
  24. typedef struct _HISTORY_SEARCH_OBJ
  25. {
  26. HANDLE hEnum;
  27. LPTSTR lpszPrefixedUrl;
  28. LPTSTR lpszFragment;
  29. LPCACHE_ENTRY_INFO lpCEI;
  30. LPTSTR *aFrags;
  31. DWORD cFrags;
  32. DWORD iFrags;
  33. } HISTORY_SEARCH_OBJ, *LPHISTORY_SEARCH_OBJ;
  34. typedef struct _HISTORY_ITEM_INFO
  35. {
  36. DWORD dwVersion; //Version of History System
  37. LPSTR lpszSourceUrlName; // embedded pointer to the URL name string.
  38. DWORD HistoryItemType; // cache type bit mask.
  39. FILETIME LastAccessTime; // last accessed time in GMT format
  40. LPSTR lpszTitle; // embedded pointer to the History-Title: info.
  41. LPSTR lpszDependancies; // list of URLs that this page requires to be functional, SPC delimited
  42. DWORD dwReserved; // reserved for future use.
  43. } HISTORY_ITEM_INFO, *LPHISTORY_ITEM_INFO;
  44. LPTSTR
  45. GetDependanciesFromCEI (LPCACHE_ENTRY_INFO lpCEI)
  46. {
  47. LPTSTR buf = NULL;
  48. HANDLE file = NULL;
  49. DWORD size = 0;
  50. LPTSTR pch = NULL;
  51. ASSERT (lpCEI);
  52. file = CreateFile(lpCEI->lpszLocalFileName,
  53. GENERIC_READ,
  54. FILE_SHARE_READ,
  55. NULL,
  56. OPEN_EXISTING,
  57. FILE_ATTRIBUTE_NORMAL,
  58. NULL);
  59. if (file == INVALID_HANDLE_VALUE)
  60. return NULL;
  61. size = GetFileSize(file, NULL);
  62. buf = (LPTSTR) LocalAlloc (LPTR, size + 1);
  63. if (!buf)
  64. {
  65. CloseHandle(file);
  66. return NULL;
  67. }
  68. buf[size] = '\0';
  69. // we are going to store these as URL\nURL\nURL\n so just look for \n and replace with space
  70. for (pch = buf; *pch; pch++)
  71. {
  72. if (*pch == '\n')
  73. *pch = ' ';
  74. }
  75. CloseHandle (file);
  76. return buf;
  77. }
  78. LPTSTR
  79. MakeDependanciesFile (LPCTSTR lpszDeps)
  80. {
  81. HANDLE file = NULL;
  82. LPTSTR pch = NULL;
  83. LPTSTR path = NULL;
  84. LPTSTR temp = NULL;
  85. DWORD size = 0;
  86. path = _tempnam (NULL, "HS");
  87. if (!path)
  88. return NULL;
  89. file = CreateFile(path,
  90. GENERIC_WRITE,
  91. 0,
  92. NULL,
  93. CREATE_ALWAYS,
  94. FILE_ATTRIBUTE_NORMAL,
  95. NULL);
  96. if (file == INVALID_HANDLE_VALUE)
  97. {
  98. LocalFree (path);
  99. return NULL;
  100. }
  101. // we are going to store these as URL\nURL\nURL\n
  102. if(lpszDeps)
  103. {
  104. size = lstrlen (lpszDeps);
  105. temp = LocalAlloc (LPTR, size + 1);
  106. if (!temp)
  107. {
  108. LocalFree (path);
  109. CloseHandle (file);
  110. return NULL;
  111. }
  112. lstrcpy (temp, lpszDeps);
  113. for (pch = temp; *pch; pch++)
  114. {
  115. if (*pch == ' ')
  116. *pch = '\n';
  117. }
  118. WriteFile (file, temp, size, &size, NULL);
  119. }
  120. CloseHandle (file);
  121. return path;
  122. }
  123. LPTSTR
  124. ConvertToUnprefixedUrl (
  125. LPCTSTR lpszPrefixedUrl,
  126. LPCTSTR lpszFragment
  127. )
  128. {
  129. DWORD size = 0;
  130. LPTSTR lpszUrl = NULL;
  131. LPTSTR temp = NULL;
  132. temp = (LPTSTR) (lpszPrefixedUrl + cbHistoryPrefix) ;
  133. size = lstrlen(temp);
  134. if (lpszFragment)
  135. {
  136. size += lstrlen (lpszFragment);
  137. size += 1; // for the fragment '#'
  138. }
  139. lpszUrl = (LPTSTR) LocalAlloc (LPTR, size + 1);
  140. if (!lpszUrl)
  141. return NULL;
  142. lstrcpy (lpszUrl, temp);
  143. if (lpszFragment)
  144. {
  145. lstrcat (lpszUrl, szPND);
  146. lstrcat (lpszUrl, lpszFragment);
  147. }
  148. return lpszUrl;
  149. }
  150. BOOL
  151. ConvertToPrefixedUrl (IN LPCTSTR lpszUrlName,
  152. OUT LPTSTR *lplpszPrefixedUrl,
  153. OUT LPTSTR *lplpszFragment)
  154. {
  155. if (!lpszUrlName || !*lpszUrlName)
  156. {
  157. *lplpszPrefixedUrl = (LPTSTR) LocalAlloc (LPTR, cbHistoryPrefix + 1);
  158. if (!*lplpszPrefixedUrl)
  159. return FALSE;
  160. lstrcpy (*lplpszPrefixedUrl, lpszHistoryPrefix);
  161. return TRUE;
  162. }
  163. *lplpszPrefixedUrl = (LPTSTR) LocalAlloc (LPTR, cbHistoryPrefix + strlen (lpszUrlName) + 1);
  164. if (!*lplpszPrefixedUrl)
  165. return FALSE;
  166. lstrcpy (*lplpszPrefixedUrl, lpszHistoryPrefix);
  167. lstrcat (*lplpszPrefixedUrl, lpszUrlName);
  168. *lplpszFragment = strchr (*lplpszPrefixedUrl, '#');
  169. if(*lplpszFragment)
  170. *((*lplpszFragment)++) = '\0';
  171. return TRUE;
  172. }
  173. LPCACHE_ENTRY_INFO
  174. RetrievePrefixedUrl (IN LPTSTR lpszUrl)
  175. /*++
  176. The CEI returned must be freed and the lpszUrl unlocked
  177. --*/
  178. {
  179. LPCACHE_ENTRY_INFO lpCEI = NULL;
  180. DWORD cbCEI = 0;
  181. lpCEI = (LPCACHE_ENTRY_INFO) LocalAlloc (LPTR, DEFAULT_CEI_BUFFER_SIZE);
  182. if (!lpCEI)
  183. return NULL;
  184. cbCEI = DEFAULT_CEI_BUFFER_SIZE;
  185. while (!RetrieveUrlCacheEntryFile (lpszUrl,
  186. lpCEI,
  187. &cbCEI,
  188. 0))
  189. {
  190. if (GetLastError () == ERROR_NOT_ENOUGH_MEMORY)
  191. {
  192. LocalFree (lpCEI);
  193. lpCEI = (LPCACHE_ENTRY_INFO) LocalAlloc (LPTR, cbCEI);
  194. if (!lpCEI)
  195. return NULL;
  196. }
  197. else
  198. return NULL;
  199. }
  200. return lpCEI;
  201. }
  202. LPCACHE_ENTRY_INFO
  203. RetrievePrefixedUrlInfo (IN LPTSTR lpszUrl)
  204. /*++
  205. The CEI returned must be freed and the lpszUrl unlocked
  206. --*/
  207. {
  208. LPCACHE_ENTRY_INFO lpCEI = NULL;
  209. DWORD cbCEI = 0;
  210. lpCEI = (LPCACHE_ENTRY_INFO) LocalAlloc (LPTR, DEFAULT_CEI_BUFFER_SIZE);
  211. if (!lpCEI)
  212. return NULL;
  213. cbCEI = DEFAULT_CEI_BUFFER_SIZE;
  214. while (!GetUrlCacheEntryInfo (lpszUrl,
  215. lpCEI,
  216. &cbCEI
  217. ))
  218. {
  219. if (GetLastError () == ERROR_NOT_ENOUGH_MEMORY)
  220. {
  221. LocalFree (lpCEI);
  222. lpCEI = (LPCACHE_ENTRY_INFO) LocalAlloc (LPTR, cbCEI);
  223. if (!lpCEI)
  224. return NULL;
  225. }
  226. else
  227. return NULL;
  228. }
  229. return lpCEI;
  230. }
  231. LPTSTR
  232. GetTitleFromCEI (IN LPCACHE_ENTRY_INFO lpCEI, LPCTSTR lpszFragment)
  233. {
  234. LPTSTR pHeader, pCurr;
  235. DWORD size = 0;
  236. pHeader = (LPTSTR) MemFind ((LPVOID) lpCEI->lpHeaderInfo,
  237. lpCEI->dwHeaderInfoSize,
  238. (LPVOID) lpszTitleHeader,
  239. cbTitleHeader);
  240. if (!pHeader)
  241. {
  242. SetLastError (ERROR_FILE_NOT_FOUND);
  243. return NULL;
  244. }
  245. //Header was found
  246. pCurr = (LPTSTR) MemFind ( (LPVOID) pHeader,
  247. (lpCEI->dwHeaderInfoSize) - ((DWORD) (pHeader - (LPTSTR)lpCEI->lpHeaderInfo)),
  248. (LPVOID) szCRLF,
  249. cbCRLF);
  250. if (!pCurr)
  251. {
  252. // BUGBUG do what now?? found the header, but the title is not in a recognized
  253. // format. lets bail with a internal prob
  254. ASSERT (FALSE);
  255. SetLastError (ERROR_FILE_NOT_FOUND);
  256. return NULL;
  257. }
  258. *pCurr = '\0';
  259. pCurr = pHeader + cbTitleHeader;
  260. while (*pCurr == ' ')
  261. pCurr++;
  262. size = lstrlen (pCurr) ;
  263. if (lpszFragment) //must also include the fragment in Title
  264. size += lstrlen (lpszFragment) + 4;
  265. pHeader = (LPTSTR) LocalAlloc (LPTR, size + 1);
  266. if (!pHeader)
  267. return NULL;
  268. lstrcpy (pHeader, pCurr);
  269. if (lpszFragment)
  270. {
  271. lstrcat (pHeader, szFRAGB);
  272. lstrcat (pHeader, lpszFragment);
  273. lstrcat (pHeader, szFRAGE);
  274. }
  275. return pHeader;
  276. }
  277. DWORD
  278. GetFragmentsFromCEI(IN LPCACHE_ENTRY_INFO lpCEI,
  279. OUT LPTSTR **paFrags,
  280. OUT DWORD *pcFrags)
  281. {
  282. LPTSTR pHeader, pCurr;
  283. //need to get the string from the CEI, then parse into args
  284. pHeader = (LPTSTR) MemFind (lpCEI->lpHeaderInfo,
  285. lpCEI->dwHeaderInfoSize,
  286. (LPVOID) lpszFragmentHeader,
  287. cbFragmentHeader);
  288. if (!pHeader)
  289. return ERROR_FILE_NOT_FOUND;
  290. //Header was found
  291. pCurr = (LPTSTR) MemFind ( (LPVOID) pHeader,
  292. lpCEI->dwHeaderInfoSize - (pHeader - lpCEI->lpHeaderInfo),
  293. (LPVOID) szCRLF,
  294. cbCRLF);
  295. if (!pCurr)
  296. {
  297. //this is a corrupted Entry
  298. ASSERT (FALSE);
  299. return ERROR_FILE_NOT_FOUND;
  300. }
  301. *pCurr = '\0';
  302. //
  303. // pHeader is now zero terminated string
  304. // we want to parse the args of that string
  305. //
  306. if (!ParseArgsDyn(pHeader + cbFragmentHeader, paFrags, pcFrags))
  307. return ERROR_NOT_ENOUGH_MEMORY;
  308. return ERROR_SUCCESS;
  309. }
  310. LPBYTE
  311. GenerateHeaderInfo(LPCTSTR lpszTitle, LPCTSTR *aFrags, DWORD cFrags)
  312. {
  313. DWORD size = 0;
  314. LPBYTE hi = NULL;
  315. LPTSTR curr;
  316. DWORD i;
  317. //first need to find the size required of HeaderInfo
  318. if (lpszTitle)
  319. {
  320. size += lstrlen (lpszTitle);
  321. size += cbTitleHeader;
  322. size += cbCRLF;
  323. }
  324. if (cFrags)
  325. {
  326. size += cbFragmentHeader;
  327. size += cFrags;
  328. for (i = 0; i < cFrags; i++)
  329. size += lstrlen(aFrags[i]);
  330. size += cbCRLF;
  331. }
  332. hi = (LPBYTE) LocalAlloc (LPTR, ++size);
  333. if (!hi)
  334. return NULL;
  335. curr = (LPTSTR) hi;
  336. *curr = '\0';
  337. if (lpszTitle)
  338. {
  339. lstrcat (curr, lpszTitleHeader);
  340. lstrcat (curr, lpszTitle);
  341. lstrcat (curr, szCRLF);
  342. }
  343. if (cFrags)
  344. {
  345. lstrcat (curr, lpszFragmentHeader);
  346. for(i = 0; i < cFrags; i++)
  347. {
  348. if (!*(aFrags[i]))
  349. continue;
  350. lstrcat(curr, szSPC);
  351. lstrcat(curr, aFrags[i]);
  352. }
  353. lstrcat (curr, szCRLF);
  354. }
  355. return hi;
  356. }
  357. DWORD
  358. CopyCEItoHII (
  359. LPCTSTR lpszFragment,
  360. LPHISTORY_ITEM_INFO lpHII,
  361. LPDWORD lpcbHII,
  362. LPCACHE_ENTRY_INFO lpCEI
  363. )
  364. {
  365. DWORD Error = ERROR_SUCCESS;
  366. DWORD cbNeeded = sizeof (HISTORY_ITEM_INFO);
  367. DWORD cbUsed = cbNeeded;
  368. LPTSTR lpszUrl = NULL;
  369. DWORD cbUrl = 0;
  370. LPTSTR lpszTitle = NULL;
  371. DWORD cbTitle = 0;
  372. LPTSTR lpszDependancies = NULL;
  373. DWORD cbDependancies = 0;
  374. ASSERT (lpCEI->lpszSourceUrlName);
  375. //
  376. // need to determine the necessary size
  377. //
  378. // need the unprefixed name
  379. lpszUrl = ConvertToUnprefixedUrl (lpCEI->lpszSourceUrlName, (LPCTSTR) lpszFragment);
  380. if (!lpszUrl)
  381. {
  382. Error = ERROR_INTERNAL_ERROR;
  383. goto quit;
  384. }
  385. cbUrl = lstrlen (lpszUrl);
  386. cbNeeded += cbUrl + 1;
  387. lpszTitle = GetTitleFromCEI (lpCEI, (LPCTSTR) lpszFragment);
  388. if (lpszTitle)
  389. {
  390. cbTitle = lstrlen (lpszTitle);
  391. cbNeeded += cbTitle + 1;
  392. }
  393. lpszDependancies = GetDependanciesFromCEI (lpCEI);
  394. if (lpszDependancies)
  395. {
  396. cbDependancies = lstrlen (lpszDependancies);
  397. cbNeeded += cbDependancies + 1;
  398. }
  399. if (cbNeeded > *lpcbHII)
  400. {
  401. Error = ERROR_NOT_ENOUGH_MEMORY;
  402. *lpcbHII = cbNeeded;
  403. goto quit;
  404. }
  405. //
  406. // Add the other pieces
  407. //
  408. lpHII->lpszSourceUrlName = (LPTSTR) (lpHII + cbUsed + 1);
  409. lstrcpy (lpHII->lpszSourceUrlName, lpszUrl);
  410. cbUsed += cbUrl + 1;
  411. if (lpszTitle)
  412. {
  413. lpHII->lpszTitle = (LPTSTR) (lpHII + cbUsed + 1);
  414. lstrcpy (lpHII->lpszTitle, lpszTitle);
  415. cbUsed += cbTitle + 1;
  416. }
  417. else
  418. lpHII->lpszTitle = NULL;
  419. if (lpszDependancies)
  420. {
  421. lpHII->lpszDependancies = (LPTSTR) (lpHII + cbUsed + 1);
  422. lstrcpy (lpHII->lpszDependancies, lpszDependancies);
  423. cbUsed += cbDependancies + 1;
  424. }
  425. else
  426. lpHII->lpszDependancies = NULL;
  427. lpHII->dwVersion = lpCEI->dwVersion;
  428. lpHII->HistoryItemType = lpCEI->CacheEntryType;
  429. lpHII->LastAccessTime.dwLowDateTime = lpCEI->LastAccessTime.dwLowDateTime;
  430. lpHII->LastAccessTime.dwHighDateTime = lpCEI->LastAccessTime.dwHighDateTime;
  431. lpHII->dwReserved = lpCEI->dwReserved;
  432. quit:
  433. if (lpszUrl)
  434. LocalFree(lpszUrl);
  435. if (lpszTitle)
  436. LocalFree(lpszTitle);
  437. if (lpszDependancies)
  438. LocalFree(lpszDependancies);
  439. if (Error == ERROR_SUCCESS)
  440. *lpcbHII = cbUsed;
  441. return Error;
  442. }
  443. HISTORYAPI_(BOOL)
  444. AddHistoryItem(
  445. IN LPCTSTR lpszUrlName, //direct correspondence in URLCACHE
  446. IN LPCTSTR lpszHistoryTitle, // this needs to be added to lpHeaderInfo
  447. IN LPCTSTR lpszDependancies,
  448. IN DWORD dwFlags,
  449. IN DWORD dwReserved
  450. )
  451. /*++
  452. Routine Description:
  453. Places the specified URL into the history.
  454. If it does not exist, then it is created. If it does exist it is overwritten.
  455. Arguments:
  456. lpszUrlName - The URL in question.
  457. lpszHistoryTitle - pointer to the friendly title that should be associated
  458. with this URL. If NULL, no title will be added.
  459. Reserved - Unused, for future implementations
  460. Return Value:
  461. BOOL
  462. Success - TRUE
  463. Failure - FALSE. Extended error can be retrieved from GetLastError()
  464. --*/
  465. {
  466. LPBYTE NewHeaderInfo = NULL;
  467. DWORD cbNHI = 0;
  468. BOOL New = FALSE;
  469. LPTSTR lpszPrefixedUrl = NULL;
  470. LPTSTR lpszFragment = NULL;
  471. DWORD Error = ERROR_SUCCESS;
  472. LPCACHE_ENTRY_INFO lpCEI = NULL;
  473. FILETIME ftExpires;
  474. FILETIME ftModified;
  475. SYSTEMTIME st;
  476. LPTSTR *aFrags = NULL;
  477. DWORD cFrags = 0;
  478. DWORD i;
  479. BOOL found = FALSE;
  480. LPTSTR lpszDepsPath = NULL;
  481. DWORD type = NORMAL_CACHE_ENTRY;
  482. LPTSTR lpszOldTitle = NULL;
  483. if (!ConvertToPrefixedUrl (lpszUrlName, &lpszPrefixedUrl, &lpszFragment))
  484. {
  485. Error = ERROR_NOT_ENOUGH_MEMORY;
  486. goto quit;
  487. }
  488. lpCEI = RetrievePrefixedUrl (lpszPrefixedUrl);
  489. if (!lpCEI)
  490. New = TRUE;
  491. // Buffer filled with data now
  492. // BUGBUG must handle fragments
  493. if (!New)
  494. {
  495. type = lpCEI->CacheEntryType;
  496. GetFragmentsFromCEI (lpCEI, &aFrags, &cFrags);
  497. lpszOldTitle = GetTitleFromCEI (lpCEI, NULL);
  498. }
  499. // if (Error != ERROR_SUCCESS)
  500. if (lpszFragment)
  501. {
  502. for (i = 0; i < cFrags; i++)
  503. {
  504. if (lstrcmp (aFrags[i], lpszFragment) == 0)
  505. {
  506. found = TRUE;
  507. break;
  508. }
  509. }
  510. if (!found)
  511. AddArgvDyn (&aFrags, &cFrags, lpszFragment);
  512. }
  513. NewHeaderInfo = GenerateHeaderInfo (lpszHistoryTitle ? lpszHistoryTitle : lpszOldTitle, aFrags, cFrags);
  514. cbNHI = lstrlen (NewHeaderInfo);
  515. lpszDepsPath = MakeDependanciesFile (lpszDependancies);
  516. if (!lpszDepsPath)
  517. {
  518. ASSERT(FALSE);
  519. Error = ERROR_INTERNAL_ERROR;
  520. goto quit;
  521. }
  522. GetLocalTime (&st);
  523. SystemTimeToFileTime(&st, &ftModified);
  524. st.wDay += 7; //BUGBUG must get this setting from registry
  525. if(!SystemTimeToFileTime(&st, &ftExpires))
  526. {
  527. Error = GetLastError ();
  528. goto quit;
  529. }
  530. if (lpCEI)
  531. {
  532. UnlockUrlCacheEntryFile (lpCEI->lpszSourceUrlName, 0);
  533. LocalFree (lpCEI);
  534. lpCEI = NULL;
  535. }
  536. if (!CommitUrlCacheEntry(
  537. lpszPrefixedUrl,
  538. lpszDepsPath,
  539. ftExpires,
  540. ftModified, //we dont care about last modified time
  541. type, //this is set from dwFlags i think
  542. NewHeaderInfo,
  543. cbNHI ,
  544. lpszHistoryFileExtension,
  545. 0))
  546. {
  547. Error = GetLastError ();
  548. goto quit;
  549. }
  550. // if we made it to here, we win!
  551. quit:
  552. if (aFrags)
  553. LocalFree (aFrags);
  554. if (lpszDepsPath)
  555. LocalFree (lpszDepsPath);
  556. if (lpCEI)
  557. {
  558. UnlockUrlCacheEntryFile (lpCEI->lpszSourceUrlName, 0);
  559. LocalFree (lpCEI);
  560. }
  561. if (lpszPrefixedUrl)
  562. LocalFree (lpszPrefixedUrl);
  563. if (NewHeaderInfo)
  564. LocalFree (NewHeaderInfo);
  565. if (lpszOldTitle)
  566. LocalFree (lpszOldTitle);
  567. if (Error != ERROR_SUCCESS)
  568. {
  569. SetLastError (Error);
  570. return FALSE;
  571. }
  572. else
  573. return TRUE;
  574. }
  575. HISTORYAPI_(BOOL)
  576. IsHistorical(
  577. IN LPCTSTR lpszUrlName
  578. )
  579. /*++
  580. Routine Description:
  581. Checks to see if Url is a valid History item
  582. Arguments:
  583. lpszUrlName - The URL in question.
  584. Return Value:
  585. BOOL
  586. Success - TRUE. Item is in History
  587. Failure - FALSE. Extended error can be retrieved from GetLastError()
  588. ERROR_FILE_NOT_FOUND indicates the URL is not available
  589. --*/
  590. {
  591. LPTSTR lpszPrefixedUrl = NULL;
  592. LPTSTR lpszFragment = NULL;
  593. DWORD Error = ERROR_SUCCESS;
  594. LPCACHE_ENTRY_INFO lpCEI = NULL;
  595. LPTSTR *aFrags = NULL;
  596. DWORD cFrags = 0;
  597. DWORD i;
  598. if (!ConvertToPrefixedUrl (lpszUrlName, &lpszPrefixedUrl, &lpszFragment))
  599. {
  600. Error = ERROR_NOT_ENOUGH_MEMORY;
  601. goto quit;
  602. }
  603. lpCEI = RetrievePrefixedUrlInfo (lpszPrefixedUrl);
  604. if (!lpCEI)
  605. {
  606. Error = GetLastError ();
  607. goto quit;
  608. }
  609. if (lpszFragment)
  610. {
  611. //
  612. // Need to check for IntraDocFrags
  613. //
  614. Error = GetFragmentsFromCEI(lpCEI, & aFrags, & cFrags);
  615. if (Error != ERROR_SUCCESS)
  616. goto quit;
  617. for (i = 0; i < cFrags; i++)
  618. {
  619. if (strcmp(aFrags[i], lpszFragment) == 0)
  620. goto quit;
  621. }
  622. Error = ERROR_FILE_NOT_FOUND;
  623. }
  624. quit:
  625. if (aFrags)
  626. LocalFree (aFrags);
  627. if (lpszPrefixedUrl)
  628. LocalFree (lpszPrefixedUrl);
  629. if (lpCEI)
  630. {
  631. LocalFree (lpCEI);
  632. }
  633. if (Error != ERROR_SUCCESS)
  634. {
  635. SetLastError (Error);
  636. return FALSE;
  637. }
  638. else
  639. return TRUE;
  640. }
  641. HISTORYAPI_(BOOL)
  642. RemoveHistoryItem (
  643. IN LPCTSTR lpszUrlName,
  644. IN DWORD dwReserved
  645. )
  646. /*++
  647. Routine Description:
  648. Changes an entry from an History Item to a normal cache entry. Removing
  649. the Title at the same time.
  650. Arguments:
  651. lpszUrlName - The URL in question.
  652. dwReserved - Unused. for future usage
  653. Return Value:
  654. BOOL
  655. Success - TRUE. Item found and removed
  656. Failure - FALSE. Extended error can be retrieved from GetLastError()
  657. ERROR_FILE_NOT_FOUND indicates the URL is not available
  658. --*/
  659. {
  660. LPTSTR *aFrags = NULL;
  661. DWORD cFrags = 0;
  662. DWORD i;
  663. LPTSTR lpszTitle = NULL;
  664. LPBYTE NewHeaderInfo = NULL;
  665. LPTSTR lpszPrefixedUrl = NULL;
  666. LPTSTR lpszFragment = NULL;
  667. DWORD Error = ERROR_SUCCESS;
  668. LPCACHE_ENTRY_INFO lpCEI = NULL;
  669. if (!ConvertToPrefixedUrl (lpszUrlName, &lpszPrefixedUrl, &lpszFragment))
  670. {
  671. Error = ERROR_NOT_ENOUGH_MEMORY;
  672. goto quit;
  673. }
  674. lpCEI = RetrievePrefixedUrl (lpszPrefixedUrl);
  675. if (!lpCEI)
  676. {
  677. Error = GetLastError ();
  678. goto quit;
  679. }
  680. if (lpszFragment)
  681. {
  682. BOOL found = FALSE;
  683. //
  684. // Need to check for IntraDocFrags
  685. //
  686. Error = GetFragmentsFromCEI(lpCEI, & aFrags, & cFrags);
  687. if (Error != ERROR_SUCCESS)
  688. goto quit;
  689. for (i = 0; i < cFrags; i++)
  690. {
  691. if (strcmp(aFrags[i], lpszFragment) == 0)
  692. {
  693. //we need to delete this and reinsert
  694. *(aFrags[i]) = '\0';
  695. found = TRUE;
  696. break;
  697. }
  698. }
  699. if (cFrags - 1 && found)
  700. {
  701. lpszTitle = GetTitleFromCEI (lpCEI, NULL);
  702. NewHeaderInfo = GenerateHeaderInfo (lpszTitle, aFrags, cFrags);
  703. if(!NewHeaderInfo)
  704. {
  705. Error = ERROR_NOT_ENOUGH_MEMORY;
  706. goto quit;
  707. }
  708. UnlockUrlCacheEntryFile(lpCEI->lpszSourceUrlName, 0);
  709. if (!CommitUrlCacheEntry(
  710. lpszPrefixedUrl,
  711. lpCEI->lpszLocalFileName,
  712. lpCEI->ExpireTime,
  713. lpCEI->LastModifiedTime,
  714. lpCEI->CacheEntryType , // only changes
  715. NewHeaderInfo, //
  716. lstrlen (NewHeaderInfo),
  717. lpCEI->lpszFileExtension,
  718. 0))
  719. {
  720. Error = GetLastError ();
  721. }
  722. goto quit;
  723. }
  724. if (!found)
  725. {
  726. Error = ERROR_FILE_NOT_FOUND;
  727. goto quit;
  728. }
  729. }
  730. //BUGBUG looks like this will always delete a history item if there is only fragment
  731. //problem is we could have a frag and a unfragged Item
  732. UnlockUrlCacheEntryFile(lpCEI->lpszSourceUrlName, 0);
  733. if (!DeleteUrlCacheEntry(lpszPrefixedUrl))
  734. {
  735. Error = GetLastError ();
  736. goto quit;
  737. }
  738. quit:
  739. if (aFrags)
  740. LocalFree (aFrags);
  741. if (lpszTitle)
  742. LocalFree (lpszTitle);
  743. if (lpCEI)
  744. {
  745. LocalFree (lpCEI);
  746. }
  747. if (NewHeaderInfo)
  748. LocalFree (NewHeaderInfo);
  749. if (lpszPrefixedUrl)
  750. LocalFree (lpszPrefixedUrl);
  751. if (Error != ERROR_SUCCESS)
  752. {
  753. SetLastError (Error);
  754. return FALSE;
  755. }
  756. else
  757. return TRUE;
  758. }
  759. HISTORYAPI_(BOOL)
  760. GetHistoryItemInfo (
  761. IN LPCTSTR lpszUrlName,
  762. OUT LPHISTORY_ITEM_INFO lpHistoryItemInfo,
  763. IN OUT LPDWORD lpdwHistoryItemInfoBufferSize
  764. )
  765. /*++
  766. Routine Description:
  767. Fills a buffer with a HISTORY_ITEM_INFO struct.
  768. Arguments:
  769. lpszUrlName - The URL in question.
  770. lpHistoryItemInfo - Buffer that will hold the HISTORY_ITEM_INFO
  771. lpdwHistoryItemInfoBufferSize - IN: size of the lpHistoryItemInfo buffer
  772. OUT: size of filled struct when successful
  773. or necessary buffer size when failed
  774. Return Value:
  775. BOOL
  776. Success - TRUE.
  777. Failure - FALSE. Extended error can be retrieved from GetLastError()
  778. ERROR_NOT_ENOUGH_MEMORY indicates the buffer is insufficient
  779. --*/
  780. {
  781. LPTSTR lpszPrefixedUrl = NULL;
  782. LPTSTR lpszFragment = NULL;
  783. DWORD Error = ERROR_SUCCESS;
  784. LPCACHE_ENTRY_INFO lpCEI = NULL;
  785. if (!ConvertToPrefixedUrl (lpszUrlName, &lpszPrefixedUrl, &lpszFragment))
  786. {
  787. Error = ERROR_NOT_ENOUGH_MEMORY;
  788. goto quit;
  789. }
  790. lpCEI = RetrievePrefixedUrlInfo (lpszPrefixedUrl);
  791. if (!lpCEI)
  792. {
  793. Error = GetLastError ();
  794. goto quit;
  795. }
  796. Error = CopyCEItoHII (lpszFragment, lpHistoryItemInfo, lpdwHistoryItemInfoBufferSize, lpCEI);
  797. quit:
  798. if (lpszPrefixedUrl)
  799. LocalFree (lpszPrefixedUrl);
  800. if (lpCEI)
  801. {
  802. LocalFree (lpCEI);
  803. }
  804. if (Error != ERROR_SUCCESS)
  805. {
  806. SetLastError (Error);
  807. return FALSE;
  808. }
  809. else
  810. return TRUE;
  811. }
  812. HISTORYAPI_(HANDLE)
  813. FindFirstHistoryItem(
  814. IN LPCTSTR lpszUrlSearchPattern,
  815. OUT LPHISTORY_ITEM_INFO lpFirstHistoryItemInfo,
  816. IN OUT LPDWORD lpdwFirstHistoryItemInfoBufferSize
  817. )
  818. /*++
  819. Routine Description:
  820. Searches through the History looking for URLs that match the search pattern,
  821. and copies the HISTORY_ITEM_INFO into the buffer.
  822. Arguments:
  823. lpszUrlSearchPattern - The URL in question.
  824. lpFirstHistoryItemInfo - Buffer that will hold the HISTORY_ITEM_INFO
  825. lpdwFirstHistoryItemInfoBufferSize - IN: size of the lpHistoryItemInfo buffer
  826. OUT: size of filled struct when successful
  827. or necessary buffer size when failed
  828. Return Value:
  829. HANDLE
  830. Success - Valid enumeration handle to pass into subsequent calls to
  831. FindNextHistoryItem ().
  832. Failure - NULL. Extended error can be retrieved from GetLastError()
  833. ERROR_NOT_ENOUGH_MEMORY indicates the buffer is insufficient
  834. --*/
  835. {
  836. LPHISTORY_SEARCH_OBJ hso = NULL;
  837. LPCACHE_ENTRY_INFO lpCEI = NULL;
  838. DWORD cbCEI = 0;
  839. LPTSTR lpszFoundFragment = NULL;
  840. DWORD Error = ERROR_SUCCESS;
  841. BOOL found = FALSE;
  842. hso = (LPHISTORY_SEARCH_OBJ) LocalAlloc (LPTR, sizeof (HISTORY_SEARCH_OBJ));
  843. if (!hso)
  844. {
  845. Error = GetLastError ();
  846. goto quit;
  847. }
  848. hso->aFrags = NULL;
  849. hso->cFrags = 0;
  850. hso->iFrags = 0;
  851. hso->lpszPrefixedUrl = NULL;
  852. hso->lpszFragment = NULL;
  853. if (!ConvertToPrefixedUrl (lpszUrlSearchPattern, &(hso->lpszPrefixedUrl), &(hso->lpszFragment)))
  854. {
  855. Error = ERROR_NOT_ENOUGH_MEMORY;
  856. goto quit;
  857. }
  858. lpCEI = (LPCACHE_ENTRY_INFO) LocalAlloc (LPTR, DEFAULT_CEI_BUFFER_SIZE);
  859. if (!lpCEI)
  860. {
  861. Error = GetLastError ();
  862. goto quit;
  863. }
  864. while (TRUE)
  865. {
  866. hso->hEnum = FindFirstUrlCacheEntry (hso->lpszPrefixedUrl,
  867. lpCEI,
  868. &cbCEI);
  869. if (!hso->hEnum)
  870. {
  871. Error = GetLastError ();
  872. if (Error == ERROR_NOT_ENOUGH_MEMORY)
  873. {
  874. LocalFree (lpCEI);
  875. lpCEI = (LPCACHE_ENTRY_INFO) LocalAlloc (LPTR, cbCEI);
  876. if (!lpCEI)
  877. {
  878. Error = ERROR_INTERNAL_ERROR;
  879. goto quit;
  880. }
  881. }
  882. else
  883. goto quit;
  884. }
  885. else break;
  886. }
  887. found = TRUE;
  888. //BUGBUG have to handle enum of fragments
  889. Error = GetFragmentsFromCEI (lpCEI, &(hso->aFrags), &(hso->cFrags));
  890. switch (Error)
  891. {
  892. case ERROR_FILE_NOT_FOUND: //only the default URL is used
  893. Error = ERROR_SUCCESS;
  894. break;
  895. case ERROR_SUCCESS: //first return the default URL next call will get frags
  896. hso->lpCEI = lpCEI;
  897. break;
  898. default:
  899. goto quit;
  900. break;
  901. }
  902. if (hso->lpszFragment)
  903. {
  904. found = FALSE;
  905. for (; hso->iFrags < hso->cFrags; hso->iFrags++)
  906. {
  907. if (strncmp (hso->aFrags[hso->iFrags], hso->lpszFragment, lstrlen (hso->lpszFragment)) == 0)
  908. {
  909. found = TRUE;
  910. lpszFoundFragment = hso->aFrags[hso->iFrags];
  911. break;
  912. }
  913. }
  914. }
  915. if (!found)
  916. {
  917. Error = ERROR_FILE_NOT_FOUND;
  918. goto quit;
  919. }
  920. Error = CopyCEItoHII (
  921. lpszFoundFragment,
  922. lpFirstHistoryItemInfo,
  923. lpdwFirstHistoryItemInfoBufferSize,
  924. lpCEI);
  925. quit:
  926. if (Error != ERROR_SUCCESS)
  927. {
  928. SetLastError (Error);
  929. if (hso->lpszPrefixedUrl)
  930. LocalFree (hso->lpszPrefixedUrl);
  931. if (hso->aFrags)
  932. LocalFree (hso->aFrags);
  933. if (hso->lpCEI)
  934. {
  935. UnlockUrlCacheEntryFile (hso->lpCEI->lpszSourceUrlName, 0);
  936. LocalFree(hso->lpCEI);
  937. }
  938. if (hso)
  939. LocalFree (hso);
  940. return NULL;
  941. }
  942. if (lpCEI && !hso->lpCEI)
  943. LocalFree (lpCEI);
  944. return (HANDLE) hso;
  945. }
  946. HISTORYAPI_(BOOL)
  947. FindNextHistoryItem(
  948. IN HANDLE hEnumHandle,
  949. OUT LPHISTORY_ITEM_INFO lpHistoryItemInfo,
  950. IN OUT LPDWORD lpdwHistoryItemInfoBufferSize
  951. )
  952. /*++
  953. Routine Description:
  954. Searches through the History looking for URLs that match the search pattern,
  955. and copies the HISTORY_ITEM_INFO into the buffer.
  956. Arguments:
  957. lpszUrlSearchPattern - The URL in question.
  958. lpFirstHistoryItemInfo - Buffer that will hold the HISTORY_ITEM_INFO
  959. lpdwFirstHistoryItemInfoBufferSize - IN: size of the lpHistoryItemInfo buffer
  960. OUT: size of filled struct when successful
  961. or necessary buffer size when failed
  962. Return Value:
  963. HANDLE
  964. Success - Valid enumeration handle to pass into subsequent calls to
  965. FindNextHistoryItem ().
  966. Failure - NULL. Extended error can be retrieved from GetLastError()
  967. ERROR_NOT_ENOUGH_MEMORY indicates the buffer is insufficient
  968. --*/
  969. {
  970. DWORD Error = ERROR_SUCCESS;
  971. LPCACHE_ENTRY_INFO lpCEI = NULL;
  972. DWORD cbCEI = 0;
  973. LPHISTORY_SEARCH_OBJ hso = NULL;
  974. BOOL found = FALSE;
  975. LPTSTR lpszFoundFragment;
  976. if (!hEnumHandle)
  977. {
  978. SetLastError (ERROR_INVALID_PARAMETER);
  979. return FALSE;
  980. }
  981. hso = (LPHISTORY_SEARCH_OBJ) hEnumHandle;
  982. while (!found)
  983. {
  984. if (hso->aFrags)
  985. {
  986. //this means that there are only fragments to find
  987. for (lpszFoundFragment = NULL; hso->iFrags < hso->cFrags; hso->iFrags++)
  988. {
  989. if (hso->lpszFragment)
  990. {
  991. if (strncmp (hso->aFrags[hso->iFrags], hso->lpszFragment, lstrlen (hso->lpszFragment)) == 0)
  992. {
  993. found = TRUE;
  994. lpCEI = hso->lpCEI;
  995. break;
  996. }
  997. }
  998. else
  999. {
  1000. found = TRUE;
  1001. break;
  1002. }
  1003. }
  1004. if (!found)
  1005. {
  1006. if (hso->lpszFragment)
  1007. {
  1008. Error = ERROR_FILE_NOT_FOUND;
  1009. goto quit;
  1010. }
  1011. else
  1012. {
  1013. //this means that we went through all the frags
  1014. //we need to drop through and find the Cache Entry that matches
  1015. Error = ERROR_SUCCESS;
  1016. ASSERT (hso->lpCEI);
  1017. ASSERT (hso->aFrags);
  1018. lpCEI = hso->lpCEI; //reuse the buffer if possible
  1019. LocalFree (hso->aFrags);
  1020. hso->lpCEI = NULL;
  1021. hso->aFrags = NULL;
  1022. }
  1023. }
  1024. else
  1025. {
  1026. lpszFoundFragment = hso->aFrags[hso->iFrags];
  1027. lpCEI = hso->lpCEI;
  1028. }
  1029. }
  1030. else
  1031. {
  1032. if (!lpCEI)
  1033. lpCEI = (LPCACHE_ENTRY_INFO) LocalAlloc (LPTR, DEFAULT_CEI_BUFFER_SIZE);
  1034. if (!lpCEI)
  1035. {
  1036. Error = ERROR_INTERNAL_ERROR;
  1037. goto quit;
  1038. }
  1039. while (TRUE)
  1040. {
  1041. if (!FindNextUrlCacheEntry (hso->hEnum,
  1042. lpCEI,
  1043. &cbCEI))
  1044. {
  1045. Error = GetLastError ();
  1046. if (Error == ERROR_NOT_ENOUGH_MEMORY)
  1047. {
  1048. LocalFree (lpCEI);
  1049. lpCEI = (LPCACHE_ENTRY_INFO) LocalAlloc (LPTR, cbCEI);
  1050. if (!lpCEI)
  1051. {
  1052. Error = ERROR_INTERNAL_ERROR;
  1053. goto quit;
  1054. }
  1055. }
  1056. else
  1057. goto quit;
  1058. }
  1059. else
  1060. break;
  1061. }
  1062. Error = GetFragmentsFromCEI (lpCEI, &(hso->aFrags), &(hso->cFrags));
  1063. switch (Error)
  1064. {
  1065. case ERROR_FILE_NOT_FOUND: //only the default URL is used
  1066. found = TRUE;
  1067. Error = ERROR_SUCCESS;
  1068. break;
  1069. case ERROR_SUCCESS: //first return the default URL next call will get frags
  1070. hso->lpCEI = lpCEI;
  1071. found = TRUE;
  1072. break;
  1073. default:
  1074. goto quit;
  1075. break;
  1076. }
  1077. }
  1078. }
  1079. Error = CopyCEItoHII(
  1080. lpszFoundFragment,
  1081. lpHistoryItemInfo,
  1082. lpdwHistoryItemInfoBufferSize,
  1083. lpCEI);
  1084. quit:
  1085. if (lpCEI && !hso->lpCEI)
  1086. {
  1087. UnlockUrlCacheEntryFile (lpCEI->lpszSourceUrlName, 0);
  1088. LocalFree (lpCEI);
  1089. }
  1090. if (Error != ERROR_SUCCESS)
  1091. {
  1092. SetLastError (Error);
  1093. return FALSE;
  1094. }
  1095. else
  1096. return TRUE;
  1097. }
  1098. HISTORYAPI_(BOOL)
  1099. FindCloseHistory (
  1100. IN HANDLE hEnumHandle
  1101. )
  1102. {
  1103. LPHISTORY_SEARCH_OBJ hso;
  1104. HANDLE hEnum;
  1105. //possibly we should be keeping track of valid hso's i dunno
  1106. if (!hEnumHandle)
  1107. {
  1108. SetLastError (ERROR_INVALID_PARAMETER);
  1109. return FALSE;
  1110. }
  1111. hso = (LPHISTORY_SEARCH_OBJ) hEnumHandle;
  1112. hEnum = hso->hEnum;
  1113. if (hso->aFrags)
  1114. LocalFree (hso->aFrags);
  1115. if (hso->lpszPrefixedUrl)
  1116. LocalFree(hso->lpszPrefixedUrl);
  1117. if (hso->lpCEI)
  1118. {
  1119. LocalFree (hso->lpCEI);
  1120. }
  1121. LocalFree (hso);
  1122. return FindCloseUrlCache (hEnum);
  1123. }
  1124. BOOL
  1125. DLLHistoryEntry(
  1126. IN HINSTANCE DllHandle,
  1127. IN DWORD Reason,
  1128. IN LPVOID Reserved
  1129. )
  1130. /*++
  1131. Routine Description:
  1132. Performs global initialization and termination for all protocol modules.
  1133. This function only handles process attach and detach which are required for
  1134. global initialization and termination, respectively. We disable thread
  1135. attach and detach. New threads calling Wininet APIs will get an
  1136. INTERNET_THREAD_INFO structure created for them by the first API requiring
  1137. this structure
  1138. Arguments:
  1139. DllHandle - handle of this DLL. Unused
  1140. Reason - process attach/detach or thread attach/detach
  1141. Reserved - if DLL_PROCESS_ATTACH, NULL means DLL is being dynamically
  1142. loaded, else static. For DLL_PROCESS_DETACH, NULL means DLL
  1143. is being freed as a consequence of call to FreeLibrary()
  1144. else the DLL is being freed as part of process termination
  1145. Return Value:
  1146. BOOL
  1147. Success - TRUE
  1148. Failure - FALSE. Failed to initialize
  1149. --*/
  1150. {
  1151. BOOL ok;
  1152. DWORD error;
  1153. // UNREFERENCED_PARAMETER(DllHandle);
  1154. //
  1155. // perform global dll initialization, if any.
  1156. //
  1157. switch (Reason) {
  1158. case DLL_PROCESS_ATTACH:
  1159. // error = DllProcessAttachDiskCache();
  1160. //
  1161. // we switch off thread library calls to avoid taking a hit for every
  1162. // thread creation/termination that happens in this process, regardless
  1163. // of whether Internet APIs are called in the thread.
  1164. //
  1165. // If a new thread does make Internet API calls that require a per-thread
  1166. // structure then the individual API will create one
  1167. //
  1168. // DisableThreadLibraryCalls(DllHandle);
  1169. break;
  1170. case DLL_PROCESS_DETACH:
  1171. if (Reserved != NULL) {
  1172. //
  1173. // Only Cleanup if there is a FreeLibrary() call.
  1174. //
  1175. break;
  1176. }
  1177. // DllProcessDetachDiskCache();
  1178. break;
  1179. }
  1180. return (TRUE);
  1181. }