Release 0.9.61.
[wine/gsoc-2012-control.git] / dlls / wininet / urlcache.c
blobf34451a19476e8910ae78ab9dd45280bdf515996
1 /*
2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003 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 HASH_CACHEFILE_ENTRY *URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash);
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 * TRUE if succeeded
210 * FALSE if failed
213 static BOOL 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 TRUE;
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 FALSE;
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 FALSE;
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 = 0;
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)
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;
300 dwFileSize = NEWFILE_SIZE;
302 /* First set some constants and defaults in the header */
303 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
304 pHeader->dwFileSize = dwFileSize;
305 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
306 /* 127MB - taken from default for Windows 2000 */
307 pHeader->dwCacheLimitHigh = 0;
308 pHeader->dwCacheLimitLow = 0x07ff5400;
309 /* Copied from a Windows 2000 cache index */
310 pHeader->DirectoryCount = 4;
312 /* If the registry has a cache size set, use the registry value */
313 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
315 DWORD dw;
316 DWORD len = sizeof(dw);
317 DWORD keytype;
319 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
320 (BYTE *) &dw, &len) == ERROR_SUCCESS &&
321 keytype == REG_DWORD)
323 pHeader->dwCacheLimitHigh = (dw >> 22);
324 pHeader->dwCacheLimitLow = dw << 10;
326 RegCloseKey(key);
329 URLCache_CreateHashTable(pHeader, NULL);
331 /* Last step - create the directories */
333 strcpyW(wszDirPath, pContainer->path);
334 pwchDir = wszDirPath + strlenW(wszDirPath);
335 pwchDir[8] = 0;
337 GetSystemTimeAsFileTime(&ft);
339 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
341 /* The following values were copied from a Windows index.
342 * I don't know what the values are supposed to mean but
343 * have made them the same in the hope that this will
344 * be better for compatibility
346 pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
347 for (j = 0;; ++j)
349 int k;
350 ULONGLONG n = ft.dwHighDateTime;
352 /* Generate a file name to attempt to create.
353 * This algorithm will create what will appear
354 * to be random and unrelated directory names
355 * of up to 9 characters in length.
357 n <<= 32;
358 n += ft.dwLowDateTime;
359 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
361 for (k = 0; k < 8; ++k)
363 int r = (n % 36);
365 /* Dividing by a prime greater than 36 helps
366 * with the appearance of randomness
368 n /= 37;
370 if (r < 10)
371 pwchDir[k] = '0' + r;
372 else
373 pwchDir[k] = 'A' + (r - 10);
376 if (CreateDirectoryW(wszDirPath, 0))
378 /* The following is OK because we generated an
379 * 8 character directory name made from characters
380 * [A-Z0-9], which are equivalent for all code
381 * pages and for UTF-16
383 for (k = 0; k < 8; ++k)
384 pHeader->directory_data[i].filename[k] = pwchDir[k];
385 break;
387 else if (j >= 255)
389 /* Give up. The most likely cause of this
390 * is a full disk, but whatever the cause
391 * is, it should be more than apparent that
392 * we won't succeed.
394 dwError = GetLastError();
395 break;
400 UnmapViewOfFile(pHeader);
402 else
404 dwError = GetLastError();
406 CloseHandle(hMapping);
408 else
410 dwError = GetLastError();
414 if (dwError)
416 CloseHandle(hFile);
417 DeleteFileW(wszFilePath);
418 ReleaseMutex(pContainer->hMutex);
419 SetLastError(dwError);
420 return FALSE;
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 FALSE;
439 return TRUE;
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 BOOL 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 TRUE;
598 ERR("no container found\n");
599 SetLastError(ERROR_FILE_NOT_FOUND);
600 return FALSE;
603 static BOOL URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
605 BOOL ret;
606 LPWSTR lpwszUrl;
607 int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
608 if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR))))
610 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len);
611 ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer);
612 HeapFree(GetProcessHeap(), 0, lpwszUrl);
613 return ret;
615 return FALSE;
618 static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, URLCACHECONTAINER ** ppContainer)
620 DWORD i = 0;
621 URLCACHECONTAINER * pContainer;
623 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern));
625 /* non-NULL search pattern only returns one container ever */
626 if (lpwszSearchPattern && dwIndex > 0)
627 return FALSE;
629 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
631 if (lpwszSearchPattern)
633 if (!strcmpW(pContainer->cache_prefix, lpwszSearchPattern))
635 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
636 *ppContainer = pContainer;
637 return TRUE;
640 else
642 if (i == dwIndex)
644 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
645 *ppContainer = pContainer;
646 return TRUE;
649 i++;
651 return FALSE;
654 /***********************************************************************
655 * URLCacheContainer_LockIndex (Internal)
658 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
660 BYTE index;
661 LPVOID pIndexData;
662 URLCACHE_HEADER * pHeader;
664 /* acquire mutex */
665 WaitForSingleObject(pContainer->hMutex, INFINITE);
667 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
669 if (!pIndexData)
671 ReleaseMutex(pContainer->hMutex);
672 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
673 return FALSE;
675 pHeader = (URLCACHE_HEADER *)pIndexData;
677 /* file has grown - we need to remap to prevent us getting
678 * access violations when we try and access beyond the end
679 * of the memory mapped file */
680 if (pHeader->dwFileSize != pContainer->file_size)
682 URLCacheContainer_CloseIndex(pContainer);
683 if (!URLCacheContainer_OpenIndex(pContainer))
685 ReleaseMutex(pContainer->hMutex);
686 return FALSE;
688 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
690 if (!pIndexData)
692 ReleaseMutex(pContainer->hMutex);
693 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
694 return FALSE;
696 pHeader = (URLCACHE_HEADER *)pIndexData;
699 TRACE("Signature: %s, file size: %d bytes\n", pHeader->szSignature, pHeader->dwFileSize);
701 for (index = 0; index < pHeader->DirectoryCount; index++)
703 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
706 return pHeader;
709 /***********************************************************************
710 * URLCacheContainer_UnlockIndex (Internal)
713 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
715 /* release mutex */
716 ReleaseMutex(pContainer->hMutex);
717 return UnmapViewOfFile(pHeader);
721 #ifndef CHAR_BIT
722 #define CHAR_BIT (8 * sizeof(CHAR))
723 #endif
725 /***********************************************************************
726 * URLCache_Allocation_BlockIsFree (Internal)
728 * Is the specified block number free?
730 * RETURNS
731 * zero if free
732 * non-zero otherwise
735 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
737 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
738 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
741 /***********************************************************************
742 * URLCache_Allocation_BlockFree (Internal)
744 * Marks the specified block as free
746 * RETURNS
747 * nothing
750 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
752 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
753 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
756 /***********************************************************************
757 * URLCache_Allocation_BlockAllocate (Internal)
759 * Marks the specified block as allocated
761 * RETURNS
762 * nothing
765 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
767 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
768 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
771 /***********************************************************************
772 * URLCache_FindFirstFreeEntry (Internal)
774 * Finds and allocates the first block of free space big enough and
775 * sets ppEntry to point to it.
777 * RETURNS
778 * TRUE if it had enough space
779 * FALSE if it couldn't find enough space
782 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
784 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
785 DWORD dwBlockNumber;
786 DWORD dwFreeCounter;
787 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
789 for (dwFreeCounter = 0;
790 dwFreeCounter < dwBlocksNeeded &&
791 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
792 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
793 dwFreeCounter++)
794 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
796 if (dwFreeCounter == dwBlocksNeeded)
798 DWORD index;
799 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
800 for (index = 0; index < dwBlocksNeeded; index++)
801 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
802 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
803 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
804 return TRUE;
807 FIXME("Grow file\n");
808 return FALSE;
811 /***********************************************************************
812 * URLCache_DeleteEntry (Internal)
814 * Deletes the specified entry and frees the space allocated to it
816 * RETURNS
817 * TRUE if it succeeded
818 * FALSE if it failed
821 static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, CACHEFILE_ENTRY * pEntry)
823 DWORD dwStartBlock;
824 DWORD dwBlock;
825 BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
827 /* update allocation table */
828 dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE;
829 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
830 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
832 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
833 return TRUE;
836 /***********************************************************************
837 * URLCache_LocalFileNameToPathW (Internal)
839 * Copies the full path to the specified buffer given the local file
840 * name and the index of the directory it is in. Always sets value in
841 * lpBufferSize to the required buffer size (in bytes).
843 * RETURNS
844 * TRUE if the buffer was big enough
845 * FALSE if the buffer was too small
848 static BOOL URLCache_LocalFileNameToPathW(
849 const URLCACHECONTAINER * pContainer,
850 LPCURLCACHE_HEADER pHeader,
851 LPCSTR szLocalFileName,
852 BYTE Directory,
853 LPWSTR wszPath,
854 LPLONG lpBufferSize)
856 LONG nRequired;
857 int path_len = strlenW(pContainer->path);
858 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
859 if (Directory >= pHeader->DirectoryCount)
861 *lpBufferSize = 0;
862 return FALSE;
865 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
866 if (nRequired < *lpBufferSize)
868 int dir_len;
870 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
871 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
872 wszPath[dir_len + path_len] = '\\';
873 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
874 *lpBufferSize = nRequired;
875 return TRUE;
877 *lpBufferSize = nRequired;
878 return FALSE;
881 /***********************************************************************
882 * URLCache_LocalFileNameToPathA (Internal)
884 * Copies the full path to the specified buffer given the local file
885 * name and the index of the directory it is in. Always sets value in
886 * lpBufferSize to the required buffer size.
888 * RETURNS
889 * TRUE if the buffer was big enough
890 * FALSE if the buffer was too small
893 static BOOL URLCache_LocalFileNameToPathA(
894 const URLCACHECONTAINER * pContainer,
895 LPCURLCACHE_HEADER pHeader,
896 LPCSTR szLocalFileName,
897 BYTE Directory,
898 LPSTR szPath,
899 LPLONG lpBufferSize)
901 LONG nRequired;
902 int path_len, file_name_len, dir_len;
904 if (Directory >= pHeader->DirectoryCount)
906 *lpBufferSize = 0;
907 return FALSE;
910 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL) - 1;
911 file_name_len = strlen(szLocalFileName) + 1 /* for nul-terminator */;
912 dir_len = DIR_LENGTH;
914 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(char);
915 if (nRequired < *lpBufferSize)
917 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, path_len, NULL, NULL);
918 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
919 szPath[path_len + dir_len] = '\\';
920 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
921 *lpBufferSize = nRequired;
922 return TRUE;
924 *lpBufferSize = nRequired;
925 return FALSE;
928 /***********************************************************************
929 * URLCache_CopyEntry (Internal)
931 * Copies an entry from the cache index file to the Win32 structure
933 * RETURNS
934 * TRUE if the buffer was big enough
935 * FALSE if the buffer was too small
938 static BOOL URLCache_CopyEntry(
939 URLCACHECONTAINER * pContainer,
940 LPCURLCACHE_HEADER pHeader,
941 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
942 LPDWORD lpdwBufferSize,
943 const URL_CACHEFILE_ENTRY * pUrlEntry,
944 BOOL bUnicode)
946 int lenUrl;
947 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
949 if (*lpdwBufferSize >= dwRequiredSize)
951 lpCacheEntryInfo->lpHeaderInfo = NULL;
952 lpCacheEntryInfo->lpszFileExtension = NULL;
953 lpCacheEntryInfo->lpszLocalFileName = NULL;
954 lpCacheEntryInfo->lpszSourceUrlName = NULL;
955 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
956 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
957 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
958 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
959 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
960 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
961 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
962 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
963 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
964 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
965 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
966 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
967 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
968 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
971 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
972 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
973 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
974 if (bUnicode)
975 lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0);
976 else
977 lenUrl = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
978 dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
980 /* FIXME: is source url optional? */
981 if (*lpdwBufferSize >= dwRequiredSize)
983 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrl - 1;
984 if (bUnicode)
985 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
986 else
987 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, (lenUrl + 1) * sizeof(CHAR));
990 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
991 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
992 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
994 if (pUrlEntry->dwOffsetLocalName)
996 LONG nLocalFilePathSize;
997 LPSTR lpszLocalFileName;
998 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
999 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
1000 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
1001 URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize))
1003 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
1005 dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ;
1007 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1008 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1009 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1011 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
1013 if (*lpdwBufferSize >= dwRequiredSize)
1015 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
1016 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
1017 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
1019 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1020 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1021 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1023 if (pUrlEntry->dwOffsetFileExtension)
1025 int lenExtension;
1027 if (bUnicode)
1028 lenExtension = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, NULL, 0);
1029 else
1030 lenExtension = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension) + 1;
1031 dwRequiredSize += lenExtension * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
1033 if (*lpdwBufferSize >= dwRequiredSize)
1035 lpCacheEntryInfo->lpszFileExtension = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenExtension;
1036 if (bUnicode)
1037 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenExtension);
1038 else
1039 memcpy(lpCacheEntryInfo->lpszFileExtension, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, lenExtension * sizeof(CHAR));
1042 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1043 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1044 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1047 if (dwRequiredSize > *lpdwBufferSize)
1049 *lpdwBufferSize = dwRequiredSize;
1050 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1051 return FALSE;
1053 *lpdwBufferSize = dwRequiredSize;
1054 return TRUE;
1058 /***********************************************************************
1059 * URLCache_SetEntryInfo (Internal)
1061 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1062 * according to the flags set by dwFieldControl.
1064 * RETURNS
1065 * TRUE if the buffer was big enough
1066 * FALSE if the buffer was too small
1069 static BOOL URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1071 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1072 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1073 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1074 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1075 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1076 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1077 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1078 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1079 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1080 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1081 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1082 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1083 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1084 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1085 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1086 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1088 return TRUE;
1091 /***********************************************************************
1092 * URLCache_HashKey (Internal)
1094 * Returns the hash key for a given string
1096 * RETURNS
1097 * hash key for the string
1100 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1102 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1103 * but the algorithm and result are not the same!
1105 static const unsigned char lookupTable[256] =
1107 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1108 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1109 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1110 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1111 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1112 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1113 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1114 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1115 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1116 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1117 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1118 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1119 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1120 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1121 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1122 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1123 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1124 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1125 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1126 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1127 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1128 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1129 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1130 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1131 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1132 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1133 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1134 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1135 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1136 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1137 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1138 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1140 BYTE key[4];
1141 DWORD i;
1142 int subscript[sizeof(key) / sizeof(key[0])];
1144 subscript[0] = *lpszKey;
1145 subscript[1] = (char)(*lpszKey + 1);
1146 subscript[2] = (char)(*lpszKey + 2);
1147 subscript[3] = (char)(*lpszKey + 3);
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 * TRUE if the entry was added
1293 * FALSE if the entry could not be added
1296 static BOOL 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;
1305 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1307 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1308 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1309 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1311 int i;
1312 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1314 ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1315 break;
1317 /* make sure that it is in fact a hash entry */
1318 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1320 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1321 break;
1324 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1326 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1327 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1329 pHashElement->dwHashKey = key;
1330 pHashElement->dwOffsetEntry = dwOffsetEntry;
1331 return TRUE;
1335 pHashEntry = URLCache_CreateHashTable(pHeader, pHashEntry);
1336 if (!pHashEntry)
1337 return FALSE;
1339 pHashEntry->HashTable[offset].dwHashKey = key;
1340 pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry;
1341 return TRUE;
1344 /***********************************************************************
1345 * URLCache_CreateHashTable (Internal)
1347 * Creates a new hash table in free space and adds it to the chain of existing
1348 * hash tables.
1350 * RETURNS
1351 * TRUE if the hash table was created
1352 * FALSE if the hash table could not be created
1355 static HASH_CACHEFILE_ENTRY *URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash)
1357 HASH_CACHEFILE_ENTRY *pHash;
1358 DWORD dwOffset;
1359 int i;
1361 if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)&pHash))
1363 FIXME("no free space for hash table\n");
1364 SetLastError(ERROR_DISK_FULL);
1365 return NULL;
1368 dwOffset = (BYTE *)pHash - (BYTE *)pHeader;
1370 if (pPrevHash)
1371 pPrevHash->dwAddressNext = dwOffset;
1372 else
1373 pHeader->dwOffsetFirstHashTable = dwOffset;
1374 pHash->CacheFileEntry.dwSignature = HASH_SIGNATURE;
1375 pHash->CacheFileEntry.dwBlocksUsed = 0x20;
1376 pHash->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0;
1377 for (i = 0; i < HASHTABLE_SIZE; i++)
1379 pHash->HashTable[i].dwOffsetEntry = 0;
1380 pHash->HashTable[i].dwHashKey = HASHTABLE_FREE;
1382 return pHash;
1385 /***********************************************************************
1386 * URLCache_EnumHashTables (Internal)
1388 * Enumerates the hash tables in a container.
1390 * RETURNS
1391 * TRUE if an entry was found
1392 * FALSE if there are no more tables to enumerate.
1395 static BOOL URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader, DWORD *pdwHashTableNumber, HASH_CACHEFILE_ENTRY ** ppHashEntry)
1397 for (*ppHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1398 URLCache_IsHashEntryValid(pHeader, *ppHashEntry);
1399 *ppHashEntry = URLCache_HashEntryFromOffset(pHeader, (*ppHashEntry)->dwAddressNext))
1401 TRACE("looking at hash table number %d\n", (*ppHashEntry)->dwHashTableNumber);
1402 if ((*ppHashEntry)->dwHashTableNumber != *pdwHashTableNumber)
1403 continue;
1404 /* make sure that it is in fact a hash entry */
1405 if ((*ppHashEntry)->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1407 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&(*ppHashEntry)->CacheFileEntry.dwSignature);
1408 (*pdwHashTableNumber)++;
1409 continue;
1412 TRACE("hash table number %d found\n", *pdwHashTableNumber);
1413 return TRUE;
1415 return FALSE;
1418 /***********************************************************************
1419 * URLCache_EnumHashTableEntries (Internal)
1421 * Enumerates entries in a hash table and returns the next non-free entry.
1423 * RETURNS
1424 * TRUE if an entry was found
1425 * FALSE if the hash table is empty or there are no more entries to
1426 * enumerate.
1429 static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY * pHashEntry,
1430 DWORD * index, const struct _HASH_ENTRY ** ppHashEntry)
1432 for (; *index < HASHTABLE_SIZE ; (*index)++)
1434 if (pHashEntry->HashTable[*index].dwHashKey == HASHTABLE_FREE)
1435 continue;
1437 *ppHashEntry = &pHashEntry->HashTable[*index];
1438 TRACE("entry found %d\n", *index);
1439 return TRUE;
1441 TRACE("no more entries (%d)\n", *index);
1442 return FALSE;
1445 /***********************************************************************
1446 * GetUrlCacheEntryInfoExA (WININET.@)
1449 BOOL WINAPI GetUrlCacheEntryInfoExA(
1450 LPCSTR lpszUrl,
1451 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1452 LPDWORD lpdwCacheEntryInfoBufSize,
1453 LPSTR lpszReserved,
1454 LPDWORD lpdwReserved,
1455 LPVOID lpReserved,
1456 DWORD dwFlags)
1458 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1459 debugstr_a(lpszUrl),
1460 lpCacheEntryInfo,
1461 lpdwCacheEntryInfoBufSize,
1462 lpszReserved,
1463 lpdwReserved,
1464 lpReserved,
1465 dwFlags);
1467 if ((lpszReserved != NULL) ||
1468 (lpdwReserved != NULL) ||
1469 (lpReserved != NULL))
1471 ERR("Reserved value was not 0\n");
1472 SetLastError(ERROR_INVALID_PARAMETER);
1473 return FALSE;
1475 if (dwFlags != 0)
1476 FIXME("Undocumented flag(s): %x\n", dwFlags);
1477 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1480 /***********************************************************************
1481 * GetUrlCacheEntryInfoA (WININET.@)
1484 BOOL WINAPI GetUrlCacheEntryInfoA(
1485 IN LPCSTR lpszUrlName,
1486 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1487 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1490 LPURLCACHE_HEADER pHeader;
1491 struct _HASH_ENTRY * pHashEntry;
1492 const CACHEFILE_ENTRY * pEntry;
1493 const URL_CACHEFILE_ENTRY * pUrlEntry;
1494 URLCACHECONTAINER * pContainer;
1496 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1498 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1499 return FALSE;
1501 if (!URLCacheContainer_OpenIndex(pContainer))
1502 return FALSE;
1504 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1505 return FALSE;
1507 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1509 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1510 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1511 SetLastError(ERROR_FILE_NOT_FOUND);
1512 return FALSE;
1515 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1516 if (pEntry->dwSignature != URL_SIGNATURE)
1518 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1519 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1520 SetLastError(ERROR_FILE_NOT_FOUND);
1521 return FALSE;
1524 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1525 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1526 if (pUrlEntry->dwOffsetHeaderInfo)
1527 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1529 if (lpdwCacheEntryInfoBufferSize)
1531 if (!URLCache_CopyEntry(
1532 pContainer,
1533 pHeader,
1534 lpCacheEntryInfo,
1535 lpdwCacheEntryInfoBufferSize,
1536 pUrlEntry,
1537 FALSE /* ANSI */))
1539 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1540 return FALSE;
1542 TRACE("Local File Name: %s\n", debugstr_a(lpCacheEntryInfo->lpszLocalFileName));
1545 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1547 return TRUE;
1550 /***********************************************************************
1551 * GetUrlCacheEntryInfoW (WININET.@)
1554 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1555 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1556 LPDWORD lpdwCacheEntryInfoBufferSize)
1558 LPURLCACHE_HEADER pHeader;
1559 struct _HASH_ENTRY * pHashEntry;
1560 const CACHEFILE_ENTRY * pEntry;
1561 const URL_CACHEFILE_ENTRY * pUrlEntry;
1562 URLCACHECONTAINER * pContainer;
1564 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1566 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1567 return FALSE;
1569 if (!URLCacheContainer_OpenIndex(pContainer))
1570 return FALSE;
1572 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1573 return FALSE;
1575 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1577 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1578 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1579 SetLastError(ERROR_FILE_NOT_FOUND);
1580 return FALSE;
1583 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1584 if (pEntry->dwSignature != URL_SIGNATURE)
1586 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1587 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1588 SetLastError(ERROR_FILE_NOT_FOUND);
1589 return FALSE;
1592 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1593 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1594 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1596 if (lpdwCacheEntryInfoBufferSize)
1598 if (!URLCache_CopyEntry(
1599 pContainer,
1600 pHeader,
1601 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1602 lpdwCacheEntryInfoBufferSize,
1603 pUrlEntry,
1604 TRUE /* UNICODE */))
1606 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1607 return FALSE;
1609 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1612 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1614 return TRUE;
1617 /***********************************************************************
1618 * GetUrlCacheEntryInfoExW (WININET.@)
1621 BOOL WINAPI GetUrlCacheEntryInfoExW(
1622 LPCWSTR lpszUrl,
1623 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1624 LPDWORD lpdwCacheEntryInfoBufSize,
1625 LPWSTR lpszReserved,
1626 LPDWORD lpdwReserved,
1627 LPVOID lpReserved,
1628 DWORD dwFlags)
1630 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1631 debugstr_w(lpszUrl),
1632 lpCacheEntryInfo,
1633 lpdwCacheEntryInfoBufSize,
1634 lpszReserved,
1635 lpdwReserved,
1636 lpReserved,
1637 dwFlags);
1639 if ((lpszReserved != NULL) ||
1640 (lpdwReserved != NULL) ||
1641 (lpReserved != NULL))
1643 ERR("Reserved value was not 0\n");
1644 SetLastError(ERROR_INVALID_PARAMETER);
1645 return FALSE;
1647 if (dwFlags != 0)
1648 FIXME("Undocumented flag(s): %x\n", dwFlags);
1649 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1652 /***********************************************************************
1653 * SetUrlCacheEntryInfoA (WININET.@)
1655 BOOL WINAPI SetUrlCacheEntryInfoA(
1656 LPCSTR lpszUrlName,
1657 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1658 DWORD dwFieldControl)
1660 LPURLCACHE_HEADER pHeader;
1661 struct _HASH_ENTRY * pHashEntry;
1662 CACHEFILE_ENTRY * pEntry;
1663 URLCACHECONTAINER * pContainer;
1665 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1667 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1668 return FALSE;
1670 if (!URLCacheContainer_OpenIndex(pContainer))
1671 return FALSE;
1673 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1674 return FALSE;
1676 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1678 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1679 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1680 SetLastError(ERROR_FILE_NOT_FOUND);
1681 return FALSE;
1684 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1685 if (pEntry->dwSignature != URL_SIGNATURE)
1687 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1688 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1689 SetLastError(ERROR_FILE_NOT_FOUND);
1690 return FALSE;
1693 URLCache_SetEntryInfo(
1694 (URL_CACHEFILE_ENTRY *)pEntry,
1695 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1696 dwFieldControl);
1698 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1700 return TRUE;
1703 /***********************************************************************
1704 * SetUrlCacheEntryInfoW (WININET.@)
1706 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1708 LPURLCACHE_HEADER pHeader;
1709 struct _HASH_ENTRY * pHashEntry;
1710 CACHEFILE_ENTRY * pEntry;
1711 URLCACHECONTAINER * pContainer;
1713 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1715 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1716 return FALSE;
1718 if (!URLCacheContainer_OpenIndex(pContainer))
1719 return FALSE;
1721 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1722 return FALSE;
1724 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1726 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1727 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1728 SetLastError(ERROR_FILE_NOT_FOUND);
1729 return FALSE;
1732 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1733 if (pEntry->dwSignature != URL_SIGNATURE)
1735 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1736 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1737 SetLastError(ERROR_FILE_NOT_FOUND);
1738 return FALSE;
1741 URLCache_SetEntryInfo(
1742 (URL_CACHEFILE_ENTRY *)pEntry,
1743 lpCacheEntryInfo,
1744 dwFieldControl);
1746 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1748 return TRUE;
1751 /***********************************************************************
1752 * RetrieveUrlCacheEntryFileA (WININET.@)
1755 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1756 IN LPCSTR lpszUrlName,
1757 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1758 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1759 IN DWORD dwReserved
1762 LPURLCACHE_HEADER pHeader;
1763 struct _HASH_ENTRY * pHashEntry;
1764 CACHEFILE_ENTRY * pEntry;
1765 URL_CACHEFILE_ENTRY * pUrlEntry;
1766 URLCACHECONTAINER * pContainer;
1768 TRACE("(%s, %p, %p, 0x%08x)\n",
1769 debugstr_a(lpszUrlName),
1770 lpCacheEntryInfo,
1771 lpdwCacheEntryInfoBufferSize,
1772 dwReserved);
1774 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1775 return FALSE;
1777 if (!URLCacheContainer_OpenIndex(pContainer))
1778 return FALSE;
1780 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1781 return FALSE;
1783 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1785 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1786 TRACE("entry %s not found!\n", lpszUrlName);
1787 SetLastError(ERROR_FILE_NOT_FOUND);
1788 return FALSE;
1791 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1792 if (pEntry->dwSignature != URL_SIGNATURE)
1794 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1795 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1796 SetLastError(ERROR_FILE_NOT_FOUND);
1797 return FALSE;
1800 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1801 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1802 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1804 pUrlEntry->dwHitRate++;
1805 pUrlEntry->dwUseCount++;
1806 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1808 if (!URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize, pUrlEntry, FALSE))
1810 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1811 return FALSE;
1813 TRACE("Local File Name: %s\n", lpCacheEntryInfo->lpszLocalFileName);
1815 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1817 return TRUE;
1820 /***********************************************************************
1821 * RetrieveUrlCacheEntryFileW (WININET.@)
1824 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1825 IN LPCWSTR lpszUrlName,
1826 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1827 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1828 IN DWORD dwReserved
1831 LPURLCACHE_HEADER pHeader;
1832 struct _HASH_ENTRY * pHashEntry;
1833 CACHEFILE_ENTRY * pEntry;
1834 URL_CACHEFILE_ENTRY * pUrlEntry;
1835 URLCACHECONTAINER * pContainer;
1837 TRACE("(%s, %p, %p, 0x%08x)\n",
1838 debugstr_w(lpszUrlName),
1839 lpCacheEntryInfo,
1840 lpdwCacheEntryInfoBufferSize,
1841 dwReserved);
1843 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
1844 return FALSE;
1846 if (!URLCacheContainer_OpenIndex(pContainer))
1847 return FALSE;
1849 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1850 return FALSE;
1852 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1854 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1855 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1856 SetLastError(ERROR_FILE_NOT_FOUND);
1857 return FALSE;
1860 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1861 if (pEntry->dwSignature != URL_SIGNATURE)
1863 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1864 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1865 SetLastError(ERROR_FILE_NOT_FOUND);
1866 return FALSE;
1869 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1870 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1871 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1873 pUrlEntry->dwHitRate++;
1874 pUrlEntry->dwUseCount++;
1875 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1877 if (!URLCache_CopyEntry(
1878 pContainer,
1879 pHeader,
1880 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1881 lpdwCacheEntryInfoBufferSize,
1882 pUrlEntry,
1883 TRUE /* UNICODE */))
1885 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1886 return FALSE;
1888 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1890 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1892 return TRUE;
1895 /***********************************************************************
1896 * UnlockUrlCacheEntryFileA (WININET.@)
1899 BOOL WINAPI UnlockUrlCacheEntryFileA(
1900 IN LPCSTR lpszUrlName,
1901 IN DWORD dwReserved
1904 LPURLCACHE_HEADER pHeader;
1905 struct _HASH_ENTRY * pHashEntry;
1906 CACHEFILE_ENTRY * pEntry;
1907 URL_CACHEFILE_ENTRY * pUrlEntry;
1908 URLCACHECONTAINER * pContainer;
1910 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
1912 if (dwReserved)
1914 ERR("dwReserved != 0\n");
1915 SetLastError(ERROR_INVALID_PARAMETER);
1916 return FALSE;
1919 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1920 return FALSE;
1922 if (!URLCacheContainer_OpenIndex(pContainer))
1923 return FALSE;
1925 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1926 return FALSE;
1928 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1930 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1931 TRACE("entry %s not found!\n", lpszUrlName);
1932 SetLastError(ERROR_FILE_NOT_FOUND);
1933 return FALSE;
1936 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1937 if (pEntry->dwSignature != URL_SIGNATURE)
1939 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1940 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1941 SetLastError(ERROR_FILE_NOT_FOUND);
1942 return FALSE;
1945 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1947 if (pUrlEntry->dwUseCount == 0)
1949 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1950 return FALSE;
1952 pUrlEntry->dwUseCount--;
1953 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1955 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1957 return TRUE;
1960 /***********************************************************************
1961 * UnlockUrlCacheEntryFileW (WININET.@)
1964 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
1966 LPURLCACHE_HEADER pHeader;
1967 struct _HASH_ENTRY * pHashEntry;
1968 CACHEFILE_ENTRY * pEntry;
1969 URL_CACHEFILE_ENTRY * pUrlEntry;
1970 URLCACHECONTAINER * pContainer;
1972 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
1974 if (dwReserved)
1976 ERR("dwReserved != 0\n");
1977 SetLastError(ERROR_INVALID_PARAMETER);
1978 return FALSE;
1981 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
1982 return FALSE;
1984 if (!URLCacheContainer_OpenIndex(pContainer))
1985 return FALSE;
1987 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1988 return FALSE;
1990 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1992 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1993 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1994 SetLastError(ERROR_FILE_NOT_FOUND);
1995 return FALSE;
1998 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1999 if (pEntry->dwSignature != URL_SIGNATURE)
2001 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2002 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2003 SetLastError(ERROR_FILE_NOT_FOUND);
2004 return FALSE;
2007 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2009 if (pUrlEntry->dwUseCount == 0)
2011 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2012 return FALSE;
2014 pUrlEntry->dwUseCount--;
2015 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2017 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2019 return TRUE;
2022 /***********************************************************************
2023 * CreateUrlCacheEntryA (WININET.@)
2026 BOOL WINAPI CreateUrlCacheEntryA(
2027 IN LPCSTR lpszUrlName,
2028 IN DWORD dwExpectedFileSize,
2029 IN LPCSTR lpszFileExtension,
2030 OUT LPSTR lpszFileName,
2031 IN DWORD dwReserved
2034 DWORD len;
2035 WCHAR *url_name;
2036 WCHAR *file_extension;
2037 WCHAR file_name[MAX_PATH];
2038 BOOL bSuccess = FALSE;
2039 DWORD dwError = 0;
2041 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
2042 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2044 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2045 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 &&
2046 (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2048 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2049 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
2051 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
2053 bSuccess = TRUE;
2055 else
2057 dwError = GetLastError();
2060 else
2062 dwError = GetLastError();
2064 HeapFree(GetProcessHeap(), 0, file_extension);
2066 else
2068 dwError = GetLastError();
2070 HeapFree(GetProcessHeap(), 0, url_name);
2071 if (!bSuccess)
2072 SetLastError(dwError);
2074 return bSuccess;
2076 /***********************************************************************
2077 * CreateUrlCacheEntryW (WININET.@)
2080 BOOL WINAPI CreateUrlCacheEntryW(
2081 IN LPCWSTR lpszUrlName,
2082 IN DWORD dwExpectedFileSize,
2083 IN LPCWSTR lpszFileExtension,
2084 OUT LPWSTR lpszFileName,
2085 IN DWORD dwReserved
2088 URLCACHECONTAINER * pContainer;
2089 LPURLCACHE_HEADER pHeader;
2090 CHAR szFile[MAX_PATH];
2091 WCHAR szExtension[MAX_PATH];
2092 LPCWSTR lpszUrlPart;
2093 LPCWSTR lpszUrlEnd;
2094 LPCWSTR lpszFileNameExtension;
2095 LPWSTR lpszFileNameNoPath;
2096 int i;
2097 int countnoextension;
2098 BYTE CacheDir;
2099 LONG lBufferSize;
2100 BOOL bFound = FALSE;
2101 int count;
2102 static const WCHAR szWWW[] = {'w','w','w',0};
2104 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2105 debugstr_w(lpszUrlName),
2106 dwExpectedFileSize,
2107 debugstr_w(lpszFileExtension),
2108 lpszFileName,
2109 dwReserved);
2111 if (dwReserved)
2113 ERR("dwReserved != 0\n");
2114 SetLastError(ERROR_INVALID_PARAMETER);
2115 return FALSE;
2118 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2120 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2121 lpszUrlEnd--;
2123 for (lpszUrlPart = lpszUrlEnd;
2124 (lpszUrlPart >= lpszUrlName);
2125 lpszUrlPart--)
2127 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2129 bFound = TRUE;
2130 lpszUrlPart++;
2131 break;
2133 else if(*lpszUrlPart == '?' || *lpszUrlPart == '#')
2135 lpszUrlEnd = lpszUrlPart;
2138 if (!lstrcmpW(lpszUrlPart, szWWW))
2140 lpszUrlPart += lstrlenW(szWWW);
2143 count = lpszUrlEnd - lpszUrlPart;
2145 if (bFound && (count < MAX_PATH))
2147 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2148 if (!len)
2149 return FALSE;
2150 szFile[len] = '\0';
2151 /* FIXME: get rid of illegal characters like \, / and : */
2153 else
2155 FIXME("need to generate a random filename\n");
2158 TRACE("File name: %s\n", debugstr_a(szFile));
2160 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
2161 return FALSE;
2163 if (!URLCacheContainer_OpenIndex(pContainer))
2164 return FALSE;
2166 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2167 return FALSE;
2169 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2171 lBufferSize = MAX_PATH * sizeof(WCHAR);
2172 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
2174 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2176 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2177 lpszFileNameNoPath >= lpszFileName;
2178 --lpszFileNameNoPath)
2180 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2181 break;
2184 countnoextension = lstrlenW(lpszFileNameNoPath);
2185 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2186 if (lpszFileNameExtension)
2187 countnoextension -= lstrlenW(lpszFileNameExtension);
2188 *szExtension = '\0';
2190 if (lpszFileExtension)
2192 szExtension[0] = '.';
2193 lstrcpyW(szExtension+1, lpszFileExtension);
2196 for (i = 0; i < 255; i++)
2198 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2199 HANDLE hFile;
2200 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2201 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2202 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2203 if (hFile != INVALID_HANDLE_VALUE)
2205 CloseHandle(hFile);
2206 return TRUE;
2210 return FALSE;
2214 /***********************************************************************
2215 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2217 * The bug we are compensating for is that some drongo at Microsoft
2218 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2219 * As a consequence, CommitUrlCacheEntryA has been effectively
2220 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2221 * is still defined as LPCWSTR. The result (other than madness) is
2222 * that we always need to store lpHeaderInfo in CP_ACP rather than
2223 * in UTF16, and we need to avoid converting lpHeaderInfo in
2224 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2225 * result will lose data for arbitrary binary data.
2228 static BOOL WINAPI CommitUrlCacheEntryInternal(
2229 IN LPCWSTR lpszUrlName,
2230 IN LPCWSTR lpszLocalFileName,
2231 IN FILETIME ExpireTime,
2232 IN FILETIME LastModifiedTime,
2233 IN DWORD CacheEntryType,
2234 IN LPBYTE lpHeaderInfo,
2235 IN DWORD dwHeaderSize,
2236 IN LPCWSTR lpszFileExtension,
2237 IN LPCWSTR lpszOriginalUrl
2240 URLCACHECONTAINER * pContainer;
2241 LPURLCACHE_HEADER pHeader;
2242 struct _HASH_ENTRY * pHashEntry;
2243 CACHEFILE_ENTRY * pEntry;
2244 URL_CACHEFILE_ENTRY * pUrlEntry;
2245 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2246 DWORD dwOffsetLocalFileName = 0;
2247 DWORD dwOffsetHeader = 0;
2248 DWORD dwOffsetFileExtension = 0;
2249 DWORD dwFileSizeLow = 0;
2250 DWORD dwFileSizeHigh = 0;
2251 BYTE cDirectory = 0;
2252 int len;
2253 char achFile[MAX_PATH];
2254 LPSTR lpszUrlNameA = NULL;
2255 LPSTR lpszFileExtensionA = NULL;
2256 char *pchLocalFileName = 0;
2257 DWORD error = ERROR_SUCCESS;
2259 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2260 debugstr_w(lpszUrlName),
2261 debugstr_w(lpszLocalFileName),
2262 CacheEntryType,
2263 lpHeaderInfo,
2264 dwHeaderSize,
2265 debugstr_w(lpszFileExtension),
2266 debugstr_w(lpszOriginalUrl));
2268 if (lpszOriginalUrl)
2269 WARN(": lpszOriginalUrl ignored\n");
2271 if (lpszLocalFileName)
2273 HANDLE hFile;
2275 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2276 if (hFile == INVALID_HANDLE_VALUE)
2278 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2279 return FALSE;
2282 /* Get file size */
2283 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2284 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2286 ERR("couldn't get file size (error is %d)\n", GetLastError());
2287 CloseHandle(hFile);
2288 return FALSE;
2291 CloseHandle(hFile);
2294 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
2295 return FALSE;
2297 if (!URLCacheContainer_OpenIndex(pContainer))
2298 return FALSE;
2300 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2301 return FALSE;
2303 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2304 lpszUrlNameA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2305 if (!lpszUrlNameA)
2307 error = GetLastError();
2308 goto cleanup;
2310 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, lpszUrlNameA, len, NULL, NULL);
2312 if (lpszFileExtension)
2314 len = WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, NULL, 0, NULL, NULL);
2315 lpszFileExtensionA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2316 if (!lpszFileExtensionA)
2318 error = GetLastError();
2319 goto cleanup;
2321 WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, lpszFileExtensionA, len, NULL, NULL);
2324 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2326 FIXME("entry already in cache - don't know what to do!\n");
2328 * SetLastError(ERROR_FILE_NOT_FOUND);
2329 * return FALSE;
2331 goto cleanup;
2334 if (lpszLocalFileName)
2336 BOOL bFound = FALSE;
2338 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2340 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2341 error = ERROR_INVALID_PARAMETER;
2342 goto cleanup;
2345 /* skip container path prefix */
2346 lpszLocalFileName += lstrlenW(pContainer->path);
2348 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, -1, NULL, NULL);
2349 pchLocalFileName = achFile;
2351 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2353 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2355 bFound = TRUE;
2356 break;
2360 if (!bFound)
2362 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2363 error = ERROR_INVALID_PARAMETER;
2364 goto cleanup;
2367 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2370 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2371 if (lpszLocalFileName)
2373 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2374 dwOffsetLocalFileName = dwBytesNeeded;
2375 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2377 if (lpHeaderInfo)
2379 dwOffsetHeader = dwBytesNeeded;
2380 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2382 if (lpszFileExtensionA)
2384 dwOffsetFileExtension = dwBytesNeeded;
2385 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2388 /* round up to next block */
2389 if (dwBytesNeeded % BLOCKSIZE)
2391 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2392 dwBytesNeeded += BLOCKSIZE;
2395 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2397 ERR("no free entries\n");
2398 error = ERROR_DISK_FULL;
2399 goto cleanup;
2402 /* FindFirstFreeEntry fills in blocks used */
2403 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2404 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2405 pUrlEntry->CacheDir = cDirectory;
2406 pUrlEntry->CacheEntryType = CacheEntryType;
2407 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2408 pUrlEntry->dwExemptDelta = 0;
2409 pUrlEntry->dwHitRate = 0;
2410 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2411 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2412 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2413 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2414 pUrlEntry->dwSizeHigh = 0;
2415 pUrlEntry->dwSizeLow = dwFileSizeLow;
2416 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2417 pUrlEntry->dwUseCount = 0;
2418 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2419 pUrlEntry->LastModifiedTime = LastModifiedTime;
2420 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2421 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2422 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2423 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2425 /*** Unknowns ***/
2426 pUrlEntry->dwUnknown1 = 0;
2427 pUrlEntry->dwUnknown2 = 0;
2428 pUrlEntry->dwUnknown3 = 0x60;
2429 pUrlEntry->Unknown4 = 0;
2430 pUrlEntry->wUnknown5 = 0x1010;
2431 pUrlEntry->dwUnknown7 = 0;
2432 pUrlEntry->dwUnknown8 = 0;
2435 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2436 if (dwOffsetLocalFileName)
2437 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2438 if (dwOffsetHeader)
2439 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2440 if (dwOffsetFileExtension)
2441 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2443 if (!URLCache_AddEntryToHash(pHeader, lpszUrlNameA, (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader)))
2445 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2446 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2447 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2448 return FALSE;
2451 cleanup:
2452 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2453 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2454 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2456 if (error == ERROR_SUCCESS)
2457 return TRUE;
2458 else
2460 SetLastError(error);
2461 return FALSE;
2465 /***********************************************************************
2466 * CommitUrlCacheEntryA (WININET.@)
2469 BOOL WINAPI CommitUrlCacheEntryA(
2470 IN LPCSTR lpszUrlName,
2471 IN LPCSTR lpszLocalFileName,
2472 IN FILETIME ExpireTime,
2473 IN FILETIME LastModifiedTime,
2474 IN DWORD CacheEntryType,
2475 IN LPBYTE lpHeaderInfo,
2476 IN DWORD dwHeaderSize,
2477 IN LPCSTR lpszFileExtension,
2478 IN LPCSTR lpszOriginalUrl
2481 DWORD len;
2482 WCHAR *url_name = NULL;
2483 WCHAR *local_file_name = NULL;
2484 WCHAR *original_url = NULL;
2485 WCHAR *file_extension = NULL;
2486 BOOL bSuccess = FALSE;
2488 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2489 debugstr_a(lpszUrlName),
2490 debugstr_a(lpszLocalFileName),
2491 CacheEntryType,
2492 lpHeaderInfo,
2493 dwHeaderSize,
2494 debugstr_a(lpszFileExtension),
2495 debugstr_a(lpszOriginalUrl));
2497 len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0);
2498 url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2499 if (!url_name)
2500 goto cleanup;
2501 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2503 if (lpszLocalFileName)
2505 len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0);
2506 local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2507 if (!local_file_name)
2508 goto cleanup;
2509 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2511 if (lpszFileExtension)
2513 len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0);
2514 file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2515 if (!file_extension)
2516 goto cleanup;
2517 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2519 if (lpszOriginalUrl)
2521 len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0);
2522 original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2523 if (!original_url)
2524 goto cleanup;
2525 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2528 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2529 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2530 file_extension, original_url);
2532 cleanup:
2533 HeapFree(GetProcessHeap(), 0, original_url);
2534 HeapFree(GetProcessHeap(), 0, file_extension);
2535 HeapFree(GetProcessHeap(), 0, local_file_name);
2536 HeapFree(GetProcessHeap(), 0, url_name);
2538 return bSuccess;
2541 /***********************************************************************
2542 * CommitUrlCacheEntryW (WININET.@)
2545 BOOL WINAPI CommitUrlCacheEntryW(
2546 IN LPCWSTR lpszUrlName,
2547 IN LPCWSTR lpszLocalFileName,
2548 IN FILETIME ExpireTime,
2549 IN FILETIME LastModifiedTime,
2550 IN DWORD CacheEntryType,
2551 IN LPWSTR lpHeaderInfo,
2552 IN DWORD dwHeaderSize,
2553 IN LPCWSTR lpszFileExtension,
2554 IN LPCWSTR lpszOriginalUrl
2557 DWORD dwError = 0;
2558 BOOL bSuccess = FALSE;
2559 DWORD len = 0;
2560 CHAR *header_info = NULL;
2562 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2563 debugstr_w(lpszUrlName),
2564 debugstr_w(lpszLocalFileName),
2565 CacheEntryType,
2566 lpHeaderInfo,
2567 dwHeaderSize,
2568 debugstr_w(lpszFileExtension),
2569 debugstr_w(lpszOriginalUrl));
2571 if (!lpHeaderInfo ||
2572 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2573 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2575 if (header_info)
2576 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2577 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2578 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2580 bSuccess = TRUE;
2582 else
2584 dwError = GetLastError();
2586 if (header_info)
2588 HeapFree(GetProcessHeap(), 0, header_info);
2589 if (!bSuccess)
2590 SetLastError(dwError);
2593 return bSuccess;
2596 /***********************************************************************
2597 * ReadUrlCacheEntryStream (WININET.@)
2600 BOOL WINAPI ReadUrlCacheEntryStream(
2601 IN HANDLE hUrlCacheStream,
2602 IN DWORD dwLocation,
2603 IN OUT LPVOID lpBuffer,
2604 IN OUT LPDWORD lpdwLen,
2605 IN DWORD dwReserved
2608 /* Get handle to file from 'stream' */
2609 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2611 if (dwReserved != 0)
2613 ERR("dwReserved != 0\n");
2614 SetLastError(ERROR_INVALID_PARAMETER);
2615 return FALSE;
2618 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2620 SetLastError(ERROR_INVALID_HANDLE);
2621 return FALSE;
2624 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2625 return FALSE;
2626 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2629 /***********************************************************************
2630 * RetrieveUrlCacheEntryStreamA (WININET.@)
2633 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2634 IN LPCSTR lpszUrlName,
2635 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2636 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2637 IN BOOL fRandomRead,
2638 IN DWORD dwReserved
2641 /* NOTE: this is not the same as the way that the native
2642 * version allocates 'stream' handles. I did it this way
2643 * as it is much easier and no applications should depend
2644 * on this behaviour. (Native version appears to allocate
2645 * indices into a table)
2647 STREAM_HANDLE * pStream;
2648 HANDLE hFile;
2650 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2651 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2653 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2654 lpCacheEntryInfo,
2655 lpdwCacheEntryInfoBufferSize,
2656 dwReserved))
2658 return NULL;
2661 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2662 GENERIC_READ,
2663 FILE_SHARE_READ,
2664 NULL,
2665 OPEN_EXISTING,
2666 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2667 NULL);
2668 if (hFile == INVALID_HANDLE_VALUE)
2669 return FALSE;
2671 /* allocate handle storage space */
2672 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2673 if (!pStream)
2675 CloseHandle(hFile);
2676 SetLastError(ERROR_OUTOFMEMORY);
2677 return FALSE;
2680 pStream->hFile = hFile;
2681 strcpy(pStream->lpszUrl, lpszUrlName);
2682 return (HANDLE)pStream;
2685 /***********************************************************************
2686 * RetrieveUrlCacheEntryStreamW (WININET.@)
2689 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2690 IN LPCWSTR lpszUrlName,
2691 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2692 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2693 IN BOOL fRandomRead,
2694 IN DWORD dwReserved
2697 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2698 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2699 return NULL;
2702 /***********************************************************************
2703 * UnlockUrlCacheEntryStream (WININET.@)
2706 BOOL WINAPI UnlockUrlCacheEntryStream(
2707 IN HANDLE hUrlCacheStream,
2708 IN DWORD dwReserved
2711 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2713 if (dwReserved != 0)
2715 ERR("dwReserved != 0\n");
2716 SetLastError(ERROR_INVALID_PARAMETER);
2717 return FALSE;
2720 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2722 SetLastError(ERROR_INVALID_HANDLE);
2723 return FALSE;
2726 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2727 return FALSE;
2729 /* close file handle */
2730 CloseHandle(pStream->hFile);
2732 /* free allocated space */
2733 HeapFree(GetProcessHeap(), 0, pStream);
2735 return TRUE;
2739 /***********************************************************************
2740 * DeleteUrlCacheEntryA (WININET.@)
2743 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2745 URLCACHECONTAINER * pContainer;
2746 LPURLCACHE_HEADER pHeader;
2747 struct _HASH_ENTRY * pHashEntry;
2748 CACHEFILE_ENTRY * pEntry;
2750 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2752 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
2753 return FALSE;
2755 if (!URLCacheContainer_OpenIndex(pContainer))
2756 return FALSE;
2758 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2759 return FALSE;
2761 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2763 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2764 TRACE("entry %s not found!\n", lpszUrlName);
2765 SetLastError(ERROR_FILE_NOT_FOUND);
2766 return FALSE;
2769 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2770 URLCache_DeleteEntry(pHeader, pEntry);
2772 URLCache_DeleteEntryFromHash(pHashEntry);
2774 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2776 return TRUE;
2779 /***********************************************************************
2780 * DeleteUrlCacheEntryW (WININET.@)
2783 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2785 URLCACHECONTAINER * pContainer;
2786 LPURLCACHE_HEADER pHeader;
2787 struct _HASH_ENTRY * pHashEntry;
2788 CACHEFILE_ENTRY * pEntry;
2789 LPSTR urlA;
2790 int url_len;
2792 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2794 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2795 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
2796 if (!urlA)
2798 SetLastError(ERROR_OUTOFMEMORY);
2799 return FALSE;
2801 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, urlA, url_len, NULL, NULL);
2803 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
2805 HeapFree(GetProcessHeap(), 0, urlA);
2806 return FALSE;
2808 if (!URLCacheContainer_OpenIndex(pContainer))
2810 HeapFree(GetProcessHeap(), 0, urlA);
2811 return FALSE;
2813 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2815 HeapFree(GetProcessHeap(), 0, urlA);
2816 return FALSE;
2819 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
2821 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2822 TRACE("entry %s not found!\n", debugstr_a(urlA));
2823 HeapFree(GetProcessHeap(), 0, urlA);
2824 SetLastError(ERROR_FILE_NOT_FOUND);
2825 return FALSE;
2828 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2829 URLCache_DeleteEntry(pHeader, pEntry);
2831 URLCache_DeleteEntryFromHash(pHashEntry);
2833 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2835 HeapFree(GetProcessHeap(), 0, urlA);
2836 return TRUE;
2839 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2841 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2842 return TRUE;
2845 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2847 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2848 return TRUE;
2851 /***********************************************************************
2852 * CreateCacheContainerA (WININET.@)
2854 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2855 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2857 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2858 d1, d2, d3, d4, d5, d6, d7, d8);
2859 return TRUE;
2862 /***********************************************************************
2863 * CreateCacheContainerW (WININET.@)
2865 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2866 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2868 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2869 d1, d2, d3, d4, d5, d6, d7, d8);
2870 return TRUE;
2873 /***********************************************************************
2874 * FindFirstUrlCacheContainerA (WININET.@)
2876 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2878 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
2879 return NULL;
2882 /***********************************************************************
2883 * FindFirstUrlCacheContainerW (WININET.@)
2885 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2887 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
2888 return NULL;
2891 /***********************************************************************
2892 * FindNextUrlCacheContainerA (WININET.@)
2894 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
2896 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2897 return FALSE;
2900 /***********************************************************************
2901 * FindNextUrlCacheContainerW (WININET.@)
2903 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
2905 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2906 return FALSE;
2909 HANDLE WINAPI FindFirstUrlCacheEntryExA(
2910 LPCSTR lpszUrlSearchPattern,
2911 DWORD dwFlags,
2912 DWORD dwFilter,
2913 GROUPID GroupId,
2914 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2915 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2916 LPVOID lpReserved,
2917 LPDWORD pcbReserved2,
2918 LPVOID lpReserved3
2921 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
2922 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2923 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2924 SetLastError(ERROR_FILE_NOT_FOUND);
2925 return NULL;
2928 HANDLE WINAPI FindFirstUrlCacheEntryExW(
2929 LPCWSTR lpszUrlSearchPattern,
2930 DWORD dwFlags,
2931 DWORD dwFilter,
2932 GROUPID GroupId,
2933 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2934 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2935 LPVOID lpReserved,
2936 LPDWORD pcbReserved2,
2937 LPVOID lpReserved3
2940 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
2941 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2942 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2943 SetLastError(ERROR_FILE_NOT_FOUND);
2944 return NULL;
2947 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
2949 typedef struct URLCacheFindEntryHandle
2951 DWORD dwMagic;
2952 LPWSTR lpszUrlSearchPattern;
2953 DWORD dwContainerIndex;
2954 DWORD dwHashTableIndex;
2955 DWORD dwHashEntryIndex;
2956 } URLCacheFindEntryHandle;
2958 /***********************************************************************
2959 * FindFirstUrlCacheEntryA (WININET.@)
2962 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
2963 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2965 URLCacheFindEntryHandle *pEntryHandle;
2967 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2969 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
2970 if (!pEntryHandle)
2971 return NULL;
2973 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
2974 if (lpszUrlSearchPattern)
2976 int len = MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, NULL, 0);
2977 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2978 if (!pEntryHandle->lpszUrlSearchPattern)
2980 HeapFree(GetProcessHeap(), 0, pEntryHandle);
2981 return NULL;
2983 MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, pEntryHandle->lpszUrlSearchPattern, len);
2985 else
2986 pEntryHandle->lpszUrlSearchPattern = NULL;
2987 pEntryHandle->dwContainerIndex = 0;
2988 pEntryHandle->dwHashTableIndex = 0;
2989 pEntryHandle->dwHashEntryIndex = 0;
2991 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
2993 HeapFree(GetProcessHeap(), 0, pEntryHandle);
2994 return NULL;
2996 return pEntryHandle;
2999 /***********************************************************************
3000 * FindFirstUrlCacheEntryW (WININET.@)
3003 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3004 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3006 URLCacheFindEntryHandle *pEntryHandle;
3008 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3010 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3011 if (!pEntryHandle)
3012 return NULL;
3014 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3015 if (lpszUrlSearchPattern)
3017 int len = strlenW(lpszUrlSearchPattern);
3018 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
3019 if (!pEntryHandle->lpszUrlSearchPattern)
3021 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3022 return NULL;
3024 memcpy(pEntryHandle->lpszUrlSearchPattern, lpszUrlSearchPattern, (len + 1) * sizeof(WCHAR));
3026 else
3027 pEntryHandle->lpszUrlSearchPattern = NULL;
3028 pEntryHandle->dwContainerIndex = 0;
3029 pEntryHandle->dwHashTableIndex = 0;
3030 pEntryHandle->dwHashEntryIndex = 0;
3032 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3034 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3035 return NULL;
3037 return pEntryHandle;
3040 /***********************************************************************
3041 * FindNextUrlCacheEntryA (WININET.@)
3043 BOOL WINAPI FindNextUrlCacheEntryA(
3044 HANDLE hEnumHandle,
3045 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3046 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3048 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3049 URLCACHECONTAINER * pContainer;
3051 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3053 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3055 SetLastError(ERROR_INVALID_HANDLE);
3056 return FALSE;
3059 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3060 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3062 LPURLCACHE_HEADER pHeader;
3063 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3065 if (!URLCacheContainer_OpenIndex(pContainer))
3066 return FALSE;
3068 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3069 return FALSE;
3071 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3072 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3074 const struct _HASH_ENTRY *pHashEntry = NULL;
3075 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3076 pEntryHandle->dwHashEntryIndex++)
3078 const URL_CACHEFILE_ENTRY *pUrlEntry;
3079 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3081 if (pEntry->dwSignature != URL_SIGNATURE)
3082 continue;
3084 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3085 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3086 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3088 if (!URLCache_CopyEntry(
3089 pContainer,
3090 pHeader,
3091 lpNextCacheEntryInfo,
3092 lpdwNextCacheEntryInfoBufferSize,
3093 pUrlEntry,
3094 FALSE /* not UNICODE */))
3096 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3097 return FALSE;
3099 TRACE("Local File Name: %s\n", debugstr_a(lpNextCacheEntryInfo->lpszLocalFileName));
3101 /* increment the current index so that next time the function
3102 * is called the next entry is returned */
3103 pEntryHandle->dwHashEntryIndex++;
3104 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3105 return TRUE;
3109 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3112 SetLastError(ERROR_NO_MORE_ITEMS);
3113 return FALSE;
3116 BOOL WINAPI FindNextUrlCacheEntryW(
3117 HANDLE hEnumHandle,
3118 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3119 LPDWORD lpdwNextCacheEntryInfoBufferSize
3122 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3123 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3124 return FALSE;
3127 /***********************************************************************
3128 * FindCloseUrlCache (WININET.@)
3130 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3132 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3134 TRACE("(%p)\n", hEnumHandle);
3136 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3138 SetLastError(ERROR_INVALID_HANDLE);
3139 return FALSE;
3142 pEntryHandle->dwMagic = 0;
3143 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3144 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3146 return TRUE;
3149 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3150 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3152 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3153 dwSearchCondition, lpGroupId, lpReserved);
3154 return NULL;
3157 BOOL WINAPI FindNextUrlCacheEntryExA(
3158 HANDLE hEnumHandle,
3159 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3160 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3161 LPVOID lpReserved,
3162 LPDWORD pcbReserved2,
3163 LPVOID lpReserved3
3166 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3167 lpReserved, pcbReserved2, lpReserved3);
3168 return FALSE;
3171 BOOL WINAPI FindNextUrlCacheEntryExW(
3172 HANDLE hEnumHandle,
3173 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3174 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3175 LPVOID lpReserved,
3176 LPDWORD pcbReserved2,
3177 LPVOID lpReserved3
3180 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3181 lpReserved, pcbReserved2, lpReserved3);
3182 return FALSE;
3185 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3187 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3188 return FALSE;
3191 /***********************************************************************
3192 * CreateUrlCacheGroup (WININET.@)
3195 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3197 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3198 return FALSE;
3201 /***********************************************************************
3202 * DeleteUrlCacheGroup (WININET.@)
3205 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3207 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3208 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3209 return FALSE;
3212 /***********************************************************************
3213 * SetUrlCacheEntryGroupA (WININET.@)
3216 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3217 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3218 LPVOID lpReserved)
3220 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3221 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3222 pbGroupAttributes, cbGroupAttributes, lpReserved);
3223 SetLastError(ERROR_FILE_NOT_FOUND);
3224 return FALSE;
3227 /***********************************************************************
3228 * SetUrlCacheEntryGroupW (WININET.@)
3231 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3232 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3233 LPVOID lpReserved)
3235 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3236 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3237 pbGroupAttributes, cbGroupAttributes, lpReserved);
3238 SetLastError(ERROR_FILE_NOT_FOUND);
3239 return FALSE;
3242 /***********************************************************************
3243 * GetUrlCacheConfigInfoW (WININET.@)
3245 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3247 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3248 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3249 return FALSE;
3252 /***********************************************************************
3253 * GetUrlCacheConfigInfoA (WININET.@)
3255 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3257 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3259 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3260 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3261 return FALSE;
3264 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3265 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3266 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3268 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3269 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3270 lpdwGroupInfo, lpReserved);
3271 return FALSE;
3274 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3275 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3276 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3278 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3279 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3280 lpdwGroupInfo, lpReserved);
3281 return FALSE;
3284 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3285 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3287 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3288 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3289 return TRUE;
3292 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3293 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3295 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3296 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3297 return TRUE;
3300 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3302 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3303 return TRUE;
3306 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3308 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3309 return TRUE;
3312 /***********************************************************************
3313 * DeleteIE3Cache (WININET.@)
3315 * Deletes the files used by the IE3 URL caching system.
3317 * PARAMS
3318 * hWnd [I] A dummy window.
3319 * hInst [I] Instance of process calling the function.
3320 * lpszCmdLine [I] Options used by function.
3321 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3323 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3325 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3326 return 0;
3329 /***********************************************************************
3330 * IsUrlCacheEntryExpiredA (WININET.@)
3332 * PARAMS
3333 * url [I] Url
3334 * dwFlags [I] Unknown
3335 * pftLastModified [O] Last modified time
3337 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3339 LPURLCACHE_HEADER pHeader;
3340 struct _HASH_ENTRY * pHashEntry;
3341 const CACHEFILE_ENTRY * pEntry;
3342 const URL_CACHEFILE_ENTRY * pUrlEntry;
3343 URLCACHECONTAINER * pContainer;
3345 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3347 if (!URLCacheContainers_FindContainerA(url, &pContainer))
3348 return FALSE;
3350 if (!URLCacheContainer_OpenIndex(pContainer))
3351 return FALSE;
3353 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3354 return FALSE;
3356 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3358 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3359 TRACE("entry %s not found!\n", url);
3360 SetLastError(ERROR_FILE_NOT_FOUND);
3361 return FALSE;
3364 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3365 if (pEntry->dwSignature != URL_SIGNATURE)
3367 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3368 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3369 SetLastError(ERROR_FILE_NOT_FOUND);
3370 return FALSE;
3373 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3375 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3377 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3379 return TRUE;
3382 /***********************************************************************
3383 * IsUrlCacheEntryExpiredW (WININET.@)
3385 * PARAMS
3386 * url [I] Url
3387 * dwFlags [I] Unknown
3388 * pftLastModified [O] Last modified time
3390 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3392 LPURLCACHE_HEADER pHeader;
3393 struct _HASH_ENTRY * pHashEntry;
3394 const CACHEFILE_ENTRY * pEntry;
3395 const URL_CACHEFILE_ENTRY * pUrlEntry;
3396 URLCACHECONTAINER * pContainer;
3398 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3400 if (!URLCacheContainers_FindContainerW(url, &pContainer))
3401 return FALSE;
3403 if (!URLCacheContainer_OpenIndex(pContainer))
3404 return FALSE;
3406 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3407 return FALSE;
3409 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3411 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3412 TRACE("entry %s not found!\n", debugstr_w(url));
3413 SetLastError(ERROR_FILE_NOT_FOUND);
3414 return FALSE;
3417 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3418 if (pEntry->dwSignature != URL_SIGNATURE)
3420 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3421 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3422 SetLastError(ERROR_FILE_NOT_FOUND);
3423 return FALSE;
3426 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3428 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3430 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3432 return TRUE;