wininet: Fix GetUrlCacheEntryInfoA/W when a NULL lpCacheEntryInfo parameter is passed in.
[wine/wine64.git] / dlls / wininet / urlcache.c
blob792c7bc9d9d1203608bd9c8fb1d0fb59e4896d6b
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 prefx %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 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(lpCacheEntryInfo->lpszLocalFileName));
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_w(lpCacheEntryInfo->lpszLocalFileName));
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 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1821 if (error != ERROR_SUCCESS)
1823 SetLastError(error);
1824 return FALSE;
1827 error = URLCacheContainer_OpenIndex(pContainer);
1828 if (error != ERROR_SUCCESS)
1830 SetLastError(error);
1831 return FALSE;
1834 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1835 return FALSE;
1837 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1839 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1840 TRACE("entry %s not found!\n", lpszUrlName);
1841 SetLastError(ERROR_FILE_NOT_FOUND);
1842 return FALSE;
1845 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1846 if (pEntry->dwSignature != URL_SIGNATURE)
1848 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1849 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1850 SetLastError(ERROR_FILE_NOT_FOUND);
1851 return FALSE;
1854 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1855 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1856 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1858 pUrlEntry->dwHitRate++;
1859 pUrlEntry->dwUseCount++;
1860 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1862 error = URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo,
1863 lpdwCacheEntryInfoBufferSize, pUrlEntry,
1864 FALSE);
1865 if (error != ERROR_SUCCESS)
1867 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1868 SetLastError(error);
1869 return FALSE;
1871 TRACE("Local File Name: %s\n", lpCacheEntryInfo->lpszLocalFileName);
1873 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1875 return TRUE;
1878 /***********************************************************************
1879 * RetrieveUrlCacheEntryFileW (WININET.@)
1882 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1883 IN LPCWSTR lpszUrlName,
1884 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1885 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1886 IN DWORD dwReserved
1889 LPURLCACHE_HEADER pHeader;
1890 struct _HASH_ENTRY * pHashEntry;
1891 CACHEFILE_ENTRY * pEntry;
1892 URL_CACHEFILE_ENTRY * pUrlEntry;
1893 URLCACHECONTAINER * pContainer;
1894 DWORD error;
1896 TRACE("(%s, %p, %p, 0x%08x)\n",
1897 debugstr_w(lpszUrlName),
1898 lpCacheEntryInfo,
1899 lpdwCacheEntryInfoBufferSize,
1900 dwReserved);
1902 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
1903 if (error != ERROR_SUCCESS)
1905 SetLastError(error);
1906 return FALSE;
1909 error = URLCacheContainer_OpenIndex(pContainer);
1910 if (error != ERROR_SUCCESS)
1912 SetLastError(error);
1913 return FALSE;
1916 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1917 return FALSE;
1919 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1921 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1922 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1923 SetLastError(ERROR_FILE_NOT_FOUND);
1924 return FALSE;
1927 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1928 if (pEntry->dwSignature != URL_SIGNATURE)
1930 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1931 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1932 SetLastError(ERROR_FILE_NOT_FOUND);
1933 return FALSE;
1936 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1937 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1938 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1940 pUrlEntry->dwHitRate++;
1941 pUrlEntry->dwUseCount++;
1942 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1944 error = URLCache_CopyEntry(
1945 pContainer,
1946 pHeader,
1947 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1948 lpdwCacheEntryInfoBufferSize,
1949 pUrlEntry,
1950 TRUE /* UNICODE */);
1951 if (error != ERROR_SUCCESS)
1953 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1954 SetLastError(error);
1955 return FALSE;
1957 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1959 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1961 return TRUE;
1964 /***********************************************************************
1965 * UnlockUrlCacheEntryFileA (WININET.@)
1968 BOOL WINAPI UnlockUrlCacheEntryFileA(
1969 IN LPCSTR lpszUrlName,
1970 IN DWORD dwReserved
1973 LPURLCACHE_HEADER pHeader;
1974 struct _HASH_ENTRY * pHashEntry;
1975 CACHEFILE_ENTRY * pEntry;
1976 URL_CACHEFILE_ENTRY * pUrlEntry;
1977 URLCACHECONTAINER * pContainer;
1978 DWORD error;
1980 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
1982 if (dwReserved)
1984 ERR("dwReserved != 0\n");
1985 SetLastError(ERROR_INVALID_PARAMETER);
1986 return FALSE;
1989 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1990 if (error != ERROR_SUCCESS)
1992 SetLastError(error);
1993 return FALSE;
1996 error = URLCacheContainer_OpenIndex(pContainer);
1997 if (error != ERROR_SUCCESS)
1999 SetLastError(error);
2000 return FALSE;
2003 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2004 return FALSE;
2006 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2008 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2009 TRACE("entry %s not found!\n", lpszUrlName);
2010 SetLastError(ERROR_FILE_NOT_FOUND);
2011 return FALSE;
2014 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2015 if (pEntry->dwSignature != URL_SIGNATURE)
2017 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2018 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2019 SetLastError(ERROR_FILE_NOT_FOUND);
2020 return FALSE;
2023 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2025 if (pUrlEntry->dwUseCount == 0)
2027 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2028 return FALSE;
2030 pUrlEntry->dwUseCount--;
2031 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2033 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2035 return TRUE;
2038 /***********************************************************************
2039 * UnlockUrlCacheEntryFileW (WININET.@)
2042 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
2044 LPURLCACHE_HEADER pHeader;
2045 struct _HASH_ENTRY * pHashEntry;
2046 CACHEFILE_ENTRY * pEntry;
2047 URL_CACHEFILE_ENTRY * pUrlEntry;
2048 URLCACHECONTAINER * pContainer;
2049 DWORD error;
2051 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
2053 if (dwReserved)
2055 ERR("dwReserved != 0\n");
2056 SetLastError(ERROR_INVALID_PARAMETER);
2057 return FALSE;
2060 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2061 if (error != ERROR_SUCCESS)
2063 SetLastError(error);
2064 return FALSE;
2067 error = URLCacheContainer_OpenIndex(pContainer);
2068 if (error != ERROR_SUCCESS)
2070 SetLastError(error);
2071 return FALSE;
2074 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2075 return FALSE;
2077 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
2079 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2080 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
2081 SetLastError(ERROR_FILE_NOT_FOUND);
2082 return FALSE;
2085 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2086 if (pEntry->dwSignature != URL_SIGNATURE)
2088 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2089 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2090 SetLastError(ERROR_FILE_NOT_FOUND);
2091 return FALSE;
2094 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2096 if (pUrlEntry->dwUseCount == 0)
2098 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2099 return FALSE;
2101 pUrlEntry->dwUseCount--;
2102 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2104 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2106 return TRUE;
2109 /***********************************************************************
2110 * CreateUrlCacheEntryA (WININET.@)
2113 BOOL WINAPI CreateUrlCacheEntryA(
2114 IN LPCSTR lpszUrlName,
2115 IN DWORD dwExpectedFileSize,
2116 IN LPCSTR lpszFileExtension,
2117 OUT LPSTR lpszFileName,
2118 IN DWORD dwReserved
2121 DWORD len;
2122 WCHAR *url_name;
2123 WCHAR *file_extension;
2124 WCHAR file_name[MAX_PATH];
2125 BOOL bSuccess = FALSE;
2126 DWORD dwError = 0;
2128 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
2129 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2131 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2132 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 &&
2133 (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2135 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2136 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
2138 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
2140 bSuccess = TRUE;
2142 else
2144 dwError = GetLastError();
2147 else
2149 dwError = GetLastError();
2151 HeapFree(GetProcessHeap(), 0, file_extension);
2153 else
2155 dwError = GetLastError();
2157 HeapFree(GetProcessHeap(), 0, url_name);
2158 if (!bSuccess)
2159 SetLastError(dwError);
2161 return bSuccess;
2163 /***********************************************************************
2164 * CreateUrlCacheEntryW (WININET.@)
2167 BOOL WINAPI CreateUrlCacheEntryW(
2168 IN LPCWSTR lpszUrlName,
2169 IN DWORD dwExpectedFileSize,
2170 IN LPCWSTR lpszFileExtension,
2171 OUT LPWSTR lpszFileName,
2172 IN DWORD dwReserved
2175 URLCACHECONTAINER * pContainer;
2176 LPURLCACHE_HEADER pHeader;
2177 CHAR szFile[MAX_PATH];
2178 WCHAR szExtension[MAX_PATH];
2179 LPCWSTR lpszUrlPart;
2180 LPCWSTR lpszUrlEnd;
2181 LPCWSTR lpszFileNameExtension;
2182 LPWSTR lpszFileNameNoPath;
2183 int i;
2184 int countnoextension;
2185 BYTE CacheDir;
2186 LONG lBufferSize;
2187 BOOL bFound = FALSE;
2188 int count;
2189 DWORD error;
2190 static const WCHAR szWWW[] = {'w','w','w',0};
2192 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2193 debugstr_w(lpszUrlName),
2194 dwExpectedFileSize,
2195 debugstr_w(lpszFileExtension),
2196 lpszFileName,
2197 dwReserved);
2199 if (dwReserved)
2201 ERR("dwReserved != 0\n");
2202 SetLastError(ERROR_INVALID_PARAMETER);
2203 return FALSE;
2206 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2208 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2209 lpszUrlEnd--;
2211 for (lpszUrlPart = lpszUrlEnd;
2212 (lpszUrlPart >= lpszUrlName);
2213 lpszUrlPart--)
2215 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2217 bFound = TRUE;
2218 lpszUrlPart++;
2219 break;
2221 else if(*lpszUrlPart == '?' || *lpszUrlPart == '#')
2223 lpszUrlEnd = lpszUrlPart;
2226 if (!lstrcmpW(lpszUrlPart, szWWW))
2228 lpszUrlPart += lstrlenW(szWWW);
2231 count = lpszUrlEnd - lpszUrlPart;
2233 if (bFound && (count < MAX_PATH))
2235 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2236 if (!len)
2237 return FALSE;
2238 szFile[len] = '\0';
2239 /* FIXME: get rid of illegal characters like \, / and : */
2241 else
2243 FIXME("need to generate a random filename\n");
2246 TRACE("File name: %s\n", debugstr_a(szFile));
2248 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2249 if (error != ERROR_SUCCESS)
2251 SetLastError(error);
2252 return FALSE;
2255 error = URLCacheContainer_OpenIndex(pContainer);
2256 if (error != ERROR_SUCCESS)
2258 SetLastError(error);
2259 return FALSE;
2262 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2263 return FALSE;
2265 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2267 lBufferSize = MAX_PATH * sizeof(WCHAR);
2268 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
2270 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2272 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2273 lpszFileNameNoPath >= lpszFileName;
2274 --lpszFileNameNoPath)
2276 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2277 break;
2280 countnoextension = lstrlenW(lpszFileNameNoPath);
2281 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2282 if (lpszFileNameExtension)
2283 countnoextension -= lstrlenW(lpszFileNameExtension);
2284 *szExtension = '\0';
2286 if (lpszFileExtension)
2288 szExtension[0] = '.';
2289 lstrcpyW(szExtension+1, lpszFileExtension);
2292 for (i = 0; i < 255; i++)
2294 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2295 HANDLE hFile;
2296 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2297 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2298 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2299 if (hFile != INVALID_HANDLE_VALUE)
2301 CloseHandle(hFile);
2302 return TRUE;
2306 return FALSE;
2310 /***********************************************************************
2311 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2313 * The bug we are compensating for is that some drongo at Microsoft
2314 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2315 * As a consequence, CommitUrlCacheEntryA has been effectively
2316 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2317 * is still defined as LPCWSTR. The result (other than madness) is
2318 * that we always need to store lpHeaderInfo in CP_ACP rather than
2319 * in UTF16, and we need to avoid converting lpHeaderInfo in
2320 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2321 * result will lose data for arbitrary binary data.
2324 static BOOL WINAPI CommitUrlCacheEntryInternal(
2325 IN LPCWSTR lpszUrlName,
2326 IN LPCWSTR lpszLocalFileName,
2327 IN FILETIME ExpireTime,
2328 IN FILETIME LastModifiedTime,
2329 IN DWORD CacheEntryType,
2330 IN LPBYTE lpHeaderInfo,
2331 IN DWORD dwHeaderSize,
2332 IN LPCWSTR lpszFileExtension,
2333 IN LPCWSTR lpszOriginalUrl
2336 URLCACHECONTAINER * pContainer;
2337 LPURLCACHE_HEADER pHeader;
2338 struct _HASH_ENTRY * pHashEntry;
2339 CACHEFILE_ENTRY * pEntry;
2340 URL_CACHEFILE_ENTRY * pUrlEntry;
2341 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2342 DWORD dwOffsetLocalFileName = 0;
2343 DWORD dwOffsetHeader = 0;
2344 DWORD dwOffsetFileExtension = 0;
2345 DWORD dwFileSizeLow = 0;
2346 DWORD dwFileSizeHigh = 0;
2347 BYTE cDirectory = 0;
2348 int len;
2349 char achFile[MAX_PATH];
2350 LPSTR lpszUrlNameA = NULL;
2351 LPSTR lpszFileExtensionA = NULL;
2352 char *pchLocalFileName = 0;
2353 DWORD error;
2355 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2356 debugstr_w(lpszUrlName),
2357 debugstr_w(lpszLocalFileName),
2358 CacheEntryType,
2359 lpHeaderInfo,
2360 dwHeaderSize,
2361 debugstr_w(lpszFileExtension),
2362 debugstr_w(lpszOriginalUrl));
2364 if (lpszOriginalUrl)
2365 WARN(": lpszOriginalUrl ignored\n");
2367 if (lpszLocalFileName)
2369 HANDLE hFile;
2371 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2372 if (hFile == INVALID_HANDLE_VALUE)
2374 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2375 return FALSE;
2378 /* Get file size */
2379 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2380 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2382 ERR("couldn't get file size (error is %d)\n", GetLastError());
2383 CloseHandle(hFile);
2384 return FALSE;
2387 CloseHandle(hFile);
2390 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2391 if (error != ERROR_SUCCESS)
2393 SetLastError(error);
2394 return FALSE;
2397 error = URLCacheContainer_OpenIndex(pContainer);
2398 if (error != ERROR_SUCCESS)
2400 SetLastError(error);
2401 return FALSE;
2404 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2405 return FALSE;
2407 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2408 lpszUrlNameA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2409 if (!lpszUrlNameA)
2411 error = GetLastError();
2412 goto cleanup;
2414 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, lpszUrlNameA, len, NULL, NULL);
2416 if (lpszFileExtension)
2418 len = WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, NULL, 0, NULL, NULL);
2419 lpszFileExtensionA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2420 if (!lpszFileExtensionA)
2422 error = GetLastError();
2423 goto cleanup;
2425 WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, lpszFileExtensionA, len, NULL, NULL);
2428 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2430 FIXME("entry already in cache - don't know what to do!\n");
2432 * SetLastError(ERROR_FILE_NOT_FOUND);
2433 * return FALSE;
2435 goto cleanup;
2438 if (lpszLocalFileName)
2440 BOOL bFound = FALSE;
2442 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2444 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2445 error = ERROR_INVALID_PARAMETER;
2446 goto cleanup;
2449 /* skip container path prefix */
2450 lpszLocalFileName += lstrlenW(pContainer->path);
2452 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL);
2453 pchLocalFileName = achFile;
2455 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2457 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2459 bFound = TRUE;
2460 break;
2464 if (!bFound)
2466 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2467 error = ERROR_INVALID_PARAMETER;
2468 goto cleanup;
2471 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2474 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2475 if (lpszLocalFileName)
2477 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2478 dwOffsetLocalFileName = dwBytesNeeded;
2479 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2481 if (lpHeaderInfo)
2483 dwOffsetHeader = dwBytesNeeded;
2484 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2486 if (lpszFileExtensionA)
2488 dwOffsetFileExtension = dwBytesNeeded;
2489 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2492 /* round up to next block */
2493 if (dwBytesNeeded % BLOCKSIZE)
2495 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2496 dwBytesNeeded += BLOCKSIZE;
2499 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2501 ERR("no free entries\n");
2502 error = ERROR_DISK_FULL;
2503 goto cleanup;
2506 /* FindFirstFreeEntry fills in blocks used */
2507 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2508 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2509 pUrlEntry->CacheDir = cDirectory;
2510 pUrlEntry->CacheEntryType = CacheEntryType;
2511 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2512 pUrlEntry->dwExemptDelta = 0;
2513 pUrlEntry->dwHitRate = 0;
2514 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2515 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2516 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2517 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2518 pUrlEntry->dwSizeHigh = 0;
2519 pUrlEntry->dwSizeLow = dwFileSizeLow;
2520 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2521 pUrlEntry->dwUseCount = 0;
2522 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2523 pUrlEntry->LastModifiedTime = LastModifiedTime;
2524 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2525 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2526 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2527 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2529 /*** Unknowns ***/
2530 pUrlEntry->dwUnknown1 = 0;
2531 pUrlEntry->dwUnknown2 = 0;
2532 pUrlEntry->dwUnknown3 = 0x60;
2533 pUrlEntry->Unknown4 = 0;
2534 pUrlEntry->wUnknown5 = 0x1010;
2535 pUrlEntry->dwUnknown7 = 0;
2536 pUrlEntry->dwUnknown8 = 0;
2539 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2540 if (dwOffsetLocalFileName)
2541 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2542 if (dwOffsetHeader)
2543 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2544 if (dwOffsetFileExtension)
2545 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2547 error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA,
2548 (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader));
2549 if (error != ERROR_SUCCESS)
2550 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2552 cleanup:
2553 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2554 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2555 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2557 if (error == ERROR_SUCCESS)
2558 return TRUE;
2559 else
2561 SetLastError(error);
2562 return FALSE;
2566 /***********************************************************************
2567 * CommitUrlCacheEntryA (WININET.@)
2570 BOOL WINAPI CommitUrlCacheEntryA(
2571 IN LPCSTR lpszUrlName,
2572 IN LPCSTR lpszLocalFileName,
2573 IN FILETIME ExpireTime,
2574 IN FILETIME LastModifiedTime,
2575 IN DWORD CacheEntryType,
2576 IN LPBYTE lpHeaderInfo,
2577 IN DWORD dwHeaderSize,
2578 IN LPCSTR lpszFileExtension,
2579 IN LPCSTR lpszOriginalUrl
2582 DWORD len;
2583 WCHAR *url_name = NULL;
2584 WCHAR *local_file_name = NULL;
2585 WCHAR *original_url = NULL;
2586 WCHAR *file_extension = NULL;
2587 BOOL bSuccess = FALSE;
2589 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2590 debugstr_a(lpszUrlName),
2591 debugstr_a(lpszLocalFileName),
2592 CacheEntryType,
2593 lpHeaderInfo,
2594 dwHeaderSize,
2595 debugstr_a(lpszFileExtension),
2596 debugstr_a(lpszOriginalUrl));
2598 len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0);
2599 url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2600 if (!url_name)
2601 goto cleanup;
2602 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2604 if (lpszLocalFileName)
2606 len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0);
2607 local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2608 if (!local_file_name)
2609 goto cleanup;
2610 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2612 if (lpszFileExtension)
2614 len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0);
2615 file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2616 if (!file_extension)
2617 goto cleanup;
2618 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2620 if (lpszOriginalUrl)
2622 len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0);
2623 original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2624 if (!original_url)
2625 goto cleanup;
2626 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2629 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2630 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2631 file_extension, original_url);
2633 cleanup:
2634 HeapFree(GetProcessHeap(), 0, original_url);
2635 HeapFree(GetProcessHeap(), 0, file_extension);
2636 HeapFree(GetProcessHeap(), 0, local_file_name);
2637 HeapFree(GetProcessHeap(), 0, url_name);
2639 return bSuccess;
2642 /***********************************************************************
2643 * CommitUrlCacheEntryW (WININET.@)
2646 BOOL WINAPI CommitUrlCacheEntryW(
2647 IN LPCWSTR lpszUrlName,
2648 IN LPCWSTR lpszLocalFileName,
2649 IN FILETIME ExpireTime,
2650 IN FILETIME LastModifiedTime,
2651 IN DWORD CacheEntryType,
2652 IN LPWSTR lpHeaderInfo,
2653 IN DWORD dwHeaderSize,
2654 IN LPCWSTR lpszFileExtension,
2655 IN LPCWSTR lpszOriginalUrl
2658 DWORD dwError = 0;
2659 BOOL bSuccess = FALSE;
2660 DWORD len = 0;
2661 CHAR *header_info = NULL;
2663 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2664 debugstr_w(lpszUrlName),
2665 debugstr_w(lpszLocalFileName),
2666 CacheEntryType,
2667 lpHeaderInfo,
2668 dwHeaderSize,
2669 debugstr_w(lpszFileExtension),
2670 debugstr_w(lpszOriginalUrl));
2672 if (!lpHeaderInfo ||
2673 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2674 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2676 if (header_info)
2677 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2678 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2679 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2681 bSuccess = TRUE;
2683 else
2685 dwError = GetLastError();
2687 if (header_info)
2689 HeapFree(GetProcessHeap(), 0, header_info);
2690 if (!bSuccess)
2691 SetLastError(dwError);
2694 return bSuccess;
2697 /***********************************************************************
2698 * ReadUrlCacheEntryStream (WININET.@)
2701 BOOL WINAPI ReadUrlCacheEntryStream(
2702 IN HANDLE hUrlCacheStream,
2703 IN DWORD dwLocation,
2704 IN OUT LPVOID lpBuffer,
2705 IN OUT LPDWORD lpdwLen,
2706 IN DWORD dwReserved
2709 /* Get handle to file from 'stream' */
2710 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2712 if (dwReserved != 0)
2714 ERR("dwReserved != 0\n");
2715 SetLastError(ERROR_INVALID_PARAMETER);
2716 return FALSE;
2719 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2721 SetLastError(ERROR_INVALID_HANDLE);
2722 return FALSE;
2725 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2726 return FALSE;
2727 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2730 /***********************************************************************
2731 * RetrieveUrlCacheEntryStreamA (WININET.@)
2734 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2735 IN LPCSTR lpszUrlName,
2736 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2737 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2738 IN BOOL fRandomRead,
2739 IN DWORD dwReserved
2742 /* NOTE: this is not the same as the way that the native
2743 * version allocates 'stream' handles. I did it this way
2744 * as it is much easier and no applications should depend
2745 * on this behaviour. (Native version appears to allocate
2746 * indices into a table)
2748 STREAM_HANDLE * pStream;
2749 HANDLE hFile;
2751 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2752 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2754 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2755 lpCacheEntryInfo,
2756 lpdwCacheEntryInfoBufferSize,
2757 dwReserved))
2759 return NULL;
2762 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2763 GENERIC_READ,
2764 FILE_SHARE_READ,
2765 NULL,
2766 OPEN_EXISTING,
2767 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2768 NULL);
2769 if (hFile == INVALID_HANDLE_VALUE)
2770 return FALSE;
2772 /* allocate handle storage space */
2773 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2774 if (!pStream)
2776 CloseHandle(hFile);
2777 SetLastError(ERROR_OUTOFMEMORY);
2778 return FALSE;
2781 pStream->hFile = hFile;
2782 strcpy(pStream->lpszUrl, lpszUrlName);
2783 return (HANDLE)pStream;
2786 /***********************************************************************
2787 * RetrieveUrlCacheEntryStreamW (WININET.@)
2790 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2791 IN LPCWSTR lpszUrlName,
2792 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2793 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2794 IN BOOL fRandomRead,
2795 IN DWORD dwReserved
2798 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2799 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2800 return NULL;
2803 /***********************************************************************
2804 * UnlockUrlCacheEntryStream (WININET.@)
2807 BOOL WINAPI UnlockUrlCacheEntryStream(
2808 IN HANDLE hUrlCacheStream,
2809 IN DWORD dwReserved
2812 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2814 if (dwReserved != 0)
2816 ERR("dwReserved != 0\n");
2817 SetLastError(ERROR_INVALID_PARAMETER);
2818 return FALSE;
2821 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2823 SetLastError(ERROR_INVALID_HANDLE);
2824 return FALSE;
2827 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2828 return FALSE;
2830 /* close file handle */
2831 CloseHandle(pStream->hFile);
2833 /* free allocated space */
2834 HeapFree(GetProcessHeap(), 0, pStream);
2836 return TRUE;
2840 /***********************************************************************
2841 * DeleteUrlCacheEntryA (WININET.@)
2844 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2846 URLCACHECONTAINER * pContainer;
2847 LPURLCACHE_HEADER pHeader;
2848 struct _HASH_ENTRY * pHashEntry;
2849 CACHEFILE_ENTRY * pEntry;
2850 DWORD error;
2852 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2854 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2855 if (error != ERROR_SUCCESS)
2857 SetLastError(error);
2858 return FALSE;
2861 error = URLCacheContainer_OpenIndex(pContainer);
2862 if (error != ERROR_SUCCESS)
2864 SetLastError(error);
2865 return FALSE;
2868 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2869 return FALSE;
2871 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2873 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2874 TRACE("entry %s not found!\n", lpszUrlName);
2875 SetLastError(ERROR_FILE_NOT_FOUND);
2876 return FALSE;
2879 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2880 URLCache_DeleteEntry(pHeader, pEntry);
2882 URLCache_DeleteEntryFromHash(pHashEntry);
2884 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2886 return TRUE;
2889 /***********************************************************************
2890 * DeleteUrlCacheEntryW (WININET.@)
2893 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2895 URLCACHECONTAINER * pContainer;
2896 LPURLCACHE_HEADER pHeader;
2897 struct _HASH_ENTRY * pHashEntry;
2898 CACHEFILE_ENTRY * pEntry;
2899 LPSTR urlA;
2900 int url_len;
2901 DWORD error;
2903 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2905 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2906 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
2907 if (!urlA)
2909 SetLastError(ERROR_OUTOFMEMORY);
2910 return FALSE;
2912 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, urlA, url_len, NULL, NULL);
2914 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2915 if (error != ERROR_SUCCESS)
2917 HeapFree(GetProcessHeap(), 0, urlA);
2918 SetLastError(error);
2919 return FALSE;
2922 error = URLCacheContainer_OpenIndex(pContainer);
2923 if (error != ERROR_SUCCESS)
2925 HeapFree(GetProcessHeap(), 0, urlA);
2926 SetLastError(error);
2927 return FALSE;
2930 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2932 HeapFree(GetProcessHeap(), 0, urlA);
2933 return FALSE;
2936 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
2938 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2939 TRACE("entry %s not found!\n", debugstr_a(urlA));
2940 HeapFree(GetProcessHeap(), 0, urlA);
2941 SetLastError(ERROR_FILE_NOT_FOUND);
2942 return FALSE;
2945 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2946 URLCache_DeleteEntry(pHeader, pEntry);
2948 URLCache_DeleteEntryFromHash(pHashEntry);
2950 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2952 HeapFree(GetProcessHeap(), 0, urlA);
2953 return TRUE;
2956 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2958 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2959 return TRUE;
2962 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2964 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2965 return TRUE;
2968 /***********************************************************************
2969 * CreateCacheContainerA (WININET.@)
2971 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2972 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2974 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2975 d1, d2, d3, d4, d5, d6, d7, d8);
2976 return TRUE;
2979 /***********************************************************************
2980 * CreateCacheContainerW (WININET.@)
2982 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2983 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2985 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2986 d1, d2, d3, d4, d5, d6, d7, d8);
2987 return TRUE;
2990 /***********************************************************************
2991 * FindFirstUrlCacheContainerA (WININET.@)
2993 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2995 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
2996 return NULL;
2999 /***********************************************************************
3000 * FindFirstUrlCacheContainerW (WININET.@)
3002 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3004 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3005 return NULL;
3008 /***********************************************************************
3009 * FindNextUrlCacheContainerA (WININET.@)
3011 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
3013 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3014 return FALSE;
3017 /***********************************************************************
3018 * FindNextUrlCacheContainerW (WININET.@)
3020 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
3022 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3023 return FALSE;
3026 HANDLE WINAPI FindFirstUrlCacheEntryExA(
3027 LPCSTR lpszUrlSearchPattern,
3028 DWORD dwFlags,
3029 DWORD dwFilter,
3030 GROUPID GroupId,
3031 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3032 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3033 LPVOID lpReserved,
3034 LPDWORD pcbReserved2,
3035 LPVOID lpReserved3
3038 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
3039 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3040 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3041 SetLastError(ERROR_FILE_NOT_FOUND);
3042 return NULL;
3045 HANDLE WINAPI FindFirstUrlCacheEntryExW(
3046 LPCWSTR lpszUrlSearchPattern,
3047 DWORD dwFlags,
3048 DWORD dwFilter,
3049 GROUPID GroupId,
3050 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3051 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3052 LPVOID lpReserved,
3053 LPDWORD pcbReserved2,
3054 LPVOID lpReserved3
3057 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
3058 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3059 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3060 SetLastError(ERROR_FILE_NOT_FOUND);
3061 return NULL;
3064 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3066 typedef struct URLCacheFindEntryHandle
3068 DWORD dwMagic;
3069 LPWSTR lpszUrlSearchPattern;
3070 DWORD dwContainerIndex;
3071 DWORD dwHashTableIndex;
3072 DWORD dwHashEntryIndex;
3073 } URLCacheFindEntryHandle;
3075 /***********************************************************************
3076 * FindFirstUrlCacheEntryA (WININET.@)
3079 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
3080 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3082 URLCacheFindEntryHandle *pEntryHandle;
3084 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3086 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3087 if (!pEntryHandle)
3088 return NULL;
3090 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3091 if (lpszUrlSearchPattern)
3093 int len = MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, NULL, 0);
3094 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3095 if (!pEntryHandle->lpszUrlSearchPattern)
3097 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3098 return NULL;
3100 MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, pEntryHandle->lpszUrlSearchPattern, len);
3102 else
3103 pEntryHandle->lpszUrlSearchPattern = NULL;
3104 pEntryHandle->dwContainerIndex = 0;
3105 pEntryHandle->dwHashTableIndex = 0;
3106 pEntryHandle->dwHashEntryIndex = 0;
3108 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3110 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3111 return NULL;
3113 return pEntryHandle;
3116 /***********************************************************************
3117 * FindFirstUrlCacheEntryW (WININET.@)
3120 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3121 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3123 URLCacheFindEntryHandle *pEntryHandle;
3125 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3127 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3128 if (!pEntryHandle)
3129 return NULL;
3131 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3132 if (lpszUrlSearchPattern)
3134 int len = strlenW(lpszUrlSearchPattern);
3135 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
3136 if (!pEntryHandle->lpszUrlSearchPattern)
3138 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3139 return NULL;
3141 memcpy(pEntryHandle->lpszUrlSearchPattern, lpszUrlSearchPattern, (len + 1) * sizeof(WCHAR));
3143 else
3144 pEntryHandle->lpszUrlSearchPattern = NULL;
3145 pEntryHandle->dwContainerIndex = 0;
3146 pEntryHandle->dwHashTableIndex = 0;
3147 pEntryHandle->dwHashEntryIndex = 0;
3149 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3151 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3152 return NULL;
3154 return pEntryHandle;
3157 /***********************************************************************
3158 * FindNextUrlCacheEntryA (WININET.@)
3160 BOOL WINAPI FindNextUrlCacheEntryA(
3161 HANDLE hEnumHandle,
3162 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3163 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3165 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3166 URLCACHECONTAINER * pContainer;
3168 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3170 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3172 SetLastError(ERROR_INVALID_HANDLE);
3173 return FALSE;
3176 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3177 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3179 LPURLCACHE_HEADER pHeader;
3180 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3181 DWORD error;
3183 error = URLCacheContainer_OpenIndex(pContainer);
3184 if (error != ERROR_SUCCESS)
3186 SetLastError(error);
3187 return FALSE;
3190 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3191 return FALSE;
3193 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3194 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3196 const struct _HASH_ENTRY *pHashEntry = NULL;
3197 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3198 pEntryHandle->dwHashEntryIndex++)
3200 const URL_CACHEFILE_ENTRY *pUrlEntry;
3201 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3203 if (pEntry->dwSignature != URL_SIGNATURE)
3204 continue;
3206 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3207 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3208 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3210 error = URLCache_CopyEntry(
3211 pContainer,
3212 pHeader,
3213 lpNextCacheEntryInfo,
3214 lpdwNextCacheEntryInfoBufferSize,
3215 pUrlEntry,
3216 FALSE /* not UNICODE */);
3217 if (error != ERROR_SUCCESS)
3219 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3220 SetLastError(error);
3221 return FALSE;
3223 TRACE("Local File Name: %s\n", debugstr_a(lpNextCacheEntryInfo->lpszLocalFileName));
3225 /* increment the current index so that next time the function
3226 * is called the next entry is returned */
3227 pEntryHandle->dwHashEntryIndex++;
3228 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3229 return TRUE;
3233 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3236 SetLastError(ERROR_NO_MORE_ITEMS);
3237 return FALSE;
3240 /***********************************************************************
3241 * FindNextUrlCacheEntryW (WININET.@)
3243 BOOL WINAPI FindNextUrlCacheEntryW(
3244 HANDLE hEnumHandle,
3245 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3246 LPDWORD lpdwNextCacheEntryInfoBufferSize
3249 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3250 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3251 return FALSE;
3254 /***********************************************************************
3255 * FindCloseUrlCache (WININET.@)
3257 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3259 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3261 TRACE("(%p)\n", hEnumHandle);
3263 if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3265 SetLastError(ERROR_INVALID_HANDLE);
3266 return FALSE;
3269 pEntryHandle->dwMagic = 0;
3270 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3271 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3273 return TRUE;
3276 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3277 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3279 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3280 dwSearchCondition, lpGroupId, lpReserved);
3281 return NULL;
3284 BOOL WINAPI FindNextUrlCacheEntryExA(
3285 HANDLE hEnumHandle,
3286 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3287 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3288 LPVOID lpReserved,
3289 LPDWORD pcbReserved2,
3290 LPVOID lpReserved3
3293 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3294 lpReserved, pcbReserved2, lpReserved3);
3295 return FALSE;
3298 BOOL WINAPI FindNextUrlCacheEntryExW(
3299 HANDLE hEnumHandle,
3300 LPINTERNET_CACHE_ENTRY_INFOW 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 FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3314 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3315 return FALSE;
3318 /***********************************************************************
3319 * CreateUrlCacheGroup (WININET.@)
3322 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3324 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3325 return FALSE;
3328 /***********************************************************************
3329 * DeleteUrlCacheGroup (WININET.@)
3332 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3334 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3335 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3336 return FALSE;
3339 /***********************************************************************
3340 * SetUrlCacheEntryGroupA (WININET.@)
3343 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3344 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3345 LPVOID lpReserved)
3347 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3348 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3349 pbGroupAttributes, cbGroupAttributes, lpReserved);
3350 SetLastError(ERROR_FILE_NOT_FOUND);
3351 return FALSE;
3354 /***********************************************************************
3355 * SetUrlCacheEntryGroupW (WININET.@)
3358 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3359 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3360 LPVOID lpReserved)
3362 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3363 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3364 pbGroupAttributes, cbGroupAttributes, lpReserved);
3365 SetLastError(ERROR_FILE_NOT_FOUND);
3366 return FALSE;
3369 /***********************************************************************
3370 * GetUrlCacheConfigInfoW (WININET.@)
3372 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3374 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3375 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3376 return FALSE;
3379 /***********************************************************************
3380 * GetUrlCacheConfigInfoA (WININET.@)
3382 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3384 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3386 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3387 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3388 return FALSE;
3391 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3392 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3393 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3395 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3396 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3397 lpdwGroupInfo, lpReserved);
3398 return FALSE;
3401 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3402 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3403 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3405 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3406 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3407 lpdwGroupInfo, lpReserved);
3408 return FALSE;
3411 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3412 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3414 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3415 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3416 return TRUE;
3419 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3420 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3422 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3423 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3424 return TRUE;
3427 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3429 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3430 return TRUE;
3433 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3435 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3436 return TRUE;
3439 /***********************************************************************
3440 * DeleteIE3Cache (WININET.@)
3442 * Deletes the files used by the IE3 URL caching system.
3444 * PARAMS
3445 * hWnd [I] A dummy window.
3446 * hInst [I] Instance of process calling the function.
3447 * lpszCmdLine [I] Options used by function.
3448 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3450 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3452 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3453 return 0;
3456 /***********************************************************************
3457 * IsUrlCacheEntryExpiredA (WININET.@)
3459 * PARAMS
3460 * url [I] Url
3461 * dwFlags [I] Unknown
3462 * pftLastModified [O] Last modified time
3464 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3466 LPURLCACHE_HEADER pHeader;
3467 struct _HASH_ENTRY * pHashEntry;
3468 const CACHEFILE_ENTRY * pEntry;
3469 const URL_CACHEFILE_ENTRY * pUrlEntry;
3470 URLCACHECONTAINER * pContainer;
3471 DWORD error;
3473 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3475 error = URLCacheContainers_FindContainerA(url, &pContainer);
3476 if (error != ERROR_SUCCESS)
3478 SetLastError(error);
3479 return FALSE;
3482 error = URLCacheContainer_OpenIndex(pContainer);
3483 if (error != ERROR_SUCCESS)
3485 SetLastError(error);
3486 return FALSE;
3489 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3490 return FALSE;
3492 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3494 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3495 TRACE("entry %s not found!\n", url);
3496 SetLastError(ERROR_FILE_NOT_FOUND);
3497 return FALSE;
3500 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3501 if (pEntry->dwSignature != URL_SIGNATURE)
3503 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3504 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3505 SetLastError(ERROR_FILE_NOT_FOUND);
3506 return FALSE;
3509 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3511 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3513 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3515 return TRUE;
3518 /***********************************************************************
3519 * IsUrlCacheEntryExpiredW (WININET.@)
3521 * PARAMS
3522 * url [I] Url
3523 * dwFlags [I] Unknown
3524 * pftLastModified [O] Last modified time
3526 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3528 LPURLCACHE_HEADER pHeader;
3529 struct _HASH_ENTRY * pHashEntry;
3530 const CACHEFILE_ENTRY * pEntry;
3531 const URL_CACHEFILE_ENTRY * pUrlEntry;
3532 URLCACHECONTAINER * pContainer;
3533 DWORD error;
3535 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3537 error = URLCacheContainers_FindContainerW(url, &pContainer);
3538 if (error != ERROR_SUCCESS)
3540 SetLastError(error);
3541 return FALSE;
3544 error = URLCacheContainer_OpenIndex(pContainer);
3545 if (error != ERROR_SUCCESS)
3547 SetLastError(error);
3548 return FALSE;
3551 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3552 return FALSE;
3554 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3556 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3557 TRACE("entry %s not found!\n", debugstr_w(url));
3558 SetLastError(ERROR_FILE_NOT_FOUND);
3559 return FALSE;
3562 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3563 if (pEntry->dwSignature != URL_SIGNATURE)
3565 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3566 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3567 SetLastError(ERROR_FILE_NOT_FOUND);
3568 return FALSE;
3571 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3573 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3575 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3577 return TRUE;