gdi32/tests: Fix a test failure on NT4.
[wine/hacks.git] / dlls / wininet / urlcache.c
blobb4feba3260c1f9899dc1692c46623cc2dabea385
1 /*
2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003-2008 Robert Shearman
7 * Eric Kohl
8 * Aric Stewart
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
26 #include "wine/port.h"
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
31 #if defined(__MINGW32__) || defined (_MSC_VER)
32 #include <ws2tcpip.h>
33 #endif
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
42 #endif
43 #include <time.h>
45 #include "windef.h"
46 #include "winbase.h"
47 #include "winuser.h"
48 #include "wininet.h"
49 #include "winineti.h"
50 #include "winerror.h"
51 #include "internet.h"
52 #include "winreg.h"
53 #include "shlwapi.h"
54 #include "shlobj.h"
56 #include "wine/unicode.h"
57 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
61 #define ENTRY_START_OFFSET 0x4000
62 #define DIR_LENGTH 8
63 #define BLOCKSIZE 128
64 #define HASHTABLE_SIZE 448
65 #define HASHTABLE_BLOCKSIZE 7
66 #define HASHTABLE_FREE 3
67 #define ALLOCATION_TABLE_OFFSET 0x250
68 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
69 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
70 #define NEWFILE_NUM_BLOCKS 0xd80
71 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
73 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
74 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
75 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
76 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
77 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
79 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
81 typedef struct _CACHEFILE_ENTRY
83 /* union
84 {*/
85 DWORD dwSignature; /* e.g. "URL " */
86 /* CHAR szSignature[4];
87 };*/
88 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
89 } CACHEFILE_ENTRY;
91 typedef struct _URL_CACHEFILE_ENTRY
93 CACHEFILE_ENTRY CacheFileEntry;
94 FILETIME LastModifiedTime;
95 FILETIME LastAccessTime;
96 WORD wExpiredDate; /* expire date in dos format */
97 WORD wExpiredTime; /* expire time in dos format */
98 DWORD dwUnknown1; /* usually zero */
99 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
100 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
101 DWORD dwUnknown2; /* usually zero */
102 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
103 DWORD dwUnknown3; /* usually 0x60 */
104 DWORD dwOffsetUrl; /* offset of start of url from start of entry */
105 BYTE CacheDir; /* index of cache directory this url is stored in */
106 BYTE Unknown4; /* usually zero */
107 WORD wUnknown5; /* usually 0x1010 */
108 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
109 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
110 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
111 DWORD dwHeaderInfoSize;
112 DWORD dwOffsetFileExtension; /* offset of start of file extension from start of entry */
113 WORD wLastSyncDate; /* last sync date in dos format */
114 WORD wLastSyncTime; /* last sync time in dos format */
115 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
116 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
117 WORD wUnknownDate; /* usually same as wLastSyncDate */
118 WORD wUnknownTime; /* usually same as wLastSyncTime */
119 DWORD dwUnknown7; /* usually zero */
120 DWORD dwUnknown8; /* usually zero */
121 /* packing to dword align start of next field */
122 /* CHAR szSourceUrlName[]; (url) */
123 /* packing to dword align start of next field */
124 /* CHAR szLocalFileName[]; (local file name excluding path) */
125 /* packing to dword align start of next field */
126 /* CHAR szHeaderInfo[]; (header info) */
127 } URL_CACHEFILE_ENTRY;
129 struct _HASH_ENTRY
131 DWORD dwHashKey;
132 DWORD dwOffsetEntry;
135 typedef struct _HASH_CACHEFILE_ENTRY
137 CACHEFILE_ENTRY CacheFileEntry;
138 DWORD dwAddressNext;
139 DWORD dwHashTableNumber;
140 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
141 } HASH_CACHEFILE_ENTRY;
143 typedef struct _DIRECTORY_DATA
145 DWORD dwUnknown;
146 char filename[DIR_LENGTH];
147 } DIRECTORY_DATA;
149 typedef struct _URLCACHE_HEADER
151 char szSignature[28];
152 DWORD dwFileSize;
153 DWORD dwOffsetFirstHashTable;
154 DWORD dwIndexCapacityInBlocks;
155 DWORD dwBlocksInUse;
156 DWORD dwUnknown1;
157 DWORD dwCacheLimitLow; /* disk space limit for cache */
158 DWORD dwCacheLimitHigh; /* disk space limit for cache */
159 DWORD dwUnknown4; /* current disk space usage for cache */
160 DWORD dwUnknown5; /* current disk space usage for cache */
161 DWORD dwUnknown6; /* possibly a flag? */
162 DWORD dwUnknown7;
163 BYTE DirectoryCount; /* number of directory_data's */
164 BYTE Unknown8[3]; /* just padding? */
165 DIRECTORY_DATA directory_data[1]; /* first directory entry */
166 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
167 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
169 typedef struct _STREAM_HANDLE
171 HANDLE hFile;
172 CHAR lpszUrl[1];
173 } STREAM_HANDLE;
175 typedef struct _URLCACHECONTAINER
177 struct list entry; /* part of a list */
178 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
179 LPWSTR path; /* path to url container directory */
180 HANDLE hMapping; /* handle of file mapping */
181 DWORD file_size; /* size of file when mapping was opened */
182 HANDLE hMutex; /* handle of mutex */
183 } URLCACHECONTAINER;
186 /* List of all containers available */
187 static struct list UrlContainers = LIST_INIT(UrlContainers);
189 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash);
191 /***********************************************************************
192 * URLCache_PathToObjectName (Internal)
194 * Converts a path to a name suitable for use as a Win32 object name.
195 * Replaces '\\' characters in-place with the specified character
196 * (usually '_' or '!')
198 * RETURNS
199 * nothing
202 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
204 for (; *lpszPath; lpszPath++)
206 if (*lpszPath == '\\')
207 *lpszPath = replace;
211 /***********************************************************************
212 * URLCacheContainer_OpenIndex (Internal)
214 * Opens the index file and saves mapping handle in hCacheIndexMapping
216 * RETURNS
217 * ERROR_SUCCESS if succeeded
218 * Any other Win32 error code if failed
221 static DWORD URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
223 HANDLE hFile;
224 WCHAR wszFilePath[MAX_PATH];
225 DWORD dwFileSize;
227 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
228 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
230 if (pContainer->hMapping)
231 return ERROR_SUCCESS;
233 strcpyW(wszFilePath, pContainer->path);
234 strcatW(wszFilePath, wszIndex);
236 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
237 if (hFile == INVALID_HANDLE_VALUE)
239 /* Maybe the directory wasn't there? Try to create it */
240 if (CreateDirectoryW(pContainer->path, 0))
241 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
243 if (hFile == INVALID_HANDLE_VALUE)
245 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath));
246 return GetLastError();
249 /* At this stage we need the mutex because we may be about to create the
250 * file.
252 WaitForSingleObject(pContainer->hMutex, INFINITE);
254 dwFileSize = GetFileSize(hFile, NULL);
255 if (dwFileSize == INVALID_FILE_SIZE)
257 ReleaseMutex(pContainer->hMutex);
258 return GetLastError();
261 if (dwFileSize == 0)
263 static const CHAR szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content";
264 HKEY key;
265 char achZeroes[0x1000];
266 DWORD dwOffset;
267 DWORD dwError = ERROR_SUCCESS;
269 /* Write zeroes to the entire file so we can safely map it without
270 * fear of getting a SEGV because the disk is full.
272 memset(achZeroes, 0, sizeof(achZeroes));
273 for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes))
275 DWORD dwWrite = sizeof(achZeroes);
276 DWORD dwWritten;
278 if (NEWFILE_SIZE - dwOffset < dwWrite)
279 dwWrite = NEWFILE_SIZE - dwOffset;
280 if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) ||
281 dwWritten != dwWrite)
283 /* If we fail to write, we need to return the error that
284 * cause the problem and also make sure the file is no
285 * longer there, if possible.
287 dwError = GetLastError();
289 break;
293 if (dwError == ERROR_SUCCESS)
295 HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL);
297 if (hMapping)
299 URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE);
301 if (pHeader)
303 WCHAR *pwchDir;
304 WCHAR wszDirPath[MAX_PATH];
305 FILETIME ft;
306 int i, j;
307 HASH_CACHEFILE_ENTRY *pHashEntry;
309 dwFileSize = NEWFILE_SIZE;
311 /* First set some constants and defaults in the header */
312 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
313 pHeader->dwFileSize = dwFileSize;
314 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
315 /* 127MB - taken from default for Windows 2000 */
316 pHeader->dwCacheLimitHigh = 0;
317 pHeader->dwCacheLimitLow = 0x07ff5400;
318 /* Copied from a Windows 2000 cache index */
319 pHeader->DirectoryCount = 4;
321 /* If the registry has a cache size set, use the registry value */
322 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
324 DWORD dw;
325 DWORD len = sizeof(dw);
326 DWORD keytype;
328 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
329 (BYTE *) &dw, &len) == ERROR_SUCCESS &&
330 keytype == REG_DWORD)
332 pHeader->dwCacheLimitHigh = (dw >> 22);
333 pHeader->dwCacheLimitLow = dw << 10;
335 RegCloseKey(key);
338 URLCache_CreateHashTable(pHeader, NULL, &pHashEntry);
340 /* Last step - create the directories */
342 strcpyW(wszDirPath, pContainer->path);
343 pwchDir = wszDirPath + strlenW(wszDirPath);
344 pwchDir[8] = 0;
346 GetSystemTimeAsFileTime(&ft);
348 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
350 /* The following values were copied from a Windows index.
351 * I don't know what the values are supposed to mean but
352 * have made them the same in the hope that this will
353 * be better for compatibility
355 pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
356 for (j = 0;; ++j)
358 int k;
359 ULONGLONG n = ft.dwHighDateTime;
361 /* Generate a file name to attempt to create.
362 * This algorithm will create what will appear
363 * to be random and unrelated directory names
364 * of up to 9 characters in length.
366 n <<= 32;
367 n += ft.dwLowDateTime;
368 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
370 for (k = 0; k < 8; ++k)
372 int r = (n % 36);
374 /* Dividing by a prime greater than 36 helps
375 * with the appearance of randomness
377 n /= 37;
379 if (r < 10)
380 pwchDir[k] = '0' + r;
381 else
382 pwchDir[k] = 'A' + (r - 10);
385 if (CreateDirectoryW(wszDirPath, 0))
387 /* The following is OK because we generated an
388 * 8 character directory name made from characters
389 * [A-Z0-9], which are equivalent for all code
390 * pages and for UTF-16
392 for (k = 0; k < 8; ++k)
393 pHeader->directory_data[i].filename[k] = pwchDir[k];
394 break;
396 else if (j >= 255)
398 /* Give up. The most likely cause of this
399 * is a full disk, but whatever the cause
400 * is, it should be more than apparent that
401 * we won't succeed.
403 dwError = GetLastError();
404 break;
409 UnmapViewOfFile(pHeader);
411 else
413 dwError = GetLastError();
415 CloseHandle(hMapping);
417 else
419 dwError = GetLastError();
423 if (dwError)
425 CloseHandle(hFile);
426 DeleteFileW(wszFilePath);
427 ReleaseMutex(pContainer->hMutex);
428 return dwError;
433 ReleaseMutex(pContainer->hMutex);
435 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
436 URLCache_PathToObjectName(wszFilePath, '_');
437 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
438 if (!pContainer->hMapping)
439 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
440 CloseHandle(hFile);
441 if (!pContainer->hMapping)
443 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
444 return GetLastError();
447 return ERROR_SUCCESS;
450 /***********************************************************************
451 * URLCacheContainer_CloseIndex (Internal)
453 * Closes the index
455 * RETURNS
456 * nothing
459 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
461 CloseHandle(pContainer->hMapping);
462 pContainer->hMapping = NULL;
465 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
467 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
468 int path_len = strlenW(path);
469 int cache_prefix_len = strlenW(cache_prefix);
471 if (!pContainer)
473 return FALSE;
476 pContainer->hMapping = NULL;
477 pContainer->file_size = 0;
479 pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR));
480 if (!pContainer->path)
482 HeapFree(GetProcessHeap(), 0, pContainer);
483 return FALSE;
486 memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR));
488 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
489 if (!pContainer->cache_prefix)
491 HeapFree(GetProcessHeap(), 0, pContainer->path);
492 HeapFree(GetProcessHeap(), 0, pContainer);
493 return FALSE;
496 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
498 CharLowerW(mutex_name);
499 URLCache_PathToObjectName(mutex_name, '!');
501 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
503 ERR("couldn't create mutex (error is %d)\n", GetLastError());
504 HeapFree(GetProcessHeap(), 0, pContainer->path);
505 HeapFree(GetProcessHeap(), 0, pContainer);
506 return FALSE;
509 list_add_head(&UrlContainers, &pContainer->entry);
511 return TRUE;
514 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
516 list_remove(&pContainer->entry);
518 URLCacheContainer_CloseIndex(pContainer);
519 CloseHandle(pContainer->hMutex);
520 HeapFree(GetProcessHeap(), 0, pContainer->path);
521 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
522 HeapFree(GetProcessHeap(), 0, pContainer);
525 void URLCacheContainers_CreateDefaults(void)
527 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
528 static const WCHAR UrlPrefix[] = {0};
529 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
530 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
531 static const WCHAR CookieSuffix[] = {0};
532 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
533 static const struct
535 int nFolder; /* CSIDL_* constant */
536 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
537 const WCHAR * cache_prefix; /* prefix used to reference the container */
538 } DefaultContainerData[] =
540 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
541 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
542 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
544 DWORD i;
546 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
548 WCHAR wszCachePath[MAX_PATH];
549 WCHAR wszMutexName[MAX_PATH];
550 int path_len, suffix_len;
552 if (!SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE))
554 ERR("Couldn't get path for default container %u\n", i);
555 continue;
557 path_len = strlenW(wszCachePath);
558 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
560 if (path_len + suffix_len + 2 > MAX_PATH)
562 ERR("Path too long\n");
563 continue;
566 wszCachePath[path_len] = '\\';
567 wszCachePath[path_len+1] = 0;
569 strcpyW(wszMutexName, wszCachePath);
571 if (suffix_len)
573 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
574 wszCachePath[path_len + suffix_len + 1] = '\\';
575 wszCachePath[path_len + suffix_len + 2] = '\0';
578 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
582 void URLCacheContainers_DeleteAll(void)
584 while(!list_empty(&UrlContainers))
585 URLCacheContainer_DeleteContainer(
586 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
590 static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
592 URLCACHECONTAINER * pContainer;
594 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
596 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
598 int prefix_len = strlenW(pContainer->cache_prefix);
599 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
601 TRACE("found container with prefix %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
602 *ppContainer = pContainer;
603 return ERROR_SUCCESS;
606 ERR("no container found\n");
607 return ERROR_FILE_NOT_FOUND;
610 static DWORD URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
612 DWORD ret;
613 LPWSTR lpwszUrl;
614 int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
615 if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR))))
617 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len);
618 ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer);
619 HeapFree(GetProcessHeap(), 0, lpwszUrl);
620 return ret;
622 return GetLastError();
625 static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, URLCACHECONTAINER ** ppContainer)
627 DWORD i = 0;
628 URLCACHECONTAINER * pContainer;
630 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern));
632 /* non-NULL search pattern only returns one container ever */
633 if (lpwszSearchPattern && dwIndex > 0)
634 return FALSE;
636 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
638 if (lpwszSearchPattern)
640 if (!strcmpW(pContainer->cache_prefix, lpwszSearchPattern))
642 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
643 *ppContainer = pContainer;
644 return TRUE;
647 else
649 if (i == dwIndex)
651 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
652 *ppContainer = pContainer;
653 return TRUE;
656 i++;
658 return FALSE;
661 /***********************************************************************
662 * URLCacheContainer_LockIndex (Internal)
664 * Locks the index for system-wide exclusive access.
666 * RETURNS
667 * Cache file header if successful
668 * NULL if failed and calls SetLastError.
670 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
672 BYTE index;
673 LPVOID pIndexData;
674 URLCACHE_HEADER * pHeader;
675 DWORD error;
677 /* acquire mutex */
678 WaitForSingleObject(pContainer->hMutex, INFINITE);
680 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
682 if (!pIndexData)
684 ReleaseMutex(pContainer->hMutex);
685 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
686 return NULL;
688 pHeader = (URLCACHE_HEADER *)pIndexData;
690 /* file has grown - we need to remap to prevent us getting
691 * access violations when we try and access beyond the end
692 * of the memory mapped file */
693 if (pHeader->dwFileSize != pContainer->file_size)
695 URLCacheContainer_CloseIndex(pContainer);
696 error = URLCacheContainer_OpenIndex(pContainer);
697 if (error != ERROR_SUCCESS)
699 ReleaseMutex(pContainer->hMutex);
700 SetLastError(error);
701 return NULL;
703 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
705 if (!pIndexData)
707 ReleaseMutex(pContainer->hMutex);
708 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
709 return NULL;
711 pHeader = (URLCACHE_HEADER *)pIndexData;
714 TRACE("Signature: %s, file size: %d bytes\n", pHeader->szSignature, pHeader->dwFileSize);
716 for (index = 0; index < pHeader->DirectoryCount; index++)
718 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
721 return pHeader;
724 /***********************************************************************
725 * URLCacheContainer_UnlockIndex (Internal)
728 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
730 /* release mutex */
731 ReleaseMutex(pContainer->hMutex);
732 return UnmapViewOfFile(pHeader);
736 #ifndef CHAR_BIT
737 #define CHAR_BIT (8 * sizeof(CHAR))
738 #endif
740 /***********************************************************************
741 * URLCache_Allocation_BlockIsFree (Internal)
743 * Is the specified block number free?
745 * RETURNS
746 * zero if free
747 * non-zero otherwise
750 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
752 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
753 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
756 /***********************************************************************
757 * URLCache_Allocation_BlockFree (Internal)
759 * Marks the specified block as free
761 * RETURNS
762 * nothing
765 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
767 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
768 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
771 /***********************************************************************
772 * URLCache_Allocation_BlockAllocate (Internal)
774 * Marks the specified block as allocated
776 * RETURNS
777 * nothing
780 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
782 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
783 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
786 /***********************************************************************
787 * URLCache_FindFirstFreeEntry (Internal)
789 * Finds and allocates the first block of free space big enough and
790 * sets ppEntry to point to it.
792 * RETURNS
793 * TRUE if it had enough space
794 * FALSE if it couldn't find enough space
797 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
799 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
800 DWORD dwBlockNumber;
801 DWORD dwFreeCounter;
802 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
804 for (dwFreeCounter = 0;
805 dwFreeCounter < dwBlocksNeeded &&
806 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
807 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
808 dwFreeCounter++)
809 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
811 if (dwFreeCounter == dwBlocksNeeded)
813 DWORD index;
814 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
815 for (index = 0; index < dwBlocksNeeded; index++)
816 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
817 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
818 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
819 return TRUE;
822 FIXME("Grow file\n");
823 return FALSE;
826 /***********************************************************************
827 * URLCache_DeleteEntry (Internal)
829 * Deletes the specified entry and frees the space allocated to it
831 * RETURNS
832 * TRUE if it succeeded
833 * FALSE if it failed
836 static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, CACHEFILE_ENTRY * pEntry)
838 DWORD dwStartBlock;
839 DWORD dwBlock;
840 BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
842 /* update allocation table */
843 dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE;
844 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
845 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
847 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
848 return TRUE;
851 /***********************************************************************
852 * URLCache_LocalFileNameToPathW (Internal)
854 * Copies the full path to the specified buffer given the local file
855 * name and the index of the directory it is in. Always sets value in
856 * lpBufferSize to the required buffer size (in bytes).
858 * RETURNS
859 * TRUE if the buffer was big enough
860 * FALSE if the buffer was too small
863 static BOOL URLCache_LocalFileNameToPathW(
864 const URLCACHECONTAINER * pContainer,
865 LPCURLCACHE_HEADER pHeader,
866 LPCSTR szLocalFileName,
867 BYTE Directory,
868 LPWSTR wszPath,
869 LPLONG lpBufferSize)
871 LONG nRequired;
872 int path_len = strlenW(pContainer->path);
873 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
874 if (Directory >= pHeader->DirectoryCount)
876 *lpBufferSize = 0;
877 return FALSE;
880 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
881 if (nRequired < *lpBufferSize)
883 int dir_len;
885 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
886 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
887 wszPath[dir_len + path_len] = '\\';
888 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
889 *lpBufferSize = nRequired;
890 return TRUE;
892 *lpBufferSize = nRequired;
893 return FALSE;
896 /***********************************************************************
897 * URLCache_LocalFileNameToPathA (Internal)
899 * Copies the full path to the specified buffer given the local file
900 * name and the index of the directory it is in. Always sets value in
901 * lpBufferSize to the required buffer size.
903 * RETURNS
904 * TRUE if the buffer was big enough
905 * FALSE if the buffer was too small
908 static BOOL URLCache_LocalFileNameToPathA(
909 const URLCACHECONTAINER * pContainer,
910 LPCURLCACHE_HEADER pHeader,
911 LPCSTR szLocalFileName,
912 BYTE Directory,
913 LPSTR szPath,
914 LPLONG lpBufferSize)
916 LONG nRequired;
917 int path_len, file_name_len, dir_len;
919 if (Directory >= pHeader->DirectoryCount)
921 *lpBufferSize = 0;
922 return FALSE;
925 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL) - 1;
926 file_name_len = strlen(szLocalFileName) + 1 /* for nul-terminator */;
927 dir_len = DIR_LENGTH;
929 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(char);
930 if (nRequired < *lpBufferSize)
932 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, path_len, NULL, NULL);
933 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
934 szPath[path_len + dir_len] = '\\';
935 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
936 *lpBufferSize = nRequired;
937 return TRUE;
939 *lpBufferSize = nRequired;
940 return FALSE;
943 /***********************************************************************
944 * URLCache_CopyEntry (Internal)
946 * Copies an entry from the cache index file to the Win32 structure
948 * RETURNS
949 * ERROR_SUCCESS if the buffer was big enough
950 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
953 static DWORD URLCache_CopyEntry(
954 URLCACHECONTAINER * pContainer,
955 LPCURLCACHE_HEADER pHeader,
956 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
957 LPDWORD lpdwBufferSize,
958 const URL_CACHEFILE_ENTRY * pUrlEntry,
959 BOOL bUnicode)
961 int lenUrl;
962 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
964 if (*lpdwBufferSize >= dwRequiredSize)
966 lpCacheEntryInfo->lpHeaderInfo = NULL;
967 lpCacheEntryInfo->lpszFileExtension = NULL;
968 lpCacheEntryInfo->lpszLocalFileName = NULL;
969 lpCacheEntryInfo->lpszSourceUrlName = NULL;
970 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
971 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
972 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
973 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
974 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
975 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
976 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
977 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
978 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
979 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
980 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
981 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
982 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
983 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
986 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
987 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
988 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
989 if (bUnicode)
990 lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0);
991 else
992 lenUrl = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
993 dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
995 /* FIXME: is source url optional? */
996 if (*lpdwBufferSize >= dwRequiredSize)
998 DWORD lenUrlBytes = (lenUrl+1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
1000 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrlBytes;
1001 if (bUnicode)
1002 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
1003 else
1004 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lenUrlBytes);
1007 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1008 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1009 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1011 if (pUrlEntry->dwOffsetLocalName)
1013 LONG nLocalFilePathSize;
1014 LPSTR lpszLocalFileName;
1015 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
1016 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
1017 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
1018 (!bUnicode && URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize)))
1020 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
1022 dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ;
1024 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1025 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1026 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1028 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
1030 if (*lpdwBufferSize >= dwRequiredSize)
1032 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
1033 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
1034 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
1036 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1037 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1038 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1040 if (pUrlEntry->dwOffsetFileExtension)
1042 int lenExtension;
1044 if (bUnicode)
1045 lenExtension = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, NULL, 0);
1046 else
1047 lenExtension = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension) + 1;
1048 dwRequiredSize += lenExtension * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
1050 if (*lpdwBufferSize >= dwRequiredSize)
1052 lpCacheEntryInfo->lpszFileExtension = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenExtension;
1053 if (bUnicode)
1054 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenExtension);
1055 else
1056 memcpy(lpCacheEntryInfo->lpszFileExtension, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, lenExtension * sizeof(CHAR));
1059 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1060 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1061 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1064 if (dwRequiredSize > *lpdwBufferSize)
1066 *lpdwBufferSize = dwRequiredSize;
1067 return ERROR_INSUFFICIENT_BUFFER;
1069 *lpdwBufferSize = dwRequiredSize;
1070 return ERROR_SUCCESS;
1074 /***********************************************************************
1075 * URLCache_SetEntryInfo (Internal)
1077 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1078 * according to the flags set by dwFieldControl.
1080 * RETURNS
1081 * ERROR_SUCCESS if the buffer was big enough
1082 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1085 static DWORD URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1087 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1088 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1089 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1090 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1091 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1092 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1093 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1094 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1095 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1096 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1097 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1098 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1099 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1100 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1101 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1102 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1104 return ERROR_SUCCESS;
1107 /***********************************************************************
1108 * URLCache_HashKey (Internal)
1110 * Returns the hash key for a given string
1112 * RETURNS
1113 * hash key for the string
1116 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1118 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1119 * but the algorithm and result are not the same!
1121 static const unsigned char lookupTable[256] =
1123 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1124 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1125 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1126 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1127 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1128 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1129 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1130 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1131 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1132 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1133 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1134 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1135 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1136 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1137 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1138 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1139 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1140 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1141 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1142 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1143 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1144 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1145 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1146 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1147 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1148 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1149 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1150 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1151 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1152 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1153 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1154 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1156 BYTE key[4];
1157 DWORD i;
1159 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1160 key[i] = lookupTable[i];
1162 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
1164 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1165 key[i] = lookupTable[*lpszKey ^ key[i]];
1168 return *(DWORD *)key;
1171 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
1173 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
1176 static inline BOOL URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY *pHashEntry)
1178 /* check pHashEntry located within acceptable bounds in the URL cache mapping */
1179 return ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) &&
1180 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1183 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1185 /* structure of hash table:
1186 * 448 entries divided into 64 blocks
1187 * each block therefore contains a chain of 7 key/offset pairs
1188 * how position in table is calculated:
1189 * 1. the url is hashed in helper function
1190 * 2. the key % 64 * 8 is the offset
1191 * 3. the key in the hash table is the hash key aligned to 64
1193 * note:
1194 * there can be multiple hash tables in the file and the offset to
1195 * the next one is stored in the header of the hash table
1197 DWORD key = URLCache_HashKey(lpszUrl);
1198 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1199 HASH_CACHEFILE_ENTRY * pHashEntry;
1200 DWORD dwHashTableNumber = 0;
1202 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1204 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1205 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1206 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1208 int i;
1209 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1211 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1212 continue;
1214 /* make sure that it is in fact a hash entry */
1215 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1217 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1218 continue;
1221 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1223 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1224 if (key == (pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
1226 /* FIXME: we should make sure that this is the right element
1227 * before returning and claiming that it is. We can do this
1228 * by doing a simple compare between the URL we were given
1229 * and the URL stored in the entry. However, this assumes
1230 * we know the format of all the entries stored in the
1231 * hash table */
1232 *ppHashEntry = pHashElement;
1233 return TRUE;
1237 return FALSE;
1240 static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1242 LPSTR urlA;
1243 int url_len;
1244 BOOL ret;
1246 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1247 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1248 if (!urlA)
1250 SetLastError(ERROR_OUTOFMEMORY);
1251 return FALSE;
1253 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, urlA, url_len, NULL, NULL);
1254 ret = URLCache_FindHash(pHeader, urlA, ppHashEntry);
1255 HeapFree(GetProcessHeap(), 0, urlA);
1256 return ret;
1259 /***********************************************************************
1260 * URLCache_HashEntrySetUse (Internal)
1262 * Searches all the hash tables in the index for the given URL and
1263 * sets the use count (stored or'ed with key)
1265 * RETURNS
1266 * TRUE if the entry was found
1267 * FALSE if the entry could not be found
1270 static BOOL URLCache_HashEntrySetUse(struct _HASH_ENTRY * pHashEntry, DWORD dwUseCount)
1272 pHashEntry->dwHashKey = dwUseCount | (pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1273 return TRUE;
1276 /***********************************************************************
1277 * URLCache_DeleteEntryFromHash (Internal)
1279 * Searches all the hash tables in the index for the given URL and
1280 * then if found deletes the entry.
1282 * RETURNS
1283 * TRUE if the entry was found
1284 * FALSE if the entry could not be found
1287 static BOOL URLCache_DeleteEntryFromHash(struct _HASH_ENTRY * pHashEntry)
1289 pHashEntry->dwHashKey = HASHTABLE_FREE;
1290 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1291 return TRUE;
1294 /***********************************************************************
1295 * URLCache_AddEntryToHash (Internal)
1297 * Searches all the hash tables for a free slot based on the offset
1298 * generated from the hash key. If a free slot is found, the offset and
1299 * key are entered into the hash table.
1301 * RETURNS
1302 * ERROR_SUCCESS if the entry was added
1303 * Any other Win32 error code if the entry could not be added
1306 static DWORD URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1308 /* see URLCache_FindEntryInHash for structure of hash tables */
1310 DWORD key = URLCache_HashKey(lpszUrl);
1311 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1312 HASH_CACHEFILE_ENTRY * pHashEntry;
1313 DWORD dwHashTableNumber = 0;
1314 DWORD error;
1316 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1318 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1319 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1320 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1322 int i;
1323 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1325 ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1326 break;
1328 /* make sure that it is in fact a hash entry */
1329 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1331 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1332 break;
1335 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1337 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1338 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1340 pHashElement->dwHashKey = key;
1341 pHashElement->dwOffsetEntry = dwOffsetEntry;
1342 return ERROR_SUCCESS;
1346 error = URLCache_CreateHashTable(pHeader, pHashEntry, &pHashEntry);
1347 if (error != ERROR_SUCCESS)
1348 return error;
1350 pHashEntry->HashTable[offset].dwHashKey = key;
1351 pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry;
1352 return ERROR_SUCCESS;
1355 /***********************************************************************
1356 * URLCache_CreateHashTable (Internal)
1358 * Creates a new hash table in free space and adds it to the chain of existing
1359 * hash tables.
1361 * RETURNS
1362 * ERROR_SUCCESS if the hash table was created
1363 * ERROR_DISK_FULL if the hash table could not be created
1366 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash)
1368 DWORD dwOffset;
1369 int i;
1371 if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)ppHash))
1373 FIXME("no free space for hash table\n");
1374 return ERROR_DISK_FULL;
1377 dwOffset = (BYTE *)*ppHash - (BYTE *)pHeader;
1379 if (pPrevHash)
1380 pPrevHash->dwAddressNext = dwOffset;
1381 else
1382 pHeader->dwOffsetFirstHashTable = dwOffset;
1383 (*ppHash)->CacheFileEntry.dwSignature = HASH_SIGNATURE;
1384 (*ppHash)->CacheFileEntry.dwBlocksUsed = 0x20;
1385 (*ppHash)->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0;
1386 for (i = 0; i < HASHTABLE_SIZE; i++)
1388 (*ppHash)->HashTable[i].dwOffsetEntry = 0;
1389 (*ppHash)->HashTable[i].dwHashKey = HASHTABLE_FREE;
1391 return ERROR_SUCCESS;
1394 /***********************************************************************
1395 * URLCache_EnumHashTables (Internal)
1397 * Enumerates the hash tables in a container.
1399 * RETURNS
1400 * TRUE if an entry was found
1401 * FALSE if there are no more tables to enumerate.
1404 static BOOL URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader, DWORD *pdwHashTableNumber, HASH_CACHEFILE_ENTRY ** ppHashEntry)
1406 for (*ppHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1407 URLCache_IsHashEntryValid(pHeader, *ppHashEntry);
1408 *ppHashEntry = URLCache_HashEntryFromOffset(pHeader, (*ppHashEntry)->dwAddressNext))
1410 TRACE("looking at hash table number %d\n", (*ppHashEntry)->dwHashTableNumber);
1411 if ((*ppHashEntry)->dwHashTableNumber != *pdwHashTableNumber)
1412 continue;
1413 /* make sure that it is in fact a hash entry */
1414 if ((*ppHashEntry)->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1416 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&(*ppHashEntry)->CacheFileEntry.dwSignature);
1417 (*pdwHashTableNumber)++;
1418 continue;
1421 TRACE("hash table number %d found\n", *pdwHashTableNumber);
1422 return TRUE;
1424 return FALSE;
1427 /***********************************************************************
1428 * URLCache_EnumHashTableEntries (Internal)
1430 * Enumerates entries in a hash table and returns the next non-free entry.
1432 * RETURNS
1433 * TRUE if an entry was found
1434 * FALSE if the hash table is empty or there are no more entries to
1435 * enumerate.
1438 static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY * pHashEntry,
1439 DWORD * index, const struct _HASH_ENTRY ** ppHashEntry)
1441 for (; *index < HASHTABLE_SIZE ; (*index)++)
1443 if (pHashEntry->HashTable[*index].dwHashKey == HASHTABLE_FREE)
1444 continue;
1446 *ppHashEntry = &pHashEntry->HashTable[*index];
1447 TRACE("entry found %d\n", *index);
1448 return TRUE;
1450 TRACE("no more entries (%d)\n", *index);
1451 return FALSE;
1454 /***********************************************************************
1455 * GetUrlCacheEntryInfoExA (WININET.@)
1458 BOOL WINAPI GetUrlCacheEntryInfoExA(
1459 LPCSTR lpszUrl,
1460 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1461 LPDWORD lpdwCacheEntryInfoBufSize,
1462 LPSTR lpszReserved,
1463 LPDWORD lpdwReserved,
1464 LPVOID lpReserved,
1465 DWORD dwFlags)
1467 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1468 debugstr_a(lpszUrl),
1469 lpCacheEntryInfo,
1470 lpdwCacheEntryInfoBufSize,
1471 lpszReserved,
1472 lpdwReserved,
1473 lpReserved,
1474 dwFlags);
1476 if ((lpszReserved != NULL) ||
1477 (lpdwReserved != NULL) ||
1478 (lpReserved != NULL))
1480 ERR("Reserved value was not 0\n");
1481 SetLastError(ERROR_INVALID_PARAMETER);
1482 return FALSE;
1484 if (dwFlags != 0)
1485 FIXME("Undocumented flag(s): %x\n", dwFlags);
1486 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1489 /***********************************************************************
1490 * GetUrlCacheEntryInfoA (WININET.@)
1493 BOOL WINAPI GetUrlCacheEntryInfoA(
1494 IN LPCSTR lpszUrlName,
1495 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1496 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1499 LPURLCACHE_HEADER pHeader;
1500 struct _HASH_ENTRY * pHashEntry;
1501 const CACHEFILE_ENTRY * pEntry;
1502 const URL_CACHEFILE_ENTRY * pUrlEntry;
1503 URLCACHECONTAINER * pContainer;
1504 DWORD error;
1506 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1508 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1509 if (error != ERROR_SUCCESS)
1511 SetLastError(error);
1512 return FALSE;
1515 error = URLCacheContainer_OpenIndex(pContainer);
1516 if (error != ERROR_SUCCESS)
1518 SetLastError(error);
1519 return FALSE;
1522 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1523 return FALSE;
1525 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1527 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1528 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1529 SetLastError(ERROR_FILE_NOT_FOUND);
1530 return FALSE;
1533 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1534 if (pEntry->dwSignature != URL_SIGNATURE)
1536 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1537 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1538 SetLastError(ERROR_FILE_NOT_FOUND);
1539 return FALSE;
1542 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1543 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1544 if (pUrlEntry->dwOffsetHeaderInfo)
1545 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1547 if (lpdwCacheEntryInfoBufferSize)
1549 if (!lpCacheEntryInfo)
1550 *lpdwCacheEntryInfoBufferSize = 0;
1552 error = URLCache_CopyEntry(
1553 pContainer,
1554 pHeader,
1555 lpCacheEntryInfo,
1556 lpdwCacheEntryInfoBufferSize,
1557 pUrlEntry,
1558 FALSE /* ANSI */);
1559 if (error != ERROR_SUCCESS)
1561 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1562 SetLastError(error);
1563 return FALSE;
1565 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1568 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1570 return TRUE;
1573 /***********************************************************************
1574 * GetUrlCacheEntryInfoW (WININET.@)
1577 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1578 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1579 LPDWORD lpdwCacheEntryInfoBufferSize)
1581 LPURLCACHE_HEADER pHeader;
1582 struct _HASH_ENTRY * pHashEntry;
1583 const CACHEFILE_ENTRY * pEntry;
1584 const URL_CACHEFILE_ENTRY * pUrlEntry;
1585 URLCACHECONTAINER * pContainer;
1586 DWORD error;
1588 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1590 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1591 if (error != ERROR_SUCCESS)
1593 SetLastError(error);
1594 return FALSE;
1597 error = URLCacheContainer_OpenIndex(pContainer);
1598 if (error != ERROR_SUCCESS)
1600 SetLastError(error);
1601 return FALSE;
1604 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1605 return FALSE;
1607 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1609 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1610 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1611 SetLastError(ERROR_FILE_NOT_FOUND);
1612 return FALSE;
1615 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1616 if (pEntry->dwSignature != URL_SIGNATURE)
1618 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1619 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1620 SetLastError(ERROR_FILE_NOT_FOUND);
1621 return FALSE;
1624 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1625 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1626 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1628 if (lpdwCacheEntryInfoBufferSize)
1630 if (!lpCacheEntryInfo)
1631 *lpdwCacheEntryInfoBufferSize = 0;
1633 error = URLCache_CopyEntry(
1634 pContainer,
1635 pHeader,
1636 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1637 lpdwCacheEntryInfoBufferSize,
1638 pUrlEntry,
1639 TRUE /* UNICODE */);
1640 if (error != ERROR_SUCCESS)
1642 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1643 SetLastError(error);
1644 return FALSE;
1646 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1649 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1651 return TRUE;
1654 /***********************************************************************
1655 * GetUrlCacheEntryInfoExW (WININET.@)
1658 BOOL WINAPI GetUrlCacheEntryInfoExW(
1659 LPCWSTR lpszUrl,
1660 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1661 LPDWORD lpdwCacheEntryInfoBufSize,
1662 LPWSTR lpszReserved,
1663 LPDWORD lpdwReserved,
1664 LPVOID lpReserved,
1665 DWORD dwFlags)
1667 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1668 debugstr_w(lpszUrl),
1669 lpCacheEntryInfo,
1670 lpdwCacheEntryInfoBufSize,
1671 lpszReserved,
1672 lpdwReserved,
1673 lpReserved,
1674 dwFlags);
1676 if ((lpszReserved != NULL) ||
1677 (lpdwReserved != NULL) ||
1678 (lpReserved != NULL))
1680 ERR("Reserved value was not 0\n");
1681 SetLastError(ERROR_INVALID_PARAMETER);
1682 return FALSE;
1684 if (dwFlags != 0)
1685 FIXME("Undocumented flag(s): %x\n", dwFlags);
1686 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1689 /***********************************************************************
1690 * SetUrlCacheEntryInfoA (WININET.@)
1692 BOOL WINAPI SetUrlCacheEntryInfoA(
1693 LPCSTR lpszUrlName,
1694 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1695 DWORD dwFieldControl)
1697 LPURLCACHE_HEADER pHeader;
1698 struct _HASH_ENTRY * pHashEntry;
1699 CACHEFILE_ENTRY * pEntry;
1700 URLCACHECONTAINER * pContainer;
1701 DWORD error;
1703 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1705 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1706 if (error != ERROR_SUCCESS)
1708 SetLastError(error);
1709 return FALSE;
1712 error = URLCacheContainer_OpenIndex(pContainer);
1713 if (error != ERROR_SUCCESS)
1715 SetLastError(error);
1716 return FALSE;
1719 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1720 return FALSE;
1722 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1724 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1725 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1726 SetLastError(ERROR_FILE_NOT_FOUND);
1727 return FALSE;
1730 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1731 if (pEntry->dwSignature != URL_SIGNATURE)
1733 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1734 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1735 SetLastError(ERROR_FILE_NOT_FOUND);
1736 return FALSE;
1739 URLCache_SetEntryInfo(
1740 (URL_CACHEFILE_ENTRY *)pEntry,
1741 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1742 dwFieldControl);
1744 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1746 return TRUE;
1749 /***********************************************************************
1750 * SetUrlCacheEntryInfoW (WININET.@)
1752 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1754 LPURLCACHE_HEADER pHeader;
1755 struct _HASH_ENTRY * pHashEntry;
1756 CACHEFILE_ENTRY * pEntry;
1757 URLCACHECONTAINER * pContainer;
1758 DWORD error;
1760 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1762 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1763 if (error != ERROR_SUCCESS)
1765 SetLastError(error);
1766 return FALSE;
1769 error = URLCacheContainer_OpenIndex(pContainer);
1770 if (error != ERROR_SUCCESS)
1772 SetLastError(error);
1773 return FALSE;
1776 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1777 return FALSE;
1779 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1781 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1782 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1783 SetLastError(ERROR_FILE_NOT_FOUND);
1784 return FALSE;
1787 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1788 if (pEntry->dwSignature != URL_SIGNATURE)
1790 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1791 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1792 SetLastError(ERROR_FILE_NOT_FOUND);
1793 return FALSE;
1796 URLCache_SetEntryInfo(
1797 (URL_CACHEFILE_ENTRY *)pEntry,
1798 lpCacheEntryInfo,
1799 dwFieldControl);
1801 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1803 return TRUE;
1806 /***********************************************************************
1807 * RetrieveUrlCacheEntryFileA (WININET.@)
1810 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1811 IN LPCSTR lpszUrlName,
1812 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1813 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1814 IN DWORD dwReserved
1817 LPURLCACHE_HEADER pHeader;
1818 struct _HASH_ENTRY * pHashEntry;
1819 CACHEFILE_ENTRY * pEntry;
1820 URL_CACHEFILE_ENTRY * pUrlEntry;
1821 URLCACHECONTAINER * pContainer;
1822 DWORD error;
1824 TRACE("(%s, %p, %p, 0x%08x)\n",
1825 debugstr_a(lpszUrlName),
1826 lpCacheEntryInfo,
1827 lpdwCacheEntryInfoBufferSize,
1828 dwReserved);
1830 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1831 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1833 SetLastError(ERROR_INVALID_PARAMETER);
1834 return FALSE;
1837 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1838 if (error != ERROR_SUCCESS)
1840 SetLastError(error);
1841 return FALSE;
1844 error = URLCacheContainer_OpenIndex(pContainer);
1845 if (error != ERROR_SUCCESS)
1847 SetLastError(error);
1848 return FALSE;
1851 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1852 return FALSE;
1854 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1856 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1857 TRACE("entry %s not found!\n", lpszUrlName);
1858 SetLastError(ERROR_FILE_NOT_FOUND);
1859 return FALSE;
1862 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1863 if (pEntry->dwSignature != URL_SIGNATURE)
1865 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1866 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1867 SetLastError(ERROR_FILE_NOT_FOUND);
1868 return FALSE;
1871 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1872 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1873 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1875 pUrlEntry->dwHitRate++;
1876 pUrlEntry->dwUseCount++;
1877 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1879 error = URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo,
1880 lpdwCacheEntryInfoBufferSize, pUrlEntry,
1881 FALSE);
1882 if (error != ERROR_SUCCESS)
1884 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1885 SetLastError(error);
1886 return FALSE;
1888 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1890 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1892 return TRUE;
1895 /***********************************************************************
1896 * RetrieveUrlCacheEntryFileW (WININET.@)
1899 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1900 IN LPCWSTR lpszUrlName,
1901 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1902 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1903 IN DWORD dwReserved
1906 LPURLCACHE_HEADER pHeader;
1907 struct _HASH_ENTRY * pHashEntry;
1908 CACHEFILE_ENTRY * pEntry;
1909 URL_CACHEFILE_ENTRY * pUrlEntry;
1910 URLCACHECONTAINER * pContainer;
1911 DWORD error;
1913 TRACE("(%s, %p, %p, 0x%08x)\n",
1914 debugstr_w(lpszUrlName),
1915 lpCacheEntryInfo,
1916 lpdwCacheEntryInfoBufferSize,
1917 dwReserved);
1919 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1920 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1922 SetLastError(ERROR_INVALID_PARAMETER);
1923 return FALSE;
1926 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
1927 if (error != ERROR_SUCCESS)
1929 SetLastError(error);
1930 return FALSE;
1933 error = URLCacheContainer_OpenIndex(pContainer);
1934 if (error != ERROR_SUCCESS)
1936 SetLastError(error);
1937 return FALSE;
1940 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1941 return FALSE;
1943 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1945 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1946 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1947 SetLastError(ERROR_FILE_NOT_FOUND);
1948 return FALSE;
1951 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1952 if (pEntry->dwSignature != URL_SIGNATURE)
1954 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1955 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1956 SetLastError(ERROR_FILE_NOT_FOUND);
1957 return FALSE;
1960 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1961 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1962 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1964 pUrlEntry->dwHitRate++;
1965 pUrlEntry->dwUseCount++;
1966 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1968 error = URLCache_CopyEntry(
1969 pContainer,
1970 pHeader,
1971 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1972 lpdwCacheEntryInfoBufferSize,
1973 pUrlEntry,
1974 TRUE /* UNICODE */);
1975 if (error != ERROR_SUCCESS)
1977 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1978 SetLastError(error);
1979 return FALSE;
1981 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1983 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1985 return TRUE;
1988 /***********************************************************************
1989 * UnlockUrlCacheEntryFileA (WININET.@)
1992 BOOL WINAPI UnlockUrlCacheEntryFileA(
1993 IN LPCSTR lpszUrlName,
1994 IN DWORD dwReserved
1997 LPURLCACHE_HEADER pHeader;
1998 struct _HASH_ENTRY * pHashEntry;
1999 CACHEFILE_ENTRY * pEntry;
2000 URL_CACHEFILE_ENTRY * pUrlEntry;
2001 URLCACHECONTAINER * pContainer;
2002 DWORD error;
2004 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
2006 if (dwReserved)
2008 ERR("dwReserved != 0\n");
2009 SetLastError(ERROR_INVALID_PARAMETER);
2010 return FALSE;
2013 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2014 if (error != ERROR_SUCCESS)
2016 SetLastError(error);
2017 return FALSE;
2020 error = URLCacheContainer_OpenIndex(pContainer);
2021 if (error != ERROR_SUCCESS)
2023 SetLastError(error);
2024 return FALSE;
2027 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2028 return FALSE;
2030 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2032 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2033 TRACE("entry %s not found!\n", lpszUrlName);
2034 SetLastError(ERROR_FILE_NOT_FOUND);
2035 return FALSE;
2038 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2039 if (pEntry->dwSignature != URL_SIGNATURE)
2041 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2042 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2043 SetLastError(ERROR_FILE_NOT_FOUND);
2044 return FALSE;
2047 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2049 if (pUrlEntry->dwUseCount == 0)
2051 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2052 return FALSE;
2054 pUrlEntry->dwUseCount--;
2055 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2057 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2059 return TRUE;
2062 /***********************************************************************
2063 * UnlockUrlCacheEntryFileW (WININET.@)
2066 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
2068 LPURLCACHE_HEADER pHeader;
2069 struct _HASH_ENTRY * pHashEntry;
2070 CACHEFILE_ENTRY * pEntry;
2071 URL_CACHEFILE_ENTRY * pUrlEntry;
2072 URLCACHECONTAINER * pContainer;
2073 DWORD error;
2075 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
2077 if (dwReserved)
2079 ERR("dwReserved != 0\n");
2080 SetLastError(ERROR_INVALID_PARAMETER);
2081 return FALSE;
2084 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2085 if (error != ERROR_SUCCESS)
2087 SetLastError(error);
2088 return FALSE;
2091 error = URLCacheContainer_OpenIndex(pContainer);
2092 if (error != ERROR_SUCCESS)
2094 SetLastError(error);
2095 return FALSE;
2098 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2099 return FALSE;
2101 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
2103 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2104 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
2105 SetLastError(ERROR_FILE_NOT_FOUND);
2106 return FALSE;
2109 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2110 if (pEntry->dwSignature != URL_SIGNATURE)
2112 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2113 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2114 SetLastError(ERROR_FILE_NOT_FOUND);
2115 return FALSE;
2118 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2120 if (pUrlEntry->dwUseCount == 0)
2122 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2123 return FALSE;
2125 pUrlEntry->dwUseCount--;
2126 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2128 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2130 return TRUE;
2133 /***********************************************************************
2134 * CreateUrlCacheEntryA (WININET.@)
2137 BOOL WINAPI CreateUrlCacheEntryA(
2138 IN LPCSTR lpszUrlName,
2139 IN DWORD dwExpectedFileSize,
2140 IN LPCSTR lpszFileExtension,
2141 OUT LPSTR lpszFileName,
2142 IN DWORD dwReserved
2145 DWORD len;
2146 WCHAR *url_name;
2147 WCHAR *file_extension;
2148 WCHAR file_name[MAX_PATH];
2149 BOOL bSuccess = FALSE;
2150 DWORD dwError = 0;
2152 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
2153 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2155 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2156 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 &&
2157 (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2159 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2160 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
2162 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
2164 bSuccess = TRUE;
2166 else
2168 dwError = GetLastError();
2171 else
2173 dwError = GetLastError();
2175 HeapFree(GetProcessHeap(), 0, file_extension);
2177 else
2179 dwError = GetLastError();
2181 HeapFree(GetProcessHeap(), 0, url_name);
2182 if (!bSuccess)
2183 SetLastError(dwError);
2185 return bSuccess;
2187 /***********************************************************************
2188 * CreateUrlCacheEntryW (WININET.@)
2191 BOOL WINAPI CreateUrlCacheEntryW(
2192 IN LPCWSTR lpszUrlName,
2193 IN DWORD dwExpectedFileSize,
2194 IN LPCWSTR lpszFileExtension,
2195 OUT LPWSTR lpszFileName,
2196 IN DWORD dwReserved
2199 URLCACHECONTAINER * pContainer;
2200 LPURLCACHE_HEADER pHeader;
2201 CHAR szFile[MAX_PATH];
2202 WCHAR szExtension[MAX_PATH];
2203 LPCWSTR lpszUrlPart;
2204 LPCWSTR lpszUrlEnd;
2205 LPCWSTR lpszFileNameExtension;
2206 LPWSTR lpszFileNameNoPath;
2207 int i;
2208 int countnoextension;
2209 BYTE CacheDir;
2210 LONG lBufferSize;
2211 BOOL bFound = FALSE;
2212 int count;
2213 DWORD error;
2214 static const WCHAR szWWW[] = {'w','w','w',0};
2216 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2217 debugstr_w(lpszUrlName),
2218 dwExpectedFileSize,
2219 debugstr_w(lpszFileExtension),
2220 lpszFileName,
2221 dwReserved);
2223 if (dwReserved)
2225 ERR("dwReserved != 0\n");
2226 SetLastError(ERROR_INVALID_PARAMETER);
2227 return FALSE;
2230 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2232 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2233 lpszUrlEnd--;
2235 for (lpszUrlPart = lpszUrlEnd;
2236 (lpszUrlPart >= lpszUrlName);
2237 lpszUrlPart--)
2239 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2241 bFound = TRUE;
2242 lpszUrlPart++;
2243 break;
2245 else if(*lpszUrlPart == '?' || *lpszUrlPart == '#')
2247 lpszUrlEnd = lpszUrlPart;
2250 if (!lstrcmpW(lpszUrlPart, szWWW))
2252 lpszUrlPart += lstrlenW(szWWW);
2255 count = lpszUrlEnd - lpszUrlPart;
2257 if (bFound && (count < MAX_PATH))
2259 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2260 if (!len)
2261 return FALSE;
2262 szFile[len] = '\0';
2263 while(len && szFile[--len] == '/') szFile[len] = '\0';
2265 /* FIXME: get rid of illegal characters like \, / and : */
2267 else
2269 FIXME("need to generate a random filename\n");
2272 TRACE("File name: %s\n", debugstr_a(szFile));
2274 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2275 if (error != ERROR_SUCCESS)
2277 SetLastError(error);
2278 return FALSE;
2281 error = URLCacheContainer_OpenIndex(pContainer);
2282 if (error != ERROR_SUCCESS)
2284 SetLastError(error);
2285 return FALSE;
2288 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2289 return FALSE;
2291 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2293 lBufferSize = MAX_PATH * sizeof(WCHAR);
2294 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
2296 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2298 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2299 lpszFileNameNoPath >= lpszFileName;
2300 --lpszFileNameNoPath)
2302 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2303 break;
2306 countnoextension = lstrlenW(lpszFileNameNoPath);
2307 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2308 if (lpszFileNameExtension)
2309 countnoextension -= lstrlenW(lpszFileNameExtension);
2310 *szExtension = '\0';
2312 if (lpszFileExtension)
2314 szExtension[0] = '.';
2315 lstrcpyW(szExtension+1, lpszFileExtension);
2318 for (i = 0; i < 255; i++)
2320 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2321 HANDLE hFile;
2322 WCHAR *p;
2324 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2325 for (p = lpszFileNameNoPath + 1; *p; p++)
2327 switch (*p)
2329 case '<': case '>':
2330 case ':': case '"':
2331 case '/': case '\\':
2332 case '|': case '?':
2333 case '*':
2334 *p = '_'; break;
2335 default: break;
2338 if (p[-1] == ' ' || p[-1] == '.') p[-1] = '_';
2340 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2341 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2342 if (hFile != INVALID_HANDLE_VALUE)
2344 CloseHandle(hFile);
2345 return TRUE;
2349 return FALSE;
2353 /***********************************************************************
2354 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2356 * The bug we are compensating for is that some drongo at Microsoft
2357 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2358 * As a consequence, CommitUrlCacheEntryA has been effectively
2359 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2360 * is still defined as LPCWSTR. The result (other than madness) is
2361 * that we always need to store lpHeaderInfo in CP_ACP rather than
2362 * in UTF16, and we need to avoid converting lpHeaderInfo in
2363 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2364 * result will lose data for arbitrary binary data.
2367 static BOOL CommitUrlCacheEntryInternal(
2368 IN LPCWSTR lpszUrlName,
2369 IN LPCWSTR lpszLocalFileName,
2370 IN FILETIME ExpireTime,
2371 IN FILETIME LastModifiedTime,
2372 IN DWORD CacheEntryType,
2373 IN LPBYTE lpHeaderInfo,
2374 IN DWORD dwHeaderSize,
2375 IN LPCWSTR lpszFileExtension,
2376 IN LPCWSTR lpszOriginalUrl
2379 URLCACHECONTAINER * pContainer;
2380 LPURLCACHE_HEADER pHeader;
2381 struct _HASH_ENTRY * pHashEntry;
2382 CACHEFILE_ENTRY * pEntry;
2383 URL_CACHEFILE_ENTRY * pUrlEntry;
2384 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2385 DWORD dwOffsetLocalFileName = 0;
2386 DWORD dwOffsetHeader = 0;
2387 DWORD dwOffsetFileExtension = 0;
2388 DWORD dwFileSizeLow = 0;
2389 DWORD dwFileSizeHigh = 0;
2390 BYTE cDirectory = 0;
2391 int len;
2392 char achFile[MAX_PATH];
2393 LPSTR lpszUrlNameA = NULL;
2394 LPSTR lpszFileExtensionA = NULL;
2395 char *pchLocalFileName = 0;
2396 DWORD error;
2398 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2399 debugstr_w(lpszUrlName),
2400 debugstr_w(lpszLocalFileName),
2401 CacheEntryType,
2402 lpHeaderInfo,
2403 dwHeaderSize,
2404 debugstr_w(lpszFileExtension),
2405 debugstr_w(lpszOriginalUrl));
2407 if (lpszOriginalUrl)
2408 WARN(": lpszOriginalUrl ignored\n");
2410 if (lpszLocalFileName)
2412 HANDLE hFile;
2414 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2415 if (hFile == INVALID_HANDLE_VALUE)
2417 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2418 return FALSE;
2421 /* Get file size */
2422 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2423 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2425 ERR("couldn't get file size (error is %d)\n", GetLastError());
2426 CloseHandle(hFile);
2427 return FALSE;
2430 CloseHandle(hFile);
2433 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2434 if (error != ERROR_SUCCESS)
2436 SetLastError(error);
2437 return FALSE;
2440 error = URLCacheContainer_OpenIndex(pContainer);
2441 if (error != ERROR_SUCCESS)
2443 SetLastError(error);
2444 return FALSE;
2447 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2448 return FALSE;
2450 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2451 lpszUrlNameA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2452 if (!lpszUrlNameA)
2454 error = GetLastError();
2455 goto cleanup;
2457 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, lpszUrlNameA, len, NULL, NULL);
2459 if (lpszFileExtension)
2461 len = WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, NULL, 0, NULL, NULL);
2462 lpszFileExtensionA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2463 if (!lpszFileExtensionA)
2465 error = GetLastError();
2466 goto cleanup;
2468 WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, lpszFileExtensionA, len, NULL, NULL);
2471 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2473 FIXME("entry already in cache - don't know what to do!\n");
2475 * SetLastError(ERROR_FILE_NOT_FOUND);
2476 * return FALSE;
2478 goto cleanup;
2481 if (lpszLocalFileName)
2483 BOOL bFound = FALSE;
2485 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2487 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2488 error = ERROR_INVALID_PARAMETER;
2489 goto cleanup;
2492 /* skip container path prefix */
2493 lpszLocalFileName += lstrlenW(pContainer->path);
2495 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL);
2496 pchLocalFileName = achFile;
2498 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2500 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2502 bFound = TRUE;
2503 break;
2507 if (!bFound)
2509 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2510 error = ERROR_INVALID_PARAMETER;
2511 goto cleanup;
2514 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2517 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2518 if (lpszLocalFileName)
2520 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2521 dwOffsetLocalFileName = dwBytesNeeded;
2522 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2524 if (lpHeaderInfo)
2526 dwOffsetHeader = dwBytesNeeded;
2527 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2529 if (lpszFileExtensionA)
2531 dwOffsetFileExtension = dwBytesNeeded;
2532 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2535 /* round up to next block */
2536 if (dwBytesNeeded % BLOCKSIZE)
2538 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2539 dwBytesNeeded += BLOCKSIZE;
2542 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2544 ERR("no free entries\n");
2545 error = ERROR_DISK_FULL;
2546 goto cleanup;
2549 /* FindFirstFreeEntry fills in blocks used */
2550 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2551 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2552 pUrlEntry->CacheDir = cDirectory;
2553 pUrlEntry->CacheEntryType = CacheEntryType;
2554 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2555 pUrlEntry->dwExemptDelta = 0;
2556 pUrlEntry->dwHitRate = 0;
2557 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2558 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2559 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2560 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2561 pUrlEntry->dwSizeHigh = 0;
2562 pUrlEntry->dwSizeLow = dwFileSizeLow;
2563 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2564 pUrlEntry->dwUseCount = 0;
2565 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2566 pUrlEntry->LastModifiedTime = LastModifiedTime;
2567 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2568 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2569 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2570 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2572 /*** Unknowns ***/
2573 pUrlEntry->dwUnknown1 = 0;
2574 pUrlEntry->dwUnknown2 = 0;
2575 pUrlEntry->dwUnknown3 = 0x60;
2576 pUrlEntry->Unknown4 = 0;
2577 pUrlEntry->wUnknown5 = 0x1010;
2578 pUrlEntry->dwUnknown7 = 0;
2579 pUrlEntry->dwUnknown8 = 0;
2582 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2583 if (dwOffsetLocalFileName)
2584 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2585 if (dwOffsetHeader)
2586 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2587 if (dwOffsetFileExtension)
2588 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2590 error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA,
2591 (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader));
2592 if (error != ERROR_SUCCESS)
2593 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2595 cleanup:
2596 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2597 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2598 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2600 if (error == ERROR_SUCCESS)
2601 return TRUE;
2602 else
2604 SetLastError(error);
2605 return FALSE;
2609 /***********************************************************************
2610 * CommitUrlCacheEntryA (WININET.@)
2613 BOOL WINAPI CommitUrlCacheEntryA(
2614 IN LPCSTR lpszUrlName,
2615 IN LPCSTR lpszLocalFileName,
2616 IN FILETIME ExpireTime,
2617 IN FILETIME LastModifiedTime,
2618 IN DWORD CacheEntryType,
2619 IN LPBYTE lpHeaderInfo,
2620 IN DWORD dwHeaderSize,
2621 IN LPCSTR lpszFileExtension,
2622 IN LPCSTR lpszOriginalUrl
2625 DWORD len;
2626 WCHAR *url_name = NULL;
2627 WCHAR *local_file_name = NULL;
2628 WCHAR *original_url = NULL;
2629 WCHAR *file_extension = NULL;
2630 BOOL bSuccess = FALSE;
2632 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2633 debugstr_a(lpszUrlName),
2634 debugstr_a(lpszLocalFileName),
2635 CacheEntryType,
2636 lpHeaderInfo,
2637 dwHeaderSize,
2638 debugstr_a(lpszFileExtension),
2639 debugstr_a(lpszOriginalUrl));
2641 len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0);
2642 url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2643 if (!url_name)
2644 goto cleanup;
2645 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2647 if (lpszLocalFileName)
2649 len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0);
2650 local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2651 if (!local_file_name)
2652 goto cleanup;
2653 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2655 if (lpszFileExtension)
2657 len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0);
2658 file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2659 if (!file_extension)
2660 goto cleanup;
2661 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2663 if (lpszOriginalUrl)
2665 len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0);
2666 original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2667 if (!original_url)
2668 goto cleanup;
2669 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2672 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2673 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2674 file_extension, original_url);
2676 cleanup:
2677 HeapFree(GetProcessHeap(), 0, original_url);
2678 HeapFree(GetProcessHeap(), 0, file_extension);
2679 HeapFree(GetProcessHeap(), 0, local_file_name);
2680 HeapFree(GetProcessHeap(), 0, url_name);
2682 return bSuccess;
2685 /***********************************************************************
2686 * CommitUrlCacheEntryW (WININET.@)
2689 BOOL WINAPI CommitUrlCacheEntryW(
2690 IN LPCWSTR lpszUrlName,
2691 IN LPCWSTR lpszLocalFileName,
2692 IN FILETIME ExpireTime,
2693 IN FILETIME LastModifiedTime,
2694 IN DWORD CacheEntryType,
2695 IN LPWSTR lpHeaderInfo,
2696 IN DWORD dwHeaderSize,
2697 IN LPCWSTR lpszFileExtension,
2698 IN LPCWSTR lpszOriginalUrl
2701 DWORD dwError = 0;
2702 BOOL bSuccess = FALSE;
2703 DWORD len = 0;
2704 CHAR *header_info = NULL;
2706 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2707 debugstr_w(lpszUrlName),
2708 debugstr_w(lpszLocalFileName),
2709 CacheEntryType,
2710 lpHeaderInfo,
2711 dwHeaderSize,
2712 debugstr_w(lpszFileExtension),
2713 debugstr_w(lpszOriginalUrl));
2715 if (!lpHeaderInfo ||
2716 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2717 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2719 if (header_info)
2720 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2721 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2722 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2724 bSuccess = TRUE;
2726 else
2728 dwError = GetLastError();
2730 if (header_info)
2732 HeapFree(GetProcessHeap(), 0, header_info);
2733 if (!bSuccess)
2734 SetLastError(dwError);
2737 return bSuccess;
2740 /***********************************************************************
2741 * ReadUrlCacheEntryStream (WININET.@)
2744 BOOL WINAPI ReadUrlCacheEntryStream(
2745 IN HANDLE hUrlCacheStream,
2746 IN DWORD dwLocation,
2747 IN OUT LPVOID lpBuffer,
2748 IN OUT LPDWORD lpdwLen,
2749 IN DWORD dwReserved
2752 /* Get handle to file from 'stream' */
2753 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2755 if (dwReserved != 0)
2757 ERR("dwReserved != 0\n");
2758 SetLastError(ERROR_INVALID_PARAMETER);
2759 return FALSE;
2762 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2764 SetLastError(ERROR_INVALID_HANDLE);
2765 return FALSE;
2768 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2769 return FALSE;
2770 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2773 /***********************************************************************
2774 * RetrieveUrlCacheEntryStreamA (WININET.@)
2777 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2778 IN LPCSTR lpszUrlName,
2779 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2780 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2781 IN BOOL fRandomRead,
2782 IN DWORD dwReserved
2785 /* NOTE: this is not the same as the way that the native
2786 * version allocates 'stream' handles. I did it this way
2787 * as it is much easier and no applications should depend
2788 * on this behaviour. (Native version appears to allocate
2789 * indices into a table)
2791 STREAM_HANDLE * pStream;
2792 HANDLE hFile;
2794 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2795 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2797 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2798 lpCacheEntryInfo,
2799 lpdwCacheEntryInfoBufferSize,
2800 dwReserved))
2802 return NULL;
2805 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2806 GENERIC_READ,
2807 FILE_SHARE_READ,
2808 NULL,
2809 OPEN_EXISTING,
2810 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2811 NULL);
2812 if (hFile == INVALID_HANDLE_VALUE)
2813 return FALSE;
2815 /* allocate handle storage space */
2816 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2817 if (!pStream)
2819 CloseHandle(hFile);
2820 SetLastError(ERROR_OUTOFMEMORY);
2821 return FALSE;
2824 pStream->hFile = hFile;
2825 strcpy(pStream->lpszUrl, lpszUrlName);
2826 return pStream;
2829 /***********************************************************************
2830 * RetrieveUrlCacheEntryStreamW (WININET.@)
2833 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2834 IN LPCWSTR lpszUrlName,
2835 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2836 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2837 IN BOOL fRandomRead,
2838 IN DWORD dwReserved
2841 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2842 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2843 return NULL;
2846 /***********************************************************************
2847 * UnlockUrlCacheEntryStream (WININET.@)
2850 BOOL WINAPI UnlockUrlCacheEntryStream(
2851 IN HANDLE hUrlCacheStream,
2852 IN DWORD dwReserved
2855 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2857 if (dwReserved != 0)
2859 ERR("dwReserved != 0\n");
2860 SetLastError(ERROR_INVALID_PARAMETER);
2861 return FALSE;
2864 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2866 SetLastError(ERROR_INVALID_HANDLE);
2867 return FALSE;
2870 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2871 return FALSE;
2873 /* close file handle */
2874 CloseHandle(pStream->hFile);
2876 /* free allocated space */
2877 HeapFree(GetProcessHeap(), 0, pStream);
2879 return TRUE;
2883 /***********************************************************************
2884 * DeleteUrlCacheEntryA (WININET.@)
2887 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2889 URLCACHECONTAINER * pContainer;
2890 LPURLCACHE_HEADER pHeader;
2891 struct _HASH_ENTRY * pHashEntry;
2892 CACHEFILE_ENTRY * pEntry;
2893 DWORD error;
2895 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2897 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2898 if (error != ERROR_SUCCESS)
2900 SetLastError(error);
2901 return FALSE;
2904 error = URLCacheContainer_OpenIndex(pContainer);
2905 if (error != ERROR_SUCCESS)
2907 SetLastError(error);
2908 return FALSE;
2911 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2912 return FALSE;
2914 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2916 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2917 TRACE("entry %s not found!\n", lpszUrlName);
2918 SetLastError(ERROR_FILE_NOT_FOUND);
2919 return FALSE;
2922 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2923 URLCache_DeleteEntry(pHeader, pEntry);
2925 URLCache_DeleteEntryFromHash(pHashEntry);
2927 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2929 return TRUE;
2932 /***********************************************************************
2933 * DeleteUrlCacheEntryW (WININET.@)
2936 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2938 URLCACHECONTAINER * pContainer;
2939 LPURLCACHE_HEADER pHeader;
2940 struct _HASH_ENTRY * pHashEntry;
2941 CACHEFILE_ENTRY * pEntry;
2942 LPSTR urlA;
2943 int url_len;
2944 DWORD error;
2946 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2948 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2949 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
2950 if (!urlA)
2952 SetLastError(ERROR_OUTOFMEMORY);
2953 return FALSE;
2955 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, urlA, url_len, NULL, NULL);
2957 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2958 if (error != ERROR_SUCCESS)
2960 HeapFree(GetProcessHeap(), 0, urlA);
2961 SetLastError(error);
2962 return FALSE;
2965 error = URLCacheContainer_OpenIndex(pContainer);
2966 if (error != ERROR_SUCCESS)
2968 HeapFree(GetProcessHeap(), 0, urlA);
2969 SetLastError(error);
2970 return FALSE;
2973 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2975 HeapFree(GetProcessHeap(), 0, urlA);
2976 return FALSE;
2979 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
2981 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2982 TRACE("entry %s not found!\n", debugstr_a(urlA));
2983 HeapFree(GetProcessHeap(), 0, urlA);
2984 SetLastError(ERROR_FILE_NOT_FOUND);
2985 return FALSE;
2988 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2989 URLCache_DeleteEntry(pHeader, pEntry);
2991 URLCache_DeleteEntryFromHash(pHashEntry);
2993 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2995 HeapFree(GetProcessHeap(), 0, urlA);
2996 return TRUE;
2999 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
3001 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3002 return TRUE;
3005 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
3007 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3008 return TRUE;
3011 /***********************************************************************
3012 * CreateCacheContainerA (WININET.@)
3014 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3015 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3017 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3018 d1, d2, d3, d4, d5, d6, d7, d8);
3019 return TRUE;
3022 /***********************************************************************
3023 * CreateCacheContainerW (WININET.@)
3025 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3026 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3028 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3029 d1, d2, d3, d4, d5, d6, d7, d8);
3030 return TRUE;
3033 /***********************************************************************
3034 * FindFirstUrlCacheContainerA (WININET.@)
3036 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3038 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3039 return NULL;
3042 /***********************************************************************
3043 * FindFirstUrlCacheContainerW (WININET.@)
3045 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3047 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3048 return NULL;
3051 /***********************************************************************
3052 * FindNextUrlCacheContainerA (WININET.@)
3054 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
3056 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3057 return FALSE;
3060 /***********************************************************************
3061 * FindNextUrlCacheContainerW (WININET.@)
3063 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
3065 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3066 return FALSE;
3069 HANDLE WINAPI FindFirstUrlCacheEntryExA(
3070 LPCSTR lpszUrlSearchPattern,
3071 DWORD dwFlags,
3072 DWORD dwFilter,
3073 GROUPID GroupId,
3074 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3075 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3076 LPVOID lpReserved,
3077 LPDWORD pcbReserved2,
3078 LPVOID lpReserved3
3081 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
3082 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3083 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3084 SetLastError(ERROR_FILE_NOT_FOUND);
3085 return NULL;
3088 HANDLE WINAPI FindFirstUrlCacheEntryExW(
3089 LPCWSTR lpszUrlSearchPattern,
3090 DWORD dwFlags,
3091 DWORD dwFilter,
3092 GROUPID GroupId,
3093 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3094 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3095 LPVOID lpReserved,
3096 LPDWORD pcbReserved2,
3097 LPVOID lpReserved3
3100 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
3101 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3102 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3103 SetLastError(ERROR_FILE_NOT_FOUND);
3104 return NULL;
3107 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3109 typedef struct URLCacheFindEntryHandle
3111 DWORD dwMagic;
3112 LPWSTR lpszUrlSearchPattern;
3113 DWORD dwContainerIndex;
3114 DWORD dwHashTableIndex;
3115 DWORD dwHashEntryIndex;
3116 } URLCacheFindEntryHandle;
3118 /***********************************************************************
3119 * FindFirstUrlCacheEntryA (WININET.@)
3122 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
3123 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3125 URLCacheFindEntryHandle *pEntryHandle;
3127 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3129 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3130 if (!pEntryHandle)
3131 return NULL;
3133 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3134 if (lpszUrlSearchPattern)
3136 int len = MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, NULL, 0);
3137 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3138 if (!pEntryHandle->lpszUrlSearchPattern)
3140 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3141 return NULL;
3143 MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, pEntryHandle->lpszUrlSearchPattern, len);
3145 else
3146 pEntryHandle->lpszUrlSearchPattern = NULL;
3147 pEntryHandle->dwContainerIndex = 0;
3148 pEntryHandle->dwHashTableIndex = 0;
3149 pEntryHandle->dwHashEntryIndex = 0;
3151 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3153 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3154 return NULL;
3156 return pEntryHandle;
3159 /***********************************************************************
3160 * FindFirstUrlCacheEntryW (WININET.@)
3163 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3164 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3166 URLCacheFindEntryHandle *pEntryHandle;
3168 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3170 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3171 if (!pEntryHandle)
3172 return NULL;
3174 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3175 if (lpszUrlSearchPattern)
3177 int len = strlenW(lpszUrlSearchPattern);
3178 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
3179 if (!pEntryHandle->lpszUrlSearchPattern)
3181 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3182 return NULL;
3184 memcpy(pEntryHandle->lpszUrlSearchPattern, lpszUrlSearchPattern, (len + 1) * sizeof(WCHAR));
3186 else
3187 pEntryHandle->lpszUrlSearchPattern = NULL;
3188 pEntryHandle->dwContainerIndex = 0;
3189 pEntryHandle->dwHashTableIndex = 0;
3190 pEntryHandle->dwHashEntryIndex = 0;
3192 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3194 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3195 return NULL;
3197 return pEntryHandle;
3200 /***********************************************************************
3201 * FindNextUrlCacheEntryA (WININET.@)
3203 BOOL WINAPI FindNextUrlCacheEntryA(
3204 HANDLE hEnumHandle,
3205 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3206 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3208 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3209 URLCACHECONTAINER * pContainer;
3211 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3213 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3215 SetLastError(ERROR_INVALID_HANDLE);
3216 return FALSE;
3219 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3220 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3222 LPURLCACHE_HEADER pHeader;
3223 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3224 DWORD error;
3226 error = URLCacheContainer_OpenIndex(pContainer);
3227 if (error != ERROR_SUCCESS)
3229 SetLastError(error);
3230 return FALSE;
3233 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3234 return FALSE;
3236 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3237 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3239 const struct _HASH_ENTRY *pHashEntry = NULL;
3240 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3241 pEntryHandle->dwHashEntryIndex++)
3243 const URL_CACHEFILE_ENTRY *pUrlEntry;
3244 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3246 if (pEntry->dwSignature != URL_SIGNATURE)
3247 continue;
3249 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3250 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3251 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3253 error = URLCache_CopyEntry(
3254 pContainer,
3255 pHeader,
3256 lpNextCacheEntryInfo,
3257 lpdwNextCacheEntryInfoBufferSize,
3258 pUrlEntry,
3259 FALSE /* not UNICODE */);
3260 if (error != ERROR_SUCCESS)
3262 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3263 SetLastError(error);
3264 return FALSE;
3266 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
3268 /* increment the current index so that next time the function
3269 * is called the next entry is returned */
3270 pEntryHandle->dwHashEntryIndex++;
3271 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3272 return TRUE;
3276 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3279 SetLastError(ERROR_NO_MORE_ITEMS);
3280 return FALSE;
3283 /***********************************************************************
3284 * FindNextUrlCacheEntryW (WININET.@)
3286 BOOL WINAPI FindNextUrlCacheEntryW(
3287 HANDLE hEnumHandle,
3288 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3289 LPDWORD lpdwNextCacheEntryInfoBufferSize
3292 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3293 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3294 return FALSE;
3297 /***********************************************************************
3298 * FindCloseUrlCache (WININET.@)
3300 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3302 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3304 TRACE("(%p)\n", hEnumHandle);
3306 if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3308 SetLastError(ERROR_INVALID_HANDLE);
3309 return FALSE;
3312 pEntryHandle->dwMagic = 0;
3313 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3314 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3316 return TRUE;
3319 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3320 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3322 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3323 dwSearchCondition, lpGroupId, lpReserved);
3324 return NULL;
3327 BOOL WINAPI FindNextUrlCacheEntryExA(
3328 HANDLE hEnumHandle,
3329 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3330 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3331 LPVOID lpReserved,
3332 LPDWORD pcbReserved2,
3333 LPVOID lpReserved3
3336 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3337 lpReserved, pcbReserved2, lpReserved3);
3338 return FALSE;
3341 BOOL WINAPI FindNextUrlCacheEntryExW(
3342 HANDLE hEnumHandle,
3343 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3344 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3345 LPVOID lpReserved,
3346 LPDWORD pcbReserved2,
3347 LPVOID lpReserved3
3350 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3351 lpReserved, pcbReserved2, lpReserved3);
3352 return FALSE;
3355 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3357 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3358 return FALSE;
3361 /***********************************************************************
3362 * CreateUrlCacheGroup (WININET.@)
3365 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3367 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3368 return FALSE;
3371 /***********************************************************************
3372 * DeleteUrlCacheGroup (WININET.@)
3375 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3377 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3378 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3379 return FALSE;
3382 /***********************************************************************
3383 * SetUrlCacheEntryGroupA (WININET.@)
3386 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3387 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3388 LPVOID lpReserved)
3390 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3391 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3392 pbGroupAttributes, cbGroupAttributes, lpReserved);
3393 SetLastError(ERROR_FILE_NOT_FOUND);
3394 return FALSE;
3397 /***********************************************************************
3398 * SetUrlCacheEntryGroupW (WININET.@)
3401 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3402 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3403 LPVOID lpReserved)
3405 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3406 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3407 pbGroupAttributes, cbGroupAttributes, lpReserved);
3408 SetLastError(ERROR_FILE_NOT_FOUND);
3409 return FALSE;
3412 /***********************************************************************
3413 * GetUrlCacheConfigInfoW (WININET.@)
3415 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3417 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3418 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3419 return FALSE;
3422 /***********************************************************************
3423 * GetUrlCacheConfigInfoA (WININET.@)
3425 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3427 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3429 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3430 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3431 return FALSE;
3434 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3435 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3436 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3438 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3439 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3440 lpdwGroupInfo, lpReserved);
3441 return FALSE;
3444 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3445 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3446 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3448 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3449 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3450 lpdwGroupInfo, lpReserved);
3451 return FALSE;
3454 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3455 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3457 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3458 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3459 return TRUE;
3462 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3463 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3465 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3466 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3467 return TRUE;
3470 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3472 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3473 return TRUE;
3476 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3478 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3479 return TRUE;
3482 /***********************************************************************
3483 * DeleteIE3Cache (WININET.@)
3485 * Deletes the files used by the IE3 URL caching system.
3487 * PARAMS
3488 * hWnd [I] A dummy window.
3489 * hInst [I] Instance of process calling the function.
3490 * lpszCmdLine [I] Options used by function.
3491 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3493 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3495 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3496 return 0;
3499 /***********************************************************************
3500 * IsUrlCacheEntryExpiredA (WININET.@)
3502 * PARAMS
3503 * url [I] Url
3504 * dwFlags [I] Unknown
3505 * pftLastModified [O] Last modified time
3507 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3509 LPURLCACHE_HEADER pHeader;
3510 struct _HASH_ENTRY * pHashEntry;
3511 const CACHEFILE_ENTRY * pEntry;
3512 const URL_CACHEFILE_ENTRY * pUrlEntry;
3513 URLCACHECONTAINER * pContainer;
3514 DWORD error;
3516 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3518 error = URLCacheContainers_FindContainerA(url, &pContainer);
3519 if (error != ERROR_SUCCESS)
3521 SetLastError(error);
3522 return FALSE;
3525 error = URLCacheContainer_OpenIndex(pContainer);
3526 if (error != ERROR_SUCCESS)
3528 SetLastError(error);
3529 return FALSE;
3532 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3533 return FALSE;
3535 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3537 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3538 TRACE("entry %s not found!\n", url);
3539 SetLastError(ERROR_FILE_NOT_FOUND);
3540 return FALSE;
3543 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3544 if (pEntry->dwSignature != URL_SIGNATURE)
3546 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3547 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3548 SetLastError(ERROR_FILE_NOT_FOUND);
3549 return FALSE;
3552 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3554 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3556 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3558 return TRUE;
3561 /***********************************************************************
3562 * IsUrlCacheEntryExpiredW (WININET.@)
3564 * PARAMS
3565 * url [I] Url
3566 * dwFlags [I] Unknown
3567 * pftLastModified [O] Last modified time
3569 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3571 LPURLCACHE_HEADER pHeader;
3572 struct _HASH_ENTRY * pHashEntry;
3573 const CACHEFILE_ENTRY * pEntry;
3574 const URL_CACHEFILE_ENTRY * pUrlEntry;
3575 URLCACHECONTAINER * pContainer;
3576 DWORD error;
3578 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3580 error = URLCacheContainers_FindContainerW(url, &pContainer);
3581 if (error != ERROR_SUCCESS)
3583 SetLastError(error);
3584 return FALSE;
3587 error = URLCacheContainer_OpenIndex(pContainer);
3588 if (error != ERROR_SUCCESS)
3590 SetLastError(error);
3591 return FALSE;
3594 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3595 return FALSE;
3597 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3599 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3600 TRACE("entry %s not found!\n", debugstr_w(url));
3601 SetLastError(ERROR_FILE_NOT_FOUND);
3602 return FALSE;
3605 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3606 if (pEntry->dwSignature != URL_SIGNATURE)
3608 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3609 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3610 SetLastError(ERROR_FILE_NOT_FOUND);
3611 return FALSE;
3614 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3616 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3618 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3620 return TRUE;
3623 /***********************************************************************
3624 * GetDiskInfoA (WININET.@)
3626 DWORD WINAPI GetDiskInfoA(void *p0, void *p1, void *p2, void *p3)
3628 FIXME("(%p, %p, %p, %p)\n", p0, p1, p2, p3);
3629 return 0;
3632 /***********************************************************************
3633 * RegisterUrlCacheNotification (WININET.@)
3635 DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
3637 FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f);
3638 return 0;