push ac8730bd9057ca84ecf262ddc5d43fb7b5849da7
[wine/hacks.git] / dlls / wininet / urlcache.c
blob1d1beaf4c260cdcc364f15b97481d8c4ae344e49
1 /*
2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003-2008 Robert Shearman
7 * Eric Kohl
8 * Aric Stewart
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
26 #include "wine/port.h"
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <time.h>
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winuser.h"
40 #include "wininet.h"
41 #include "winineti.h"
42 #include "winerror.h"
43 #include "internet.h"
44 #include "winreg.h"
45 #include "shlwapi.h"
46 #include "shlobj.h"
48 #include "wine/unicode.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
53 #define ENTRY_START_OFFSET 0x4000
54 #define DIR_LENGTH 8
55 #define BLOCKSIZE 128
56 #define HASHTABLE_SIZE 448
57 #define HASHTABLE_BLOCKSIZE 7
58 #define HASHTABLE_FREE 3
59 #define ALLOCATION_TABLE_OFFSET 0x250
60 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
61 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
62 #define NEWFILE_NUM_BLOCKS 0xd80
63 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
65 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
66 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
67 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
68 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
69 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
71 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
73 typedef struct _CACHEFILE_ENTRY
75 /* union
76 {*/
77 DWORD dwSignature; /* e.g. "URL " */
78 /* CHAR szSignature[4];
79 };*/
80 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
81 } CACHEFILE_ENTRY;
83 typedef struct _URL_CACHEFILE_ENTRY
85 CACHEFILE_ENTRY CacheFileEntry;
86 FILETIME LastModifiedTime;
87 FILETIME LastAccessTime;
88 WORD wExpiredDate; /* expire date in dos format */
89 WORD wExpiredTime; /* expire time in dos format */
90 DWORD dwUnknown1; /* usually zero */
91 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
92 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
93 DWORD dwUnknown2; /* usually zero */
94 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
95 DWORD dwUnknown3; /* usually 0x60 */
96 DWORD dwOffsetUrl; /* offset of start of url from start of entry */
97 BYTE CacheDir; /* index of cache directory this url is stored in */
98 BYTE Unknown4; /* usually zero */
99 WORD wUnknown5; /* usually 0x1010 */
100 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
101 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
102 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
103 DWORD dwHeaderInfoSize;
104 DWORD dwOffsetFileExtension; /* offset of start of file extension from start of entry */
105 WORD wLastSyncDate; /* last sync date in dos format */
106 WORD wLastSyncTime; /* last sync time in dos format */
107 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
108 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
109 WORD wUnknownDate; /* usually same as wLastSyncDate */
110 WORD wUnknownTime; /* usually same as wLastSyncTime */
111 DWORD dwUnknown7; /* usually zero */
112 DWORD dwUnknown8; /* usually zero */
113 /* packing to dword align start of next field */
114 /* CHAR szSourceUrlName[]; (url) */
115 /* packing to dword align start of next field */
116 /* CHAR szLocalFileName[]; (local file name excluding path) */
117 /* packing to dword align start of next field */
118 /* CHAR szHeaderInfo[]; (header info) */
119 } URL_CACHEFILE_ENTRY;
121 struct _HASH_ENTRY
123 DWORD dwHashKey;
124 DWORD dwOffsetEntry;
127 typedef struct _HASH_CACHEFILE_ENTRY
129 CACHEFILE_ENTRY CacheFileEntry;
130 DWORD dwAddressNext;
131 DWORD dwHashTableNumber;
132 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
133 } HASH_CACHEFILE_ENTRY;
135 typedef struct _DIRECTORY_DATA
137 DWORD dwUnknown;
138 char filename[DIR_LENGTH];
139 } DIRECTORY_DATA;
141 typedef struct _URLCACHE_HEADER
143 char szSignature[28];
144 DWORD dwFileSize;
145 DWORD dwOffsetFirstHashTable;
146 DWORD dwIndexCapacityInBlocks;
147 DWORD dwBlocksInUse;
148 DWORD dwUnknown1;
149 DWORD dwCacheLimitLow; /* disk space limit for cache */
150 DWORD dwCacheLimitHigh; /* disk space limit for cache */
151 DWORD dwUnknown4; /* current disk space usage for cache */
152 DWORD dwUnknown5; /* current disk space usage for cache */
153 DWORD dwUnknown6; /* possibly a flag? */
154 DWORD dwUnknown7;
155 BYTE DirectoryCount; /* number of directory_data's */
156 BYTE Unknown8[3]; /* just padding? */
157 DIRECTORY_DATA directory_data[1]; /* first directory entry */
158 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
159 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
161 typedef struct _STREAM_HANDLE
163 HANDLE hFile;
164 CHAR lpszUrl[1];
165 } STREAM_HANDLE;
167 typedef struct _URLCACHECONTAINER
169 struct list entry; /* part of a list */
170 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
171 LPWSTR path; /* path to url container directory */
172 HANDLE hMapping; /* handle of file mapping */
173 DWORD file_size; /* size of file when mapping was opened */
174 HANDLE hMutex; /* handle of mutex */
175 } URLCACHECONTAINER;
178 /* List of all containers available */
179 static struct list UrlContainers = LIST_INIT(UrlContainers);
181 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash);
183 /***********************************************************************
184 * URLCache_PathToObjectName (Internal)
186 * Converts a path to a name suitable for use as a Win32 object name.
187 * Replaces '\\' characters in-place with the specified character
188 * (usually '_' or '!')
190 * RETURNS
191 * nothing
194 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
196 for (; *lpszPath; lpszPath++)
198 if (*lpszPath == '\\')
199 *lpszPath = replace;
203 /***********************************************************************
204 * URLCacheContainer_OpenIndex (Internal)
206 * Opens the index file and saves mapping handle in hCacheIndexMapping
208 * RETURNS
209 * ERROR_SUCCESS if succeeded
210 * Any other Win32 error code if failed
213 static DWORD URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
215 HANDLE hFile;
216 WCHAR wszFilePath[MAX_PATH];
217 DWORD dwFileSize;
219 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
220 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
222 if (pContainer->hMapping)
223 return ERROR_SUCCESS;
225 strcpyW(wszFilePath, pContainer->path);
226 strcatW(wszFilePath, wszIndex);
228 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
229 if (hFile == INVALID_HANDLE_VALUE)
231 /* Maybe the directory wasn't there? Try to create it */
232 if (CreateDirectoryW(pContainer->path, 0))
233 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
235 if (hFile == INVALID_HANDLE_VALUE)
237 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath));
238 return GetLastError();
241 /* At this stage we need the mutex because we may be about to create the
242 * file.
244 WaitForSingleObject(pContainer->hMutex, INFINITE);
246 dwFileSize = GetFileSize(hFile, NULL);
247 if (dwFileSize == INVALID_FILE_SIZE)
249 ReleaseMutex(pContainer->hMutex);
250 return GetLastError();
253 if (dwFileSize == 0)
255 static const CHAR szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content";
256 HKEY key;
257 char achZeroes[0x1000];
258 DWORD dwOffset;
259 DWORD dwError = ERROR_SUCCESS;
261 /* Write zeroes to the entire file so we can safely map it without
262 * fear of getting a SEGV because the disk is full.
264 memset(achZeroes, 0, sizeof(achZeroes));
265 for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes))
267 DWORD dwWrite = sizeof(achZeroes);
268 DWORD dwWritten;
270 if (NEWFILE_SIZE - dwOffset < dwWrite)
271 dwWrite = NEWFILE_SIZE - dwOffset;
272 if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) ||
273 dwWritten != dwWrite)
275 /* If we fail to write, we need to return the error that
276 * cause the problem and also make sure the file is no
277 * longer there, if possible.
279 dwError = GetLastError();
281 break;
285 if (dwError == ERROR_SUCCESS)
287 HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL);
289 if (hMapping)
291 URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE);
293 if (pHeader)
295 WCHAR *pwchDir;
296 WCHAR wszDirPath[MAX_PATH];
297 FILETIME ft;
298 int i, j;
299 HASH_CACHEFILE_ENTRY *pHashEntry;
301 dwFileSize = NEWFILE_SIZE;
303 /* First set some constants and defaults in the header */
304 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
305 pHeader->dwFileSize = dwFileSize;
306 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
307 /* 127MB - taken from default for Windows 2000 */
308 pHeader->dwCacheLimitHigh = 0;
309 pHeader->dwCacheLimitLow = 0x07ff5400;
310 /* Copied from a Windows 2000 cache index */
311 pHeader->DirectoryCount = 4;
313 /* If the registry has a cache size set, use the registry value */
314 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
316 DWORD dw;
317 DWORD len = sizeof(dw);
318 DWORD keytype;
320 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
321 (BYTE *) &dw, &len) == ERROR_SUCCESS &&
322 keytype == REG_DWORD)
324 pHeader->dwCacheLimitHigh = (dw >> 22);
325 pHeader->dwCacheLimitLow = dw << 10;
327 RegCloseKey(key);
330 URLCache_CreateHashTable(pHeader, NULL, &pHashEntry);
332 /* Last step - create the directories */
334 strcpyW(wszDirPath, pContainer->path);
335 pwchDir = wszDirPath + strlenW(wszDirPath);
336 pwchDir[8] = 0;
338 GetSystemTimeAsFileTime(&ft);
340 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
342 /* The following values were copied from a Windows index.
343 * I don't know what the values are supposed to mean but
344 * have made them the same in the hope that this will
345 * be better for compatibility
347 pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
348 for (j = 0;; ++j)
350 int k;
351 ULONGLONG n = ft.dwHighDateTime;
353 /* Generate a file name to attempt to create.
354 * This algorithm will create what will appear
355 * to be random and unrelated directory names
356 * of up to 9 characters in length.
358 n <<= 32;
359 n += ft.dwLowDateTime;
360 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
362 for (k = 0; k < 8; ++k)
364 int r = (n % 36);
366 /* Dividing by a prime greater than 36 helps
367 * with the appearance of randomness
369 n /= 37;
371 if (r < 10)
372 pwchDir[k] = '0' + r;
373 else
374 pwchDir[k] = 'A' + (r - 10);
377 if (CreateDirectoryW(wszDirPath, 0))
379 /* The following is OK because we generated an
380 * 8 character directory name made from characters
381 * [A-Z0-9], which are equivalent for all code
382 * pages and for UTF-16
384 for (k = 0; k < 8; ++k)
385 pHeader->directory_data[i].filename[k] = pwchDir[k];
386 break;
388 else if (j >= 255)
390 /* Give up. The most likely cause of this
391 * is a full disk, but whatever the cause
392 * is, it should be more than apparent that
393 * we won't succeed.
395 dwError = GetLastError();
396 break;
401 UnmapViewOfFile(pHeader);
403 else
405 dwError = GetLastError();
407 CloseHandle(hMapping);
409 else
411 dwError = GetLastError();
415 if (dwError)
417 CloseHandle(hFile);
418 DeleteFileW(wszFilePath);
419 ReleaseMutex(pContainer->hMutex);
420 return dwError;
425 ReleaseMutex(pContainer->hMutex);
427 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
428 URLCache_PathToObjectName(wszFilePath, '_');
429 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
430 if (!pContainer->hMapping)
431 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
432 CloseHandle(hFile);
433 if (!pContainer->hMapping)
435 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
436 return GetLastError();
439 return ERROR_SUCCESS;
442 /***********************************************************************
443 * URLCacheContainer_CloseIndex (Internal)
445 * Closes the index
447 * RETURNS
448 * nothing
451 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
453 CloseHandle(pContainer->hMapping);
454 pContainer->hMapping = NULL;
457 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
459 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
460 int path_len = strlenW(path);
461 int cache_prefix_len = strlenW(cache_prefix);
463 if (!pContainer)
465 return FALSE;
468 pContainer->hMapping = NULL;
469 pContainer->file_size = 0;
471 pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR));
472 if (!pContainer->path)
474 HeapFree(GetProcessHeap(), 0, pContainer);
475 return FALSE;
478 memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR));
480 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
481 if (!pContainer->cache_prefix)
483 HeapFree(GetProcessHeap(), 0, pContainer->path);
484 HeapFree(GetProcessHeap(), 0, pContainer);
485 return FALSE;
488 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
490 CharLowerW(mutex_name);
491 URLCache_PathToObjectName(mutex_name, '!');
493 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
495 ERR("couldn't create mutex (error is %d)\n", GetLastError());
496 HeapFree(GetProcessHeap(), 0, pContainer->path);
497 HeapFree(GetProcessHeap(), 0, pContainer);
498 return FALSE;
501 list_add_head(&UrlContainers, &pContainer->entry);
503 return TRUE;
506 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
508 list_remove(&pContainer->entry);
510 URLCacheContainer_CloseIndex(pContainer);
511 CloseHandle(pContainer->hMutex);
512 HeapFree(GetProcessHeap(), 0, pContainer->path);
513 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
514 HeapFree(GetProcessHeap(), 0, pContainer);
517 void URLCacheContainers_CreateDefaults(void)
519 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
520 static const WCHAR UrlPrefix[] = {0};
521 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
522 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
523 static const WCHAR CookieSuffix[] = {0};
524 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
525 static const struct
527 int nFolder; /* CSIDL_* constant */
528 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
529 const WCHAR * cache_prefix; /* prefix used to reference the container */
530 } DefaultContainerData[] =
532 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
533 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
534 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
536 DWORD i;
538 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
540 WCHAR wszCachePath[MAX_PATH];
541 WCHAR wszMutexName[MAX_PATH];
542 int path_len, suffix_len;
544 if (!SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE))
546 ERR("Couldn't get path for default container %u\n", i);
547 continue;
549 path_len = strlenW(wszCachePath);
550 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
552 if (path_len + suffix_len + 2 > MAX_PATH)
554 ERR("Path too long\n");
555 continue;
558 wszCachePath[path_len] = '\\';
559 wszCachePath[path_len+1] = 0;
561 strcpyW(wszMutexName, wszCachePath);
563 if (suffix_len)
565 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
566 wszCachePath[path_len + suffix_len + 1] = '\\';
567 wszCachePath[path_len + suffix_len + 2] = '\0';
570 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
574 void URLCacheContainers_DeleteAll(void)
576 while(!list_empty(&UrlContainers))
577 URLCacheContainer_DeleteContainer(
578 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
582 static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
584 URLCACHECONTAINER * pContainer;
586 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
588 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
590 int prefix_len = strlenW(pContainer->cache_prefix);
591 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
593 TRACE("found container with prefix %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
594 *ppContainer = pContainer;
595 return ERROR_SUCCESS;
598 ERR("no container found\n");
599 return ERROR_FILE_NOT_FOUND;
602 static DWORD URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
604 DWORD ret;
605 LPWSTR lpwszUrl;
606 int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
607 if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR))))
609 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len);
610 ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer);
611 HeapFree(GetProcessHeap(), 0, lpwszUrl);
612 return ret;
614 return GetLastError();
617 static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, URLCACHECONTAINER ** ppContainer)
619 DWORD i = 0;
620 URLCACHECONTAINER * pContainer;
622 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern));
624 /* non-NULL search pattern only returns one container ever */
625 if (lpwszSearchPattern && dwIndex > 0)
626 return FALSE;
628 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
630 if (lpwszSearchPattern)
632 if (!strcmpW(pContainer->cache_prefix, lpwszSearchPattern))
634 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
635 *ppContainer = pContainer;
636 return TRUE;
639 else
641 if (i == dwIndex)
643 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
644 *ppContainer = pContainer;
645 return TRUE;
648 i++;
650 return FALSE;
653 /***********************************************************************
654 * URLCacheContainer_LockIndex (Internal)
656 * Locks the index for system-wide exclusive access.
658 * RETURNS
659 * Cache file header if successful
660 * NULL if failed and calls SetLastError.
662 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
664 BYTE index;
665 LPVOID pIndexData;
666 URLCACHE_HEADER * pHeader;
667 DWORD error;
669 /* acquire mutex */
670 WaitForSingleObject(pContainer->hMutex, INFINITE);
672 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
674 if (!pIndexData)
676 ReleaseMutex(pContainer->hMutex);
677 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
678 return NULL;
680 pHeader = (URLCACHE_HEADER *)pIndexData;
682 /* file has grown - we need to remap to prevent us getting
683 * access violations when we try and access beyond the end
684 * of the memory mapped file */
685 if (pHeader->dwFileSize != pContainer->file_size)
687 URLCacheContainer_CloseIndex(pContainer);
688 error = URLCacheContainer_OpenIndex(pContainer);
689 if (error != ERROR_SUCCESS)
691 ReleaseMutex(pContainer->hMutex);
692 SetLastError(error);
693 return NULL;
695 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
697 if (!pIndexData)
699 ReleaseMutex(pContainer->hMutex);
700 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
701 return NULL;
703 pHeader = (URLCACHE_HEADER *)pIndexData;
706 TRACE("Signature: %s, file size: %d bytes\n", pHeader->szSignature, pHeader->dwFileSize);
708 for (index = 0; index < pHeader->DirectoryCount; index++)
710 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
713 return pHeader;
716 /***********************************************************************
717 * URLCacheContainer_UnlockIndex (Internal)
720 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
722 /* release mutex */
723 ReleaseMutex(pContainer->hMutex);
724 return UnmapViewOfFile(pHeader);
728 #ifndef CHAR_BIT
729 #define CHAR_BIT (8 * sizeof(CHAR))
730 #endif
732 /***********************************************************************
733 * URLCache_Allocation_BlockIsFree (Internal)
735 * Is the specified block number free?
737 * RETURNS
738 * zero if free
739 * non-zero otherwise
742 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
744 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
745 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
748 /***********************************************************************
749 * URLCache_Allocation_BlockFree (Internal)
751 * Marks the specified block as free
753 * RETURNS
754 * nothing
757 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
759 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
760 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
763 /***********************************************************************
764 * URLCache_Allocation_BlockAllocate (Internal)
766 * Marks the specified block as allocated
768 * RETURNS
769 * nothing
772 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
774 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
775 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
778 /***********************************************************************
779 * URLCache_FindFirstFreeEntry (Internal)
781 * Finds and allocates the first block of free space big enough and
782 * sets ppEntry to point to it.
784 * RETURNS
785 * TRUE if it had enough space
786 * FALSE if it couldn't find enough space
789 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
791 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
792 DWORD dwBlockNumber;
793 DWORD dwFreeCounter;
794 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
796 for (dwFreeCounter = 0;
797 dwFreeCounter < dwBlocksNeeded &&
798 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
799 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
800 dwFreeCounter++)
801 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
803 if (dwFreeCounter == dwBlocksNeeded)
805 DWORD index;
806 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
807 for (index = 0; index < dwBlocksNeeded; index++)
808 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
809 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
810 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
811 return TRUE;
814 FIXME("Grow file\n");
815 return FALSE;
818 /***********************************************************************
819 * URLCache_DeleteEntry (Internal)
821 * Deletes the specified entry and frees the space allocated to it
823 * RETURNS
824 * TRUE if it succeeded
825 * FALSE if it failed
828 static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, CACHEFILE_ENTRY * pEntry)
830 DWORD dwStartBlock;
831 DWORD dwBlock;
832 BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
834 /* update allocation table */
835 dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE;
836 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
837 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
839 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
840 return TRUE;
843 /***********************************************************************
844 * URLCache_LocalFileNameToPathW (Internal)
846 * Copies the full path to the specified buffer given the local file
847 * name and the index of the directory it is in. Always sets value in
848 * lpBufferSize to the required buffer size (in bytes).
850 * RETURNS
851 * TRUE if the buffer was big enough
852 * FALSE if the buffer was too small
855 static BOOL URLCache_LocalFileNameToPathW(
856 const URLCACHECONTAINER * pContainer,
857 LPCURLCACHE_HEADER pHeader,
858 LPCSTR szLocalFileName,
859 BYTE Directory,
860 LPWSTR wszPath,
861 LPLONG lpBufferSize)
863 LONG nRequired;
864 int path_len = strlenW(pContainer->path);
865 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
866 if (Directory >= pHeader->DirectoryCount)
868 *lpBufferSize = 0;
869 return FALSE;
872 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
873 if (nRequired < *lpBufferSize)
875 int dir_len;
877 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
878 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
879 wszPath[dir_len + path_len] = '\\';
880 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
881 *lpBufferSize = nRequired;
882 return TRUE;
884 *lpBufferSize = nRequired;
885 return FALSE;
888 /***********************************************************************
889 * URLCache_LocalFileNameToPathA (Internal)
891 * Copies the full path to the specified buffer given the local file
892 * name and the index of the directory it is in. Always sets value in
893 * lpBufferSize to the required buffer size.
895 * RETURNS
896 * TRUE if the buffer was big enough
897 * FALSE if the buffer was too small
900 static BOOL URLCache_LocalFileNameToPathA(
901 const URLCACHECONTAINER * pContainer,
902 LPCURLCACHE_HEADER pHeader,
903 LPCSTR szLocalFileName,
904 BYTE Directory,
905 LPSTR szPath,
906 LPLONG lpBufferSize)
908 LONG nRequired;
909 int path_len, file_name_len, dir_len;
911 if (Directory >= pHeader->DirectoryCount)
913 *lpBufferSize = 0;
914 return FALSE;
917 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL) - 1;
918 file_name_len = strlen(szLocalFileName) + 1 /* for nul-terminator */;
919 dir_len = DIR_LENGTH;
921 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(char);
922 if (nRequired < *lpBufferSize)
924 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, path_len, NULL, NULL);
925 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
926 szPath[path_len + dir_len] = '\\';
927 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
928 *lpBufferSize = nRequired;
929 return TRUE;
931 *lpBufferSize = nRequired;
932 return FALSE;
935 /***********************************************************************
936 * URLCache_CopyEntry (Internal)
938 * Copies an entry from the cache index file to the Win32 structure
940 * RETURNS
941 * ERROR_SUCCESS if the buffer was big enough
942 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
945 static DWORD URLCache_CopyEntry(
946 URLCACHECONTAINER * pContainer,
947 LPCURLCACHE_HEADER pHeader,
948 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
949 LPDWORD lpdwBufferSize,
950 const URL_CACHEFILE_ENTRY * pUrlEntry,
951 BOOL bUnicode)
953 int lenUrl;
954 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
956 if (*lpdwBufferSize >= dwRequiredSize)
958 lpCacheEntryInfo->lpHeaderInfo = NULL;
959 lpCacheEntryInfo->lpszFileExtension = NULL;
960 lpCacheEntryInfo->lpszLocalFileName = NULL;
961 lpCacheEntryInfo->lpszSourceUrlName = NULL;
962 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
963 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
964 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
965 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
966 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
967 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
968 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
969 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
970 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
971 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
972 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
973 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
974 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
975 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
978 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
979 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
980 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
981 if (bUnicode)
982 lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0);
983 else
984 lenUrl = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
985 dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
987 /* FIXME: is source url optional? */
988 if (*lpdwBufferSize >= dwRequiredSize)
990 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrl - 1;
991 if (bUnicode)
992 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
993 else
994 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, (lenUrl + 1) * sizeof(CHAR));
997 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
998 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
999 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1001 if (pUrlEntry->dwOffsetLocalName)
1003 LONG nLocalFilePathSize;
1004 LPSTR lpszLocalFileName;
1005 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
1006 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
1007 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
1008 (!bUnicode && URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize)))
1010 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
1012 dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ;
1014 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1015 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1016 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1018 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
1020 if (*lpdwBufferSize >= dwRequiredSize)
1022 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
1023 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
1024 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
1026 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1027 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1028 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1030 if (pUrlEntry->dwOffsetFileExtension)
1032 int lenExtension;
1034 if (bUnicode)
1035 lenExtension = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, NULL, 0);
1036 else
1037 lenExtension = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension) + 1;
1038 dwRequiredSize += lenExtension * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
1040 if (*lpdwBufferSize >= dwRequiredSize)
1042 lpCacheEntryInfo->lpszFileExtension = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenExtension;
1043 if (bUnicode)
1044 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenExtension);
1045 else
1046 memcpy(lpCacheEntryInfo->lpszFileExtension, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, lenExtension * sizeof(CHAR));
1049 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1050 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1051 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1054 if (dwRequiredSize > *lpdwBufferSize)
1056 *lpdwBufferSize = dwRequiredSize;
1057 return ERROR_INSUFFICIENT_BUFFER;
1059 *lpdwBufferSize = dwRequiredSize;
1060 return ERROR_SUCCESS;
1064 /***********************************************************************
1065 * URLCache_SetEntryInfo (Internal)
1067 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1068 * according to the flags set by dwFieldControl.
1070 * RETURNS
1071 * ERROR_SUCCESS if the buffer was big enough
1072 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1075 static DWORD URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1077 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1078 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1079 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1080 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1081 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1082 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1083 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1084 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1085 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1086 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1087 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1088 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1089 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1090 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1091 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1092 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1094 return ERROR_SUCCESS;
1097 /***********************************************************************
1098 * URLCache_HashKey (Internal)
1100 * Returns the hash key for a given string
1102 * RETURNS
1103 * hash key for the string
1106 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1108 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1109 * but the algorithm and result are not the same!
1111 static const unsigned char lookupTable[256] =
1113 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1114 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1115 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1116 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1117 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1118 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1119 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1120 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1121 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1122 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1123 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1124 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1125 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1126 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1127 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1128 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1129 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1130 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1131 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1132 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1133 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1134 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1135 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1136 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1137 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1138 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1139 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1140 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1141 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1142 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1143 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1144 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1146 BYTE key[4];
1147 DWORD i;
1149 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1150 key[i] = lookupTable[i];
1152 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
1154 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1155 key[i] = lookupTable[*lpszKey ^ key[i]];
1158 return *(DWORD *)key;
1161 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
1163 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
1166 static inline BOOL URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY *pHashEntry)
1168 /* check pHashEntry located within acceptable bounds in the URL cache mapping */
1169 return ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) &&
1170 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1173 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1175 /* structure of hash table:
1176 * 448 entries divided into 64 blocks
1177 * each block therefore contains a chain of 7 key/offset pairs
1178 * how position in table is calculated:
1179 * 1. the url is hashed in helper function
1180 * 2. the key % 64 * 8 is the offset
1181 * 3. the key in the hash table is the hash key aligned to 64
1183 * note:
1184 * there can be multiple hash tables in the file and the offset to
1185 * the next one is stored in the header of the hash table
1187 DWORD key = URLCache_HashKey(lpszUrl);
1188 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1189 HASH_CACHEFILE_ENTRY * pHashEntry;
1190 DWORD dwHashTableNumber = 0;
1192 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1194 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1195 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1196 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1198 int i;
1199 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1201 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1202 continue;
1204 /* make sure that it is in fact a hash entry */
1205 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1207 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1208 continue;
1211 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1213 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1214 if (key == (pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
1216 /* FIXME: we should make sure that this is the right element
1217 * before returning and claiming that it is. We can do this
1218 * by doing a simple compare between the URL we were given
1219 * and the URL stored in the entry. However, this assumes
1220 * we know the format of all the entries stored in the
1221 * hash table */
1222 *ppHashEntry = pHashElement;
1223 return TRUE;
1227 return FALSE;
1230 static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1232 LPSTR urlA;
1233 int url_len;
1234 BOOL ret;
1236 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1237 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1238 if (!urlA)
1240 SetLastError(ERROR_OUTOFMEMORY);
1241 return FALSE;
1243 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, urlA, url_len, NULL, NULL);
1244 ret = URLCache_FindHash(pHeader, urlA, ppHashEntry);
1245 HeapFree(GetProcessHeap(), 0, urlA);
1246 return ret;
1249 /***********************************************************************
1250 * URLCache_HashEntrySetUse (Internal)
1252 * Searches all the hash tables in the index for the given URL and
1253 * sets the use count (stored or'ed with key)
1255 * RETURNS
1256 * TRUE if the entry was found
1257 * FALSE if the entry could not be found
1260 static BOOL URLCache_HashEntrySetUse(struct _HASH_ENTRY * pHashEntry, DWORD dwUseCount)
1262 pHashEntry->dwHashKey = dwUseCount | (pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1263 return TRUE;
1266 /***********************************************************************
1267 * URLCache_DeleteEntryFromHash (Internal)
1269 * Searches all the hash tables in the index for the given URL and
1270 * then if found deletes the entry.
1272 * RETURNS
1273 * TRUE if the entry was found
1274 * FALSE if the entry could not be found
1277 static BOOL URLCache_DeleteEntryFromHash(struct _HASH_ENTRY * pHashEntry)
1279 pHashEntry->dwHashKey = HASHTABLE_FREE;
1280 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1281 return TRUE;
1284 /***********************************************************************
1285 * URLCache_AddEntryToHash (Internal)
1287 * Searches all the hash tables for a free slot based on the offset
1288 * generated from the hash key. If a free slot is found, the offset and
1289 * key are entered into the hash table.
1291 * RETURNS
1292 * ERROR_SUCCESS if the entry was added
1293 * Any other Win32 error code if the entry could not be added
1296 static DWORD URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1298 /* see URLCache_FindEntryInHash for structure of hash tables */
1300 DWORD key = URLCache_HashKey(lpszUrl);
1301 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1302 HASH_CACHEFILE_ENTRY * pHashEntry;
1303 DWORD dwHashTableNumber = 0;
1304 DWORD error;
1306 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1308 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1309 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1310 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1312 int i;
1313 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1315 ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1316 break;
1318 /* make sure that it is in fact a hash entry */
1319 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1321 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1322 break;
1325 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1327 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1328 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1330 pHashElement->dwHashKey = key;
1331 pHashElement->dwOffsetEntry = dwOffsetEntry;
1332 return ERROR_SUCCESS;
1336 error = URLCache_CreateHashTable(pHeader, pHashEntry, &pHashEntry);
1337 if (error != ERROR_SUCCESS)
1338 return error;
1340 pHashEntry->HashTable[offset].dwHashKey = key;
1341 pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry;
1342 return ERROR_SUCCESS;
1345 /***********************************************************************
1346 * URLCache_CreateHashTable (Internal)
1348 * Creates a new hash table in free space and adds it to the chain of existing
1349 * hash tables.
1351 * RETURNS
1352 * ERROR_SUCCESS if the hash table was created
1353 * ERROR_DISK_FULL if the hash table could not be created
1356 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash)
1358 DWORD dwOffset;
1359 int i;
1361 if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)ppHash))
1363 FIXME("no free space for hash table\n");
1364 return ERROR_DISK_FULL;
1367 dwOffset = (BYTE *)*ppHash - (BYTE *)pHeader;
1369 if (pPrevHash)
1370 pPrevHash->dwAddressNext = dwOffset;
1371 else
1372 pHeader->dwOffsetFirstHashTable = dwOffset;
1373 (*ppHash)->CacheFileEntry.dwSignature = HASH_SIGNATURE;
1374 (*ppHash)->CacheFileEntry.dwBlocksUsed = 0x20;
1375 (*ppHash)->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0;
1376 for (i = 0; i < HASHTABLE_SIZE; i++)
1378 (*ppHash)->HashTable[i].dwOffsetEntry = 0;
1379 (*ppHash)->HashTable[i].dwHashKey = HASHTABLE_FREE;
1381 return ERROR_SUCCESS;
1384 /***********************************************************************
1385 * URLCache_EnumHashTables (Internal)
1387 * Enumerates the hash tables in a container.
1389 * RETURNS
1390 * TRUE if an entry was found
1391 * FALSE if there are no more tables to enumerate.
1394 static BOOL URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader, DWORD *pdwHashTableNumber, HASH_CACHEFILE_ENTRY ** ppHashEntry)
1396 for (*ppHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1397 URLCache_IsHashEntryValid(pHeader, *ppHashEntry);
1398 *ppHashEntry = URLCache_HashEntryFromOffset(pHeader, (*ppHashEntry)->dwAddressNext))
1400 TRACE("looking at hash table number %d\n", (*ppHashEntry)->dwHashTableNumber);
1401 if ((*ppHashEntry)->dwHashTableNumber != *pdwHashTableNumber)
1402 continue;
1403 /* make sure that it is in fact a hash entry */
1404 if ((*ppHashEntry)->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1406 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&(*ppHashEntry)->CacheFileEntry.dwSignature);
1407 (*pdwHashTableNumber)++;
1408 continue;
1411 TRACE("hash table number %d found\n", *pdwHashTableNumber);
1412 return TRUE;
1414 return FALSE;
1417 /***********************************************************************
1418 * URLCache_EnumHashTableEntries (Internal)
1420 * Enumerates entries in a hash table and returns the next non-free entry.
1422 * RETURNS
1423 * TRUE if an entry was found
1424 * FALSE if the hash table is empty or there are no more entries to
1425 * enumerate.
1428 static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY * pHashEntry,
1429 DWORD * index, const struct _HASH_ENTRY ** ppHashEntry)
1431 for (; *index < HASHTABLE_SIZE ; (*index)++)
1433 if (pHashEntry->HashTable[*index].dwHashKey == HASHTABLE_FREE)
1434 continue;
1436 *ppHashEntry = &pHashEntry->HashTable[*index];
1437 TRACE("entry found %d\n", *index);
1438 return TRUE;
1440 TRACE("no more entries (%d)\n", *index);
1441 return FALSE;
1444 /***********************************************************************
1445 * GetUrlCacheEntryInfoExA (WININET.@)
1448 BOOL WINAPI GetUrlCacheEntryInfoExA(
1449 LPCSTR lpszUrl,
1450 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1451 LPDWORD lpdwCacheEntryInfoBufSize,
1452 LPSTR lpszReserved,
1453 LPDWORD lpdwReserved,
1454 LPVOID lpReserved,
1455 DWORD dwFlags)
1457 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1458 debugstr_a(lpszUrl),
1459 lpCacheEntryInfo,
1460 lpdwCacheEntryInfoBufSize,
1461 lpszReserved,
1462 lpdwReserved,
1463 lpReserved,
1464 dwFlags);
1466 if ((lpszReserved != NULL) ||
1467 (lpdwReserved != NULL) ||
1468 (lpReserved != NULL))
1470 ERR("Reserved value was not 0\n");
1471 SetLastError(ERROR_INVALID_PARAMETER);
1472 return FALSE;
1474 if (dwFlags != 0)
1475 FIXME("Undocumented flag(s): %x\n", dwFlags);
1476 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1479 /***********************************************************************
1480 * GetUrlCacheEntryInfoA (WININET.@)
1483 BOOL WINAPI GetUrlCacheEntryInfoA(
1484 IN LPCSTR lpszUrlName,
1485 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1486 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1489 LPURLCACHE_HEADER pHeader;
1490 struct _HASH_ENTRY * pHashEntry;
1491 const CACHEFILE_ENTRY * pEntry;
1492 const URL_CACHEFILE_ENTRY * pUrlEntry;
1493 URLCACHECONTAINER * pContainer;
1494 DWORD error;
1496 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1498 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1499 if (error != ERROR_SUCCESS)
1501 SetLastError(error);
1502 return FALSE;
1505 error = URLCacheContainer_OpenIndex(pContainer);
1506 if (error != ERROR_SUCCESS)
1508 SetLastError(error);
1509 return FALSE;
1512 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1513 return FALSE;
1515 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1517 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1518 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1519 SetLastError(ERROR_FILE_NOT_FOUND);
1520 return FALSE;
1523 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1524 if (pEntry->dwSignature != URL_SIGNATURE)
1526 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1527 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1528 SetLastError(ERROR_FILE_NOT_FOUND);
1529 return FALSE;
1532 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1533 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1534 if (pUrlEntry->dwOffsetHeaderInfo)
1535 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1537 if (lpdwCacheEntryInfoBufferSize)
1539 if (!lpCacheEntryInfo)
1540 *lpdwCacheEntryInfoBufferSize = 0;
1542 error = URLCache_CopyEntry(
1543 pContainer,
1544 pHeader,
1545 lpCacheEntryInfo,
1546 lpdwCacheEntryInfoBufferSize,
1547 pUrlEntry,
1548 FALSE /* ANSI */);
1549 if (error != ERROR_SUCCESS)
1551 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1552 SetLastError(error);
1553 return FALSE;
1555 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1558 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1560 return TRUE;
1563 /***********************************************************************
1564 * GetUrlCacheEntryInfoW (WININET.@)
1567 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1568 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1569 LPDWORD lpdwCacheEntryInfoBufferSize)
1571 LPURLCACHE_HEADER pHeader;
1572 struct _HASH_ENTRY * pHashEntry;
1573 const CACHEFILE_ENTRY * pEntry;
1574 const URL_CACHEFILE_ENTRY * pUrlEntry;
1575 URLCACHECONTAINER * pContainer;
1576 DWORD error;
1578 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1580 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1581 if (error != ERROR_SUCCESS)
1583 SetLastError(error);
1584 return FALSE;
1587 error = URLCacheContainer_OpenIndex(pContainer);
1588 if (error != ERROR_SUCCESS)
1590 SetLastError(error);
1591 return FALSE;
1594 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1595 return FALSE;
1597 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1599 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1600 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1601 SetLastError(ERROR_FILE_NOT_FOUND);
1602 return FALSE;
1605 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1606 if (pEntry->dwSignature != URL_SIGNATURE)
1608 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1609 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1610 SetLastError(ERROR_FILE_NOT_FOUND);
1611 return FALSE;
1614 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1615 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1616 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1618 if (lpdwCacheEntryInfoBufferSize)
1620 if (!lpCacheEntryInfo)
1621 *lpdwCacheEntryInfoBufferSize = 0;
1623 error = URLCache_CopyEntry(
1624 pContainer,
1625 pHeader,
1626 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1627 lpdwCacheEntryInfoBufferSize,
1628 pUrlEntry,
1629 TRUE /* UNICODE */);
1630 if (error != ERROR_SUCCESS)
1632 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1633 SetLastError(error);
1634 return FALSE;
1636 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1639 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1641 return TRUE;
1644 /***********************************************************************
1645 * GetUrlCacheEntryInfoExW (WININET.@)
1648 BOOL WINAPI GetUrlCacheEntryInfoExW(
1649 LPCWSTR lpszUrl,
1650 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1651 LPDWORD lpdwCacheEntryInfoBufSize,
1652 LPWSTR lpszReserved,
1653 LPDWORD lpdwReserved,
1654 LPVOID lpReserved,
1655 DWORD dwFlags)
1657 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1658 debugstr_w(lpszUrl),
1659 lpCacheEntryInfo,
1660 lpdwCacheEntryInfoBufSize,
1661 lpszReserved,
1662 lpdwReserved,
1663 lpReserved,
1664 dwFlags);
1666 if ((lpszReserved != NULL) ||
1667 (lpdwReserved != NULL) ||
1668 (lpReserved != NULL))
1670 ERR("Reserved value was not 0\n");
1671 SetLastError(ERROR_INVALID_PARAMETER);
1672 return FALSE;
1674 if (dwFlags != 0)
1675 FIXME("Undocumented flag(s): %x\n", dwFlags);
1676 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1679 /***********************************************************************
1680 * SetUrlCacheEntryInfoA (WININET.@)
1682 BOOL WINAPI SetUrlCacheEntryInfoA(
1683 LPCSTR lpszUrlName,
1684 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1685 DWORD dwFieldControl)
1687 LPURLCACHE_HEADER pHeader;
1688 struct _HASH_ENTRY * pHashEntry;
1689 CACHEFILE_ENTRY * pEntry;
1690 URLCACHECONTAINER * pContainer;
1691 DWORD error;
1693 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1695 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1696 if (error != ERROR_SUCCESS)
1698 SetLastError(error);
1699 return FALSE;
1702 error = URLCacheContainer_OpenIndex(pContainer);
1703 if (error != ERROR_SUCCESS)
1705 SetLastError(error);
1706 return FALSE;
1709 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1710 return FALSE;
1712 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1714 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1715 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1716 SetLastError(ERROR_FILE_NOT_FOUND);
1717 return FALSE;
1720 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1721 if (pEntry->dwSignature != URL_SIGNATURE)
1723 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1724 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1725 SetLastError(ERROR_FILE_NOT_FOUND);
1726 return FALSE;
1729 URLCache_SetEntryInfo(
1730 (URL_CACHEFILE_ENTRY *)pEntry,
1731 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1732 dwFieldControl);
1734 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1736 return TRUE;
1739 /***********************************************************************
1740 * SetUrlCacheEntryInfoW (WININET.@)
1742 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1744 LPURLCACHE_HEADER pHeader;
1745 struct _HASH_ENTRY * pHashEntry;
1746 CACHEFILE_ENTRY * pEntry;
1747 URLCACHECONTAINER * pContainer;
1748 DWORD error;
1750 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1752 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1753 if (error != ERROR_SUCCESS)
1755 SetLastError(error);
1756 return FALSE;
1759 error = URLCacheContainer_OpenIndex(pContainer);
1760 if (error != ERROR_SUCCESS)
1762 SetLastError(error);
1763 return FALSE;
1766 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1767 return FALSE;
1769 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1771 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1772 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1773 SetLastError(ERROR_FILE_NOT_FOUND);
1774 return FALSE;
1777 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1778 if (pEntry->dwSignature != URL_SIGNATURE)
1780 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1781 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1782 SetLastError(ERROR_FILE_NOT_FOUND);
1783 return FALSE;
1786 URLCache_SetEntryInfo(
1787 (URL_CACHEFILE_ENTRY *)pEntry,
1788 lpCacheEntryInfo,
1789 dwFieldControl);
1791 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1793 return TRUE;
1796 /***********************************************************************
1797 * RetrieveUrlCacheEntryFileA (WININET.@)
1800 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1801 IN LPCSTR lpszUrlName,
1802 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1803 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1804 IN DWORD dwReserved
1807 LPURLCACHE_HEADER pHeader;
1808 struct _HASH_ENTRY * pHashEntry;
1809 CACHEFILE_ENTRY * pEntry;
1810 URL_CACHEFILE_ENTRY * pUrlEntry;
1811 URLCACHECONTAINER * pContainer;
1812 DWORD error;
1814 TRACE("(%s, %p, %p, 0x%08x)\n",
1815 debugstr_a(lpszUrlName),
1816 lpCacheEntryInfo,
1817 lpdwCacheEntryInfoBufferSize,
1818 dwReserved);
1820 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1821 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1823 SetLastError(ERROR_INVALID_PARAMETER);
1824 return FALSE;
1827 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1828 if (error != ERROR_SUCCESS)
1830 SetLastError(error);
1831 return FALSE;
1834 error = URLCacheContainer_OpenIndex(pContainer);
1835 if (error != ERROR_SUCCESS)
1837 SetLastError(error);
1838 return FALSE;
1841 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1842 return FALSE;
1844 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1846 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1847 TRACE("entry %s not found!\n", lpszUrlName);
1848 SetLastError(ERROR_FILE_NOT_FOUND);
1849 return FALSE;
1852 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1853 if (pEntry->dwSignature != URL_SIGNATURE)
1855 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1856 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1857 SetLastError(ERROR_FILE_NOT_FOUND);
1858 return FALSE;
1861 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1862 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1863 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1865 pUrlEntry->dwHitRate++;
1866 pUrlEntry->dwUseCount++;
1867 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1869 error = URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo,
1870 lpdwCacheEntryInfoBufferSize, pUrlEntry,
1871 FALSE);
1872 if (error != ERROR_SUCCESS)
1874 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1875 SetLastError(error);
1876 return FALSE;
1878 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1880 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1882 return TRUE;
1885 /***********************************************************************
1886 * RetrieveUrlCacheEntryFileW (WININET.@)
1889 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1890 IN LPCWSTR lpszUrlName,
1891 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1892 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1893 IN DWORD dwReserved
1896 LPURLCACHE_HEADER pHeader;
1897 struct _HASH_ENTRY * pHashEntry;
1898 CACHEFILE_ENTRY * pEntry;
1899 URL_CACHEFILE_ENTRY * pUrlEntry;
1900 URLCACHECONTAINER * pContainer;
1901 DWORD error;
1903 TRACE("(%s, %p, %p, 0x%08x)\n",
1904 debugstr_w(lpszUrlName),
1905 lpCacheEntryInfo,
1906 lpdwCacheEntryInfoBufferSize,
1907 dwReserved);
1909 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1910 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1912 SetLastError(ERROR_INVALID_PARAMETER);
1913 return FALSE;
1916 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
1917 if (error != ERROR_SUCCESS)
1919 SetLastError(error);
1920 return FALSE;
1923 error = URLCacheContainer_OpenIndex(pContainer);
1924 if (error != ERROR_SUCCESS)
1926 SetLastError(error);
1927 return FALSE;
1930 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1931 return FALSE;
1933 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1935 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1936 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1937 SetLastError(ERROR_FILE_NOT_FOUND);
1938 return FALSE;
1941 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1942 if (pEntry->dwSignature != URL_SIGNATURE)
1944 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1945 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1946 SetLastError(ERROR_FILE_NOT_FOUND);
1947 return FALSE;
1950 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1951 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1952 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1954 pUrlEntry->dwHitRate++;
1955 pUrlEntry->dwUseCount++;
1956 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1958 error = URLCache_CopyEntry(
1959 pContainer,
1960 pHeader,
1961 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1962 lpdwCacheEntryInfoBufferSize,
1963 pUrlEntry,
1964 TRUE /* UNICODE */);
1965 if (error != ERROR_SUCCESS)
1967 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1968 SetLastError(error);
1969 return FALSE;
1971 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1973 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1975 return TRUE;
1978 /***********************************************************************
1979 * UnlockUrlCacheEntryFileA (WININET.@)
1982 BOOL WINAPI UnlockUrlCacheEntryFileA(
1983 IN LPCSTR lpszUrlName,
1984 IN DWORD dwReserved
1987 LPURLCACHE_HEADER pHeader;
1988 struct _HASH_ENTRY * pHashEntry;
1989 CACHEFILE_ENTRY * pEntry;
1990 URL_CACHEFILE_ENTRY * pUrlEntry;
1991 URLCACHECONTAINER * pContainer;
1992 DWORD error;
1994 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
1996 if (dwReserved)
1998 ERR("dwReserved != 0\n");
1999 SetLastError(ERROR_INVALID_PARAMETER);
2000 return FALSE;
2003 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2004 if (error != ERROR_SUCCESS)
2006 SetLastError(error);
2007 return FALSE;
2010 error = URLCacheContainer_OpenIndex(pContainer);
2011 if (error != ERROR_SUCCESS)
2013 SetLastError(error);
2014 return FALSE;
2017 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2018 return FALSE;
2020 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2022 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2023 TRACE("entry %s not found!\n", lpszUrlName);
2024 SetLastError(ERROR_FILE_NOT_FOUND);
2025 return FALSE;
2028 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2029 if (pEntry->dwSignature != URL_SIGNATURE)
2031 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2032 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2033 SetLastError(ERROR_FILE_NOT_FOUND);
2034 return FALSE;
2037 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2039 if (pUrlEntry->dwUseCount == 0)
2041 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2042 return FALSE;
2044 pUrlEntry->dwUseCount--;
2045 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2047 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2049 return TRUE;
2052 /***********************************************************************
2053 * UnlockUrlCacheEntryFileW (WININET.@)
2056 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
2058 LPURLCACHE_HEADER pHeader;
2059 struct _HASH_ENTRY * pHashEntry;
2060 CACHEFILE_ENTRY * pEntry;
2061 URL_CACHEFILE_ENTRY * pUrlEntry;
2062 URLCACHECONTAINER * pContainer;
2063 DWORD error;
2065 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
2067 if (dwReserved)
2069 ERR("dwReserved != 0\n");
2070 SetLastError(ERROR_INVALID_PARAMETER);
2071 return FALSE;
2074 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2075 if (error != ERROR_SUCCESS)
2077 SetLastError(error);
2078 return FALSE;
2081 error = URLCacheContainer_OpenIndex(pContainer);
2082 if (error != ERROR_SUCCESS)
2084 SetLastError(error);
2085 return FALSE;
2088 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2089 return FALSE;
2091 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
2093 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2094 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
2095 SetLastError(ERROR_FILE_NOT_FOUND);
2096 return FALSE;
2099 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2100 if (pEntry->dwSignature != URL_SIGNATURE)
2102 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2103 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2104 SetLastError(ERROR_FILE_NOT_FOUND);
2105 return FALSE;
2108 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2110 if (pUrlEntry->dwUseCount == 0)
2112 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2113 return FALSE;
2115 pUrlEntry->dwUseCount--;
2116 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2118 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2120 return TRUE;
2123 /***********************************************************************
2124 * CreateUrlCacheEntryA (WININET.@)
2127 BOOL WINAPI CreateUrlCacheEntryA(
2128 IN LPCSTR lpszUrlName,
2129 IN DWORD dwExpectedFileSize,
2130 IN LPCSTR lpszFileExtension,
2131 OUT LPSTR lpszFileName,
2132 IN DWORD dwReserved
2135 DWORD len;
2136 WCHAR *url_name;
2137 WCHAR *file_extension;
2138 WCHAR file_name[MAX_PATH];
2139 BOOL bSuccess = FALSE;
2140 DWORD dwError = 0;
2142 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
2143 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2145 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2146 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 &&
2147 (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2149 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2150 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
2152 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
2154 bSuccess = TRUE;
2156 else
2158 dwError = GetLastError();
2161 else
2163 dwError = GetLastError();
2165 HeapFree(GetProcessHeap(), 0, file_extension);
2167 else
2169 dwError = GetLastError();
2171 HeapFree(GetProcessHeap(), 0, url_name);
2172 if (!bSuccess)
2173 SetLastError(dwError);
2175 return bSuccess;
2177 /***********************************************************************
2178 * CreateUrlCacheEntryW (WININET.@)
2181 BOOL WINAPI CreateUrlCacheEntryW(
2182 IN LPCWSTR lpszUrlName,
2183 IN DWORD dwExpectedFileSize,
2184 IN LPCWSTR lpszFileExtension,
2185 OUT LPWSTR lpszFileName,
2186 IN DWORD dwReserved
2189 URLCACHECONTAINER * pContainer;
2190 LPURLCACHE_HEADER pHeader;
2191 CHAR szFile[MAX_PATH];
2192 WCHAR szExtension[MAX_PATH];
2193 LPCWSTR lpszUrlPart;
2194 LPCWSTR lpszUrlEnd;
2195 LPCWSTR lpszFileNameExtension;
2196 LPWSTR lpszFileNameNoPath;
2197 int i;
2198 int countnoextension;
2199 BYTE CacheDir;
2200 LONG lBufferSize;
2201 BOOL bFound = FALSE;
2202 int count;
2203 DWORD error;
2204 static const WCHAR szWWW[] = {'w','w','w',0};
2206 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2207 debugstr_w(lpszUrlName),
2208 dwExpectedFileSize,
2209 debugstr_w(lpszFileExtension),
2210 lpszFileName,
2211 dwReserved);
2213 if (dwReserved)
2215 ERR("dwReserved != 0\n");
2216 SetLastError(ERROR_INVALID_PARAMETER);
2217 return FALSE;
2220 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2222 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2223 lpszUrlEnd--;
2225 for (lpszUrlPart = lpszUrlEnd;
2226 (lpszUrlPart >= lpszUrlName);
2227 lpszUrlPart--)
2229 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2231 bFound = TRUE;
2232 lpszUrlPart++;
2233 break;
2235 else if(*lpszUrlPart == '?' || *lpszUrlPart == '#')
2237 lpszUrlEnd = lpszUrlPart;
2240 if (!lstrcmpW(lpszUrlPart, szWWW))
2242 lpszUrlPart += lstrlenW(szWWW);
2245 count = lpszUrlEnd - lpszUrlPart;
2247 if (bFound && (count < MAX_PATH))
2249 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2250 if (!len)
2251 return FALSE;
2252 szFile[len] = '\0';
2253 /* FIXME: get rid of illegal characters like \, / and : */
2255 else
2257 FIXME("need to generate a random filename\n");
2260 TRACE("File name: %s\n", debugstr_a(szFile));
2262 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2263 if (error != ERROR_SUCCESS)
2265 SetLastError(error);
2266 return FALSE;
2269 error = URLCacheContainer_OpenIndex(pContainer);
2270 if (error != ERROR_SUCCESS)
2272 SetLastError(error);
2273 return FALSE;
2276 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2277 return FALSE;
2279 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2281 lBufferSize = MAX_PATH * sizeof(WCHAR);
2282 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
2284 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2286 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2287 lpszFileNameNoPath >= lpszFileName;
2288 --lpszFileNameNoPath)
2290 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2291 break;
2294 countnoextension = lstrlenW(lpszFileNameNoPath);
2295 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2296 if (lpszFileNameExtension)
2297 countnoextension -= lstrlenW(lpszFileNameExtension);
2298 *szExtension = '\0';
2300 if (lpszFileExtension)
2302 szExtension[0] = '.';
2303 lstrcpyW(szExtension+1, lpszFileExtension);
2306 for (i = 0; i < 255; i++)
2308 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2309 HANDLE hFile;
2310 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2311 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2312 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2313 if (hFile != INVALID_HANDLE_VALUE)
2315 CloseHandle(hFile);
2316 return TRUE;
2320 return FALSE;
2324 /***********************************************************************
2325 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2327 * The bug we are compensating for is that some drongo at Microsoft
2328 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2329 * As a consequence, CommitUrlCacheEntryA has been effectively
2330 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2331 * is still defined as LPCWSTR. The result (other than madness) is
2332 * that we always need to store lpHeaderInfo in CP_ACP rather than
2333 * in UTF16, and we need to avoid converting lpHeaderInfo in
2334 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2335 * result will lose data for arbitrary binary data.
2338 static BOOL WINAPI CommitUrlCacheEntryInternal(
2339 IN LPCWSTR lpszUrlName,
2340 IN LPCWSTR lpszLocalFileName,
2341 IN FILETIME ExpireTime,
2342 IN FILETIME LastModifiedTime,
2343 IN DWORD CacheEntryType,
2344 IN LPBYTE lpHeaderInfo,
2345 IN DWORD dwHeaderSize,
2346 IN LPCWSTR lpszFileExtension,
2347 IN LPCWSTR lpszOriginalUrl
2350 URLCACHECONTAINER * pContainer;
2351 LPURLCACHE_HEADER pHeader;
2352 struct _HASH_ENTRY * pHashEntry;
2353 CACHEFILE_ENTRY * pEntry;
2354 URL_CACHEFILE_ENTRY * pUrlEntry;
2355 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2356 DWORD dwOffsetLocalFileName = 0;
2357 DWORD dwOffsetHeader = 0;
2358 DWORD dwOffsetFileExtension = 0;
2359 DWORD dwFileSizeLow = 0;
2360 DWORD dwFileSizeHigh = 0;
2361 BYTE cDirectory = 0;
2362 int len;
2363 char achFile[MAX_PATH];
2364 LPSTR lpszUrlNameA = NULL;
2365 LPSTR lpszFileExtensionA = NULL;
2366 char *pchLocalFileName = 0;
2367 DWORD error;
2369 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2370 debugstr_w(lpszUrlName),
2371 debugstr_w(lpszLocalFileName),
2372 CacheEntryType,
2373 lpHeaderInfo,
2374 dwHeaderSize,
2375 debugstr_w(lpszFileExtension),
2376 debugstr_w(lpszOriginalUrl));
2378 if (lpszOriginalUrl)
2379 WARN(": lpszOriginalUrl ignored\n");
2381 if (lpszLocalFileName)
2383 HANDLE hFile;
2385 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2386 if (hFile == INVALID_HANDLE_VALUE)
2388 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2389 return FALSE;
2392 /* Get file size */
2393 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2394 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2396 ERR("couldn't get file size (error is %d)\n", GetLastError());
2397 CloseHandle(hFile);
2398 return FALSE;
2401 CloseHandle(hFile);
2404 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2405 if (error != ERROR_SUCCESS)
2407 SetLastError(error);
2408 return FALSE;
2411 error = URLCacheContainer_OpenIndex(pContainer);
2412 if (error != ERROR_SUCCESS)
2414 SetLastError(error);
2415 return FALSE;
2418 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2419 return FALSE;
2421 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2422 lpszUrlNameA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2423 if (!lpszUrlNameA)
2425 error = GetLastError();
2426 goto cleanup;
2428 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, lpszUrlNameA, len, NULL, NULL);
2430 if (lpszFileExtension)
2432 len = WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, NULL, 0, NULL, NULL);
2433 lpszFileExtensionA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2434 if (!lpszFileExtensionA)
2436 error = GetLastError();
2437 goto cleanup;
2439 WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, lpszFileExtensionA, len, NULL, NULL);
2442 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2444 FIXME("entry already in cache - don't know what to do!\n");
2446 * SetLastError(ERROR_FILE_NOT_FOUND);
2447 * return FALSE;
2449 goto cleanup;
2452 if (lpszLocalFileName)
2454 BOOL bFound = FALSE;
2456 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2458 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2459 error = ERROR_INVALID_PARAMETER;
2460 goto cleanup;
2463 /* skip container path prefix */
2464 lpszLocalFileName += lstrlenW(pContainer->path);
2466 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL);
2467 pchLocalFileName = achFile;
2469 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2471 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2473 bFound = TRUE;
2474 break;
2478 if (!bFound)
2480 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2481 error = ERROR_INVALID_PARAMETER;
2482 goto cleanup;
2485 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2488 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2489 if (lpszLocalFileName)
2491 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2492 dwOffsetLocalFileName = dwBytesNeeded;
2493 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2495 if (lpHeaderInfo)
2497 dwOffsetHeader = dwBytesNeeded;
2498 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2500 if (lpszFileExtensionA)
2502 dwOffsetFileExtension = dwBytesNeeded;
2503 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2506 /* round up to next block */
2507 if (dwBytesNeeded % BLOCKSIZE)
2509 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2510 dwBytesNeeded += BLOCKSIZE;
2513 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2515 ERR("no free entries\n");
2516 error = ERROR_DISK_FULL;
2517 goto cleanup;
2520 /* FindFirstFreeEntry fills in blocks used */
2521 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2522 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2523 pUrlEntry->CacheDir = cDirectory;
2524 pUrlEntry->CacheEntryType = CacheEntryType;
2525 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2526 pUrlEntry->dwExemptDelta = 0;
2527 pUrlEntry->dwHitRate = 0;
2528 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2529 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2530 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2531 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2532 pUrlEntry->dwSizeHigh = 0;
2533 pUrlEntry->dwSizeLow = dwFileSizeLow;
2534 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2535 pUrlEntry->dwUseCount = 0;
2536 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2537 pUrlEntry->LastModifiedTime = LastModifiedTime;
2538 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2539 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2540 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2541 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2543 /*** Unknowns ***/
2544 pUrlEntry->dwUnknown1 = 0;
2545 pUrlEntry->dwUnknown2 = 0;
2546 pUrlEntry->dwUnknown3 = 0x60;
2547 pUrlEntry->Unknown4 = 0;
2548 pUrlEntry->wUnknown5 = 0x1010;
2549 pUrlEntry->dwUnknown7 = 0;
2550 pUrlEntry->dwUnknown8 = 0;
2553 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2554 if (dwOffsetLocalFileName)
2555 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2556 if (dwOffsetHeader)
2557 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2558 if (dwOffsetFileExtension)
2559 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2561 error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA,
2562 (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader));
2563 if (error != ERROR_SUCCESS)
2564 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2566 cleanup:
2567 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2568 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2569 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2571 if (error == ERROR_SUCCESS)
2572 return TRUE;
2573 else
2575 SetLastError(error);
2576 return FALSE;
2580 /***********************************************************************
2581 * CommitUrlCacheEntryA (WININET.@)
2584 BOOL WINAPI CommitUrlCacheEntryA(
2585 IN LPCSTR lpszUrlName,
2586 IN LPCSTR lpszLocalFileName,
2587 IN FILETIME ExpireTime,
2588 IN FILETIME LastModifiedTime,
2589 IN DWORD CacheEntryType,
2590 IN LPBYTE lpHeaderInfo,
2591 IN DWORD dwHeaderSize,
2592 IN LPCSTR lpszFileExtension,
2593 IN LPCSTR lpszOriginalUrl
2596 DWORD len;
2597 WCHAR *url_name = NULL;
2598 WCHAR *local_file_name = NULL;
2599 WCHAR *original_url = NULL;
2600 WCHAR *file_extension = NULL;
2601 BOOL bSuccess = FALSE;
2603 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2604 debugstr_a(lpszUrlName),
2605 debugstr_a(lpszLocalFileName),
2606 CacheEntryType,
2607 lpHeaderInfo,
2608 dwHeaderSize,
2609 debugstr_a(lpszFileExtension),
2610 debugstr_a(lpszOriginalUrl));
2612 len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0);
2613 url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2614 if (!url_name)
2615 goto cleanup;
2616 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2618 if (lpszLocalFileName)
2620 len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0);
2621 local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2622 if (!local_file_name)
2623 goto cleanup;
2624 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2626 if (lpszFileExtension)
2628 len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0);
2629 file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2630 if (!file_extension)
2631 goto cleanup;
2632 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2634 if (lpszOriginalUrl)
2636 len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0);
2637 original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2638 if (!original_url)
2639 goto cleanup;
2640 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2643 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2644 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2645 file_extension, original_url);
2647 cleanup:
2648 HeapFree(GetProcessHeap(), 0, original_url);
2649 HeapFree(GetProcessHeap(), 0, file_extension);
2650 HeapFree(GetProcessHeap(), 0, local_file_name);
2651 HeapFree(GetProcessHeap(), 0, url_name);
2653 return bSuccess;
2656 /***********************************************************************
2657 * CommitUrlCacheEntryW (WININET.@)
2660 BOOL WINAPI CommitUrlCacheEntryW(
2661 IN LPCWSTR lpszUrlName,
2662 IN LPCWSTR lpszLocalFileName,
2663 IN FILETIME ExpireTime,
2664 IN FILETIME LastModifiedTime,
2665 IN DWORD CacheEntryType,
2666 IN LPWSTR lpHeaderInfo,
2667 IN DWORD dwHeaderSize,
2668 IN LPCWSTR lpszFileExtension,
2669 IN LPCWSTR lpszOriginalUrl
2672 DWORD dwError = 0;
2673 BOOL bSuccess = FALSE;
2674 DWORD len = 0;
2675 CHAR *header_info = NULL;
2677 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2678 debugstr_w(lpszUrlName),
2679 debugstr_w(lpszLocalFileName),
2680 CacheEntryType,
2681 lpHeaderInfo,
2682 dwHeaderSize,
2683 debugstr_w(lpszFileExtension),
2684 debugstr_w(lpszOriginalUrl));
2686 if (!lpHeaderInfo ||
2687 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2688 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2690 if (header_info)
2691 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2692 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2693 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2695 bSuccess = TRUE;
2697 else
2699 dwError = GetLastError();
2701 if (header_info)
2703 HeapFree(GetProcessHeap(), 0, header_info);
2704 if (!bSuccess)
2705 SetLastError(dwError);
2708 return bSuccess;
2711 /***********************************************************************
2712 * ReadUrlCacheEntryStream (WININET.@)
2715 BOOL WINAPI ReadUrlCacheEntryStream(
2716 IN HANDLE hUrlCacheStream,
2717 IN DWORD dwLocation,
2718 IN OUT LPVOID lpBuffer,
2719 IN OUT LPDWORD lpdwLen,
2720 IN DWORD dwReserved
2723 /* Get handle to file from 'stream' */
2724 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2726 if (dwReserved != 0)
2728 ERR("dwReserved != 0\n");
2729 SetLastError(ERROR_INVALID_PARAMETER);
2730 return FALSE;
2733 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2735 SetLastError(ERROR_INVALID_HANDLE);
2736 return FALSE;
2739 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2740 return FALSE;
2741 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2744 /***********************************************************************
2745 * RetrieveUrlCacheEntryStreamA (WININET.@)
2748 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2749 IN LPCSTR lpszUrlName,
2750 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2751 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2752 IN BOOL fRandomRead,
2753 IN DWORD dwReserved
2756 /* NOTE: this is not the same as the way that the native
2757 * version allocates 'stream' handles. I did it this way
2758 * as it is much easier and no applications should depend
2759 * on this behaviour. (Native version appears to allocate
2760 * indices into a table)
2762 STREAM_HANDLE * pStream;
2763 HANDLE hFile;
2765 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2766 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2768 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2769 lpCacheEntryInfo,
2770 lpdwCacheEntryInfoBufferSize,
2771 dwReserved))
2773 return NULL;
2776 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2777 GENERIC_READ,
2778 FILE_SHARE_READ,
2779 NULL,
2780 OPEN_EXISTING,
2781 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2782 NULL);
2783 if (hFile == INVALID_HANDLE_VALUE)
2784 return FALSE;
2786 /* allocate handle storage space */
2787 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2788 if (!pStream)
2790 CloseHandle(hFile);
2791 SetLastError(ERROR_OUTOFMEMORY);
2792 return FALSE;
2795 pStream->hFile = hFile;
2796 strcpy(pStream->lpszUrl, lpszUrlName);
2797 return (HANDLE)pStream;
2800 /***********************************************************************
2801 * RetrieveUrlCacheEntryStreamW (WININET.@)
2804 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2805 IN LPCWSTR lpszUrlName,
2806 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2807 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2808 IN BOOL fRandomRead,
2809 IN DWORD dwReserved
2812 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2813 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2814 return NULL;
2817 /***********************************************************************
2818 * UnlockUrlCacheEntryStream (WININET.@)
2821 BOOL WINAPI UnlockUrlCacheEntryStream(
2822 IN HANDLE hUrlCacheStream,
2823 IN DWORD dwReserved
2826 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2828 if (dwReserved != 0)
2830 ERR("dwReserved != 0\n");
2831 SetLastError(ERROR_INVALID_PARAMETER);
2832 return FALSE;
2835 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2837 SetLastError(ERROR_INVALID_HANDLE);
2838 return FALSE;
2841 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2842 return FALSE;
2844 /* close file handle */
2845 CloseHandle(pStream->hFile);
2847 /* free allocated space */
2848 HeapFree(GetProcessHeap(), 0, pStream);
2850 return TRUE;
2854 /***********************************************************************
2855 * DeleteUrlCacheEntryA (WININET.@)
2858 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2860 URLCACHECONTAINER * pContainer;
2861 LPURLCACHE_HEADER pHeader;
2862 struct _HASH_ENTRY * pHashEntry;
2863 CACHEFILE_ENTRY * pEntry;
2864 DWORD error;
2866 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2868 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2869 if (error != ERROR_SUCCESS)
2871 SetLastError(error);
2872 return FALSE;
2875 error = URLCacheContainer_OpenIndex(pContainer);
2876 if (error != ERROR_SUCCESS)
2878 SetLastError(error);
2879 return FALSE;
2882 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2883 return FALSE;
2885 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2887 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2888 TRACE("entry %s not found!\n", lpszUrlName);
2889 SetLastError(ERROR_FILE_NOT_FOUND);
2890 return FALSE;
2893 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2894 URLCache_DeleteEntry(pHeader, pEntry);
2896 URLCache_DeleteEntryFromHash(pHashEntry);
2898 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2900 return TRUE;
2903 /***********************************************************************
2904 * DeleteUrlCacheEntryW (WININET.@)
2907 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2909 URLCACHECONTAINER * pContainer;
2910 LPURLCACHE_HEADER pHeader;
2911 struct _HASH_ENTRY * pHashEntry;
2912 CACHEFILE_ENTRY * pEntry;
2913 LPSTR urlA;
2914 int url_len;
2915 DWORD error;
2917 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2919 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2920 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
2921 if (!urlA)
2923 SetLastError(ERROR_OUTOFMEMORY);
2924 return FALSE;
2926 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, urlA, url_len, NULL, NULL);
2928 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2929 if (error != ERROR_SUCCESS)
2931 HeapFree(GetProcessHeap(), 0, urlA);
2932 SetLastError(error);
2933 return FALSE;
2936 error = URLCacheContainer_OpenIndex(pContainer);
2937 if (error != ERROR_SUCCESS)
2939 HeapFree(GetProcessHeap(), 0, urlA);
2940 SetLastError(error);
2941 return FALSE;
2944 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2946 HeapFree(GetProcessHeap(), 0, urlA);
2947 return FALSE;
2950 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
2952 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2953 TRACE("entry %s not found!\n", debugstr_a(urlA));
2954 HeapFree(GetProcessHeap(), 0, urlA);
2955 SetLastError(ERROR_FILE_NOT_FOUND);
2956 return FALSE;
2959 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2960 URLCache_DeleteEntry(pHeader, pEntry);
2962 URLCache_DeleteEntryFromHash(pHashEntry);
2964 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2966 HeapFree(GetProcessHeap(), 0, urlA);
2967 return TRUE;
2970 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2972 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2973 return TRUE;
2976 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2978 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2979 return TRUE;
2982 /***********************************************************************
2983 * CreateCacheContainerA (WININET.@)
2985 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2986 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2988 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2989 d1, d2, d3, d4, d5, d6, d7, d8);
2990 return TRUE;
2993 /***********************************************************************
2994 * CreateCacheContainerW (WININET.@)
2996 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2997 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2999 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3000 d1, d2, d3, d4, d5, d6, d7, d8);
3001 return TRUE;
3004 /***********************************************************************
3005 * FindFirstUrlCacheContainerA (WININET.@)
3007 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3009 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3010 return NULL;
3013 /***********************************************************************
3014 * FindFirstUrlCacheContainerW (WININET.@)
3016 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3018 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3019 return NULL;
3022 /***********************************************************************
3023 * FindNextUrlCacheContainerA (WININET.@)
3025 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
3027 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3028 return FALSE;
3031 /***********************************************************************
3032 * FindNextUrlCacheContainerW (WININET.@)
3034 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
3036 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3037 return FALSE;
3040 HANDLE WINAPI FindFirstUrlCacheEntryExA(
3041 LPCSTR lpszUrlSearchPattern,
3042 DWORD dwFlags,
3043 DWORD dwFilter,
3044 GROUPID GroupId,
3045 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3046 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3047 LPVOID lpReserved,
3048 LPDWORD pcbReserved2,
3049 LPVOID lpReserved3
3052 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
3053 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3054 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3055 SetLastError(ERROR_FILE_NOT_FOUND);
3056 return NULL;
3059 HANDLE WINAPI FindFirstUrlCacheEntryExW(
3060 LPCWSTR lpszUrlSearchPattern,
3061 DWORD dwFlags,
3062 DWORD dwFilter,
3063 GROUPID GroupId,
3064 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3065 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3066 LPVOID lpReserved,
3067 LPDWORD pcbReserved2,
3068 LPVOID lpReserved3
3071 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
3072 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3073 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3074 SetLastError(ERROR_FILE_NOT_FOUND);
3075 return NULL;
3078 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3080 typedef struct URLCacheFindEntryHandle
3082 DWORD dwMagic;
3083 LPWSTR lpszUrlSearchPattern;
3084 DWORD dwContainerIndex;
3085 DWORD dwHashTableIndex;
3086 DWORD dwHashEntryIndex;
3087 } URLCacheFindEntryHandle;
3089 /***********************************************************************
3090 * FindFirstUrlCacheEntryA (WININET.@)
3093 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
3094 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3096 URLCacheFindEntryHandle *pEntryHandle;
3098 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3100 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3101 if (!pEntryHandle)
3102 return NULL;
3104 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3105 if (lpszUrlSearchPattern)
3107 int len = MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, NULL, 0);
3108 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3109 if (!pEntryHandle->lpszUrlSearchPattern)
3111 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3112 return NULL;
3114 MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, pEntryHandle->lpszUrlSearchPattern, len);
3116 else
3117 pEntryHandle->lpszUrlSearchPattern = NULL;
3118 pEntryHandle->dwContainerIndex = 0;
3119 pEntryHandle->dwHashTableIndex = 0;
3120 pEntryHandle->dwHashEntryIndex = 0;
3122 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3124 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3125 return NULL;
3127 return pEntryHandle;
3130 /***********************************************************************
3131 * FindFirstUrlCacheEntryW (WININET.@)
3134 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3135 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3137 URLCacheFindEntryHandle *pEntryHandle;
3139 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3141 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3142 if (!pEntryHandle)
3143 return NULL;
3145 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3146 if (lpszUrlSearchPattern)
3148 int len = strlenW(lpszUrlSearchPattern);
3149 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
3150 if (!pEntryHandle->lpszUrlSearchPattern)
3152 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3153 return NULL;
3155 memcpy(pEntryHandle->lpszUrlSearchPattern, lpszUrlSearchPattern, (len + 1) * sizeof(WCHAR));
3157 else
3158 pEntryHandle->lpszUrlSearchPattern = NULL;
3159 pEntryHandle->dwContainerIndex = 0;
3160 pEntryHandle->dwHashTableIndex = 0;
3161 pEntryHandle->dwHashEntryIndex = 0;
3163 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3165 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3166 return NULL;
3168 return pEntryHandle;
3171 /***********************************************************************
3172 * FindNextUrlCacheEntryA (WININET.@)
3174 BOOL WINAPI FindNextUrlCacheEntryA(
3175 HANDLE hEnumHandle,
3176 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3177 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3179 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3180 URLCACHECONTAINER * pContainer;
3182 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3184 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3186 SetLastError(ERROR_INVALID_HANDLE);
3187 return FALSE;
3190 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3191 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3193 LPURLCACHE_HEADER pHeader;
3194 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3195 DWORD error;
3197 error = URLCacheContainer_OpenIndex(pContainer);
3198 if (error != ERROR_SUCCESS)
3200 SetLastError(error);
3201 return FALSE;
3204 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3205 return FALSE;
3207 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3208 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3210 const struct _HASH_ENTRY *pHashEntry = NULL;
3211 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3212 pEntryHandle->dwHashEntryIndex++)
3214 const URL_CACHEFILE_ENTRY *pUrlEntry;
3215 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3217 if (pEntry->dwSignature != URL_SIGNATURE)
3218 continue;
3220 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3221 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3222 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3224 error = URLCache_CopyEntry(
3225 pContainer,
3226 pHeader,
3227 lpNextCacheEntryInfo,
3228 lpdwNextCacheEntryInfoBufferSize,
3229 pUrlEntry,
3230 FALSE /* not UNICODE */);
3231 if (error != ERROR_SUCCESS)
3233 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3234 SetLastError(error);
3235 return FALSE;
3237 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
3239 /* increment the current index so that next time the function
3240 * is called the next entry is returned */
3241 pEntryHandle->dwHashEntryIndex++;
3242 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3243 return TRUE;
3247 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3250 SetLastError(ERROR_NO_MORE_ITEMS);
3251 return FALSE;
3254 /***********************************************************************
3255 * FindNextUrlCacheEntryW (WININET.@)
3257 BOOL WINAPI FindNextUrlCacheEntryW(
3258 HANDLE hEnumHandle,
3259 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3260 LPDWORD lpdwNextCacheEntryInfoBufferSize
3263 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3264 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3265 return FALSE;
3268 /***********************************************************************
3269 * FindCloseUrlCache (WININET.@)
3271 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3273 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3275 TRACE("(%p)\n", hEnumHandle);
3277 if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3279 SetLastError(ERROR_INVALID_HANDLE);
3280 return FALSE;
3283 pEntryHandle->dwMagic = 0;
3284 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3285 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3287 return TRUE;
3290 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3291 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3293 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3294 dwSearchCondition, lpGroupId, lpReserved);
3295 return NULL;
3298 BOOL WINAPI FindNextUrlCacheEntryExA(
3299 HANDLE hEnumHandle,
3300 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3301 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3302 LPVOID lpReserved,
3303 LPDWORD pcbReserved2,
3304 LPVOID lpReserved3
3307 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3308 lpReserved, pcbReserved2, lpReserved3);
3309 return FALSE;
3312 BOOL WINAPI FindNextUrlCacheEntryExW(
3313 HANDLE hEnumHandle,
3314 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3315 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3316 LPVOID lpReserved,
3317 LPDWORD pcbReserved2,
3318 LPVOID lpReserved3
3321 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3322 lpReserved, pcbReserved2, lpReserved3);
3323 return FALSE;
3326 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3328 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3329 return FALSE;
3332 /***********************************************************************
3333 * CreateUrlCacheGroup (WININET.@)
3336 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3338 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3339 return FALSE;
3342 /***********************************************************************
3343 * DeleteUrlCacheGroup (WININET.@)
3346 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3348 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3349 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3350 return FALSE;
3353 /***********************************************************************
3354 * SetUrlCacheEntryGroupA (WININET.@)
3357 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3358 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3359 LPVOID lpReserved)
3361 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3362 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3363 pbGroupAttributes, cbGroupAttributes, lpReserved);
3364 SetLastError(ERROR_FILE_NOT_FOUND);
3365 return FALSE;
3368 /***********************************************************************
3369 * SetUrlCacheEntryGroupW (WININET.@)
3372 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3373 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3374 LPVOID lpReserved)
3376 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3377 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3378 pbGroupAttributes, cbGroupAttributes, lpReserved);
3379 SetLastError(ERROR_FILE_NOT_FOUND);
3380 return FALSE;
3383 /***********************************************************************
3384 * GetUrlCacheConfigInfoW (WININET.@)
3386 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3388 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3389 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3390 return FALSE;
3393 /***********************************************************************
3394 * GetUrlCacheConfigInfoA (WININET.@)
3396 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3398 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3400 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3401 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3402 return FALSE;
3405 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3406 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3407 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3409 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3410 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3411 lpdwGroupInfo, lpReserved);
3412 return FALSE;
3415 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3416 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3417 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3419 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3420 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3421 lpdwGroupInfo, lpReserved);
3422 return FALSE;
3425 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3426 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3428 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3429 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3430 return TRUE;
3433 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3434 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3436 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3437 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3438 return TRUE;
3441 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3443 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3444 return TRUE;
3447 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3449 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3450 return TRUE;
3453 /***********************************************************************
3454 * DeleteIE3Cache (WININET.@)
3456 * Deletes the files used by the IE3 URL caching system.
3458 * PARAMS
3459 * hWnd [I] A dummy window.
3460 * hInst [I] Instance of process calling the function.
3461 * lpszCmdLine [I] Options used by function.
3462 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3464 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3466 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3467 return 0;
3470 /***********************************************************************
3471 * IsUrlCacheEntryExpiredA (WININET.@)
3473 * PARAMS
3474 * url [I] Url
3475 * dwFlags [I] Unknown
3476 * pftLastModified [O] Last modified time
3478 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3480 LPURLCACHE_HEADER pHeader;
3481 struct _HASH_ENTRY * pHashEntry;
3482 const CACHEFILE_ENTRY * pEntry;
3483 const URL_CACHEFILE_ENTRY * pUrlEntry;
3484 URLCACHECONTAINER * pContainer;
3485 DWORD error;
3487 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3489 error = URLCacheContainers_FindContainerA(url, &pContainer);
3490 if (error != ERROR_SUCCESS)
3492 SetLastError(error);
3493 return FALSE;
3496 error = URLCacheContainer_OpenIndex(pContainer);
3497 if (error != ERROR_SUCCESS)
3499 SetLastError(error);
3500 return FALSE;
3503 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3504 return FALSE;
3506 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3508 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3509 TRACE("entry %s not found!\n", url);
3510 SetLastError(ERROR_FILE_NOT_FOUND);
3511 return FALSE;
3514 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3515 if (pEntry->dwSignature != URL_SIGNATURE)
3517 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3518 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3519 SetLastError(ERROR_FILE_NOT_FOUND);
3520 return FALSE;
3523 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3525 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3527 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3529 return TRUE;
3532 /***********************************************************************
3533 * IsUrlCacheEntryExpiredW (WININET.@)
3535 * PARAMS
3536 * url [I] Url
3537 * dwFlags [I] Unknown
3538 * pftLastModified [O] Last modified time
3540 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3542 LPURLCACHE_HEADER pHeader;
3543 struct _HASH_ENTRY * pHashEntry;
3544 const CACHEFILE_ENTRY * pEntry;
3545 const URL_CACHEFILE_ENTRY * pUrlEntry;
3546 URLCACHECONTAINER * pContainer;
3547 DWORD error;
3549 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3551 error = URLCacheContainers_FindContainerW(url, &pContainer);
3552 if (error != ERROR_SUCCESS)
3554 SetLastError(error);
3555 return FALSE;
3558 error = URLCacheContainer_OpenIndex(pContainer);
3559 if (error != ERROR_SUCCESS)
3561 SetLastError(error);
3562 return FALSE;
3565 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3566 return FALSE;
3568 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3570 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3571 TRACE("entry %s not found!\n", debugstr_w(url));
3572 SetLastError(ERROR_FILE_NOT_FOUND);
3573 return FALSE;
3576 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3577 if (pEntry->dwSignature != URL_SIGNATURE)
3579 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3580 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3581 SetLastError(ERROR_FILE_NOT_FOUND);
3582 return FALSE;
3585 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3587 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3589 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3591 return TRUE;