push 22b3e00525a9a3743634eb8f21ffe1bf98bf885e
[wine/hacks.git] / dlls / wininet / urlcache.c
blob5e1541da5b17022688564ec5aa473d9496a39bf2
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 UnmapViewOfFile( pHeader );
696 URLCacheContainer_CloseIndex(pContainer);
697 error = URLCacheContainer_OpenIndex(pContainer);
698 if (error != ERROR_SUCCESS)
700 ReleaseMutex(pContainer->hMutex);
701 SetLastError(error);
702 return NULL;
704 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
706 if (!pIndexData)
708 ReleaseMutex(pContainer->hMutex);
709 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
710 return NULL;
712 pHeader = (URLCACHE_HEADER *)pIndexData;
715 TRACE("Signature: %s, file size: %d bytes\n", pHeader->szSignature, pHeader->dwFileSize);
717 for (index = 0; index < pHeader->DirectoryCount; index++)
719 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
722 return pHeader;
725 /***********************************************************************
726 * URLCacheContainer_UnlockIndex (Internal)
729 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
731 /* release mutex */
732 ReleaseMutex(pContainer->hMutex);
733 return UnmapViewOfFile(pHeader);
737 #ifndef CHAR_BIT
738 #define CHAR_BIT (8 * sizeof(CHAR))
739 #endif
741 /***********************************************************************
742 * URLCache_Allocation_BlockIsFree (Internal)
744 * Is the specified block number free?
746 * RETURNS
747 * zero if free
748 * non-zero otherwise
751 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
753 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
754 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
757 /***********************************************************************
758 * URLCache_Allocation_BlockFree (Internal)
760 * Marks the specified block as free
762 * RETURNS
763 * nothing
766 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
768 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
769 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
772 /***********************************************************************
773 * URLCache_Allocation_BlockAllocate (Internal)
775 * Marks the specified block as allocated
777 * RETURNS
778 * nothing
781 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
783 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
784 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
787 /***********************************************************************
788 * URLCache_FindFirstFreeEntry (Internal)
790 * Finds and allocates the first block of free space big enough and
791 * sets ppEntry to point to it.
793 * RETURNS
794 * TRUE if it had enough space
795 * FALSE if it couldn't find enough space
798 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
800 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
801 DWORD dwBlockNumber;
802 DWORD dwFreeCounter;
803 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
805 for (dwFreeCounter = 0;
806 dwFreeCounter < dwBlocksNeeded &&
807 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
808 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
809 dwFreeCounter++)
810 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
812 if (dwFreeCounter == dwBlocksNeeded)
814 DWORD index;
815 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
816 for (index = 0; index < dwBlocksNeeded; index++)
817 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
818 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
819 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
820 return TRUE;
823 FIXME("Grow file\n");
824 return FALSE;
827 /***********************************************************************
828 * URLCache_DeleteEntry (Internal)
830 * Deletes the specified entry and frees the space allocated to it
832 * RETURNS
833 * TRUE if it succeeded
834 * FALSE if it failed
837 static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, CACHEFILE_ENTRY * pEntry)
839 DWORD dwStartBlock;
840 DWORD dwBlock;
841 BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
843 /* update allocation table */
844 dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE;
845 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
846 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
848 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
849 return TRUE;
852 /***********************************************************************
853 * URLCache_LocalFileNameToPathW (Internal)
855 * Copies the full path to the specified buffer given the local file
856 * name and the index of the directory it is in. Always sets value in
857 * lpBufferSize to the required buffer size (in bytes).
859 * RETURNS
860 * TRUE if the buffer was big enough
861 * FALSE if the buffer was too small
864 static BOOL URLCache_LocalFileNameToPathW(
865 const URLCACHECONTAINER * pContainer,
866 LPCURLCACHE_HEADER pHeader,
867 LPCSTR szLocalFileName,
868 BYTE Directory,
869 LPWSTR wszPath,
870 LPLONG lpBufferSize)
872 LONG nRequired;
873 int path_len = strlenW(pContainer->path);
874 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
875 if (Directory >= pHeader->DirectoryCount)
877 *lpBufferSize = 0;
878 return FALSE;
881 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
882 if (nRequired < *lpBufferSize)
884 int dir_len;
886 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
887 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
888 wszPath[dir_len + path_len] = '\\';
889 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
890 *lpBufferSize = nRequired;
891 return TRUE;
893 *lpBufferSize = nRequired;
894 return FALSE;
897 /***********************************************************************
898 * URLCache_LocalFileNameToPathA (Internal)
900 * Copies the full path to the specified buffer given the local file
901 * name and the index of the directory it is in. Always sets value in
902 * lpBufferSize to the required buffer size.
904 * RETURNS
905 * TRUE if the buffer was big enough
906 * FALSE if the buffer was too small
909 static BOOL URLCache_LocalFileNameToPathA(
910 const URLCACHECONTAINER * pContainer,
911 LPCURLCACHE_HEADER pHeader,
912 LPCSTR szLocalFileName,
913 BYTE Directory,
914 LPSTR szPath,
915 LPLONG lpBufferSize)
917 LONG nRequired;
918 int path_len, file_name_len, dir_len;
920 if (Directory >= pHeader->DirectoryCount)
922 *lpBufferSize = 0;
923 return FALSE;
926 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL) - 1;
927 file_name_len = strlen(szLocalFileName) + 1 /* for nul-terminator */;
928 dir_len = DIR_LENGTH;
930 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(char);
931 if (nRequired < *lpBufferSize)
933 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, path_len, NULL, NULL);
934 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
935 szPath[path_len + dir_len] = '\\';
936 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
937 *lpBufferSize = nRequired;
938 return TRUE;
940 *lpBufferSize = nRequired;
941 return FALSE;
944 /***********************************************************************
945 * URLCache_CopyEntry (Internal)
947 * Copies an entry from the cache index file to the Win32 structure
949 * RETURNS
950 * ERROR_SUCCESS if the buffer was big enough
951 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
954 static DWORD URLCache_CopyEntry(
955 URLCACHECONTAINER * pContainer,
956 LPCURLCACHE_HEADER pHeader,
957 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
958 LPDWORD lpdwBufferSize,
959 const URL_CACHEFILE_ENTRY * pUrlEntry,
960 BOOL bUnicode)
962 int lenUrl;
963 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
965 if (*lpdwBufferSize >= dwRequiredSize)
967 lpCacheEntryInfo->lpHeaderInfo = NULL;
968 lpCacheEntryInfo->lpszFileExtension = NULL;
969 lpCacheEntryInfo->lpszLocalFileName = NULL;
970 lpCacheEntryInfo->lpszSourceUrlName = NULL;
971 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
972 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
973 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
974 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
975 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
976 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
977 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
978 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
979 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
980 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
981 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
982 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
983 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
984 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
987 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
988 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
989 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
990 if (bUnicode)
991 lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0);
992 else
993 lenUrl = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
994 dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
996 /* FIXME: is source url optional? */
997 if (*lpdwBufferSize >= dwRequiredSize)
999 DWORD lenUrlBytes = (lenUrl+1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
1001 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrlBytes;
1002 if (bUnicode)
1003 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
1004 else
1005 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lenUrlBytes);
1008 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1009 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1010 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1012 if (pUrlEntry->dwOffsetLocalName)
1014 LONG nLocalFilePathSize;
1015 LPSTR lpszLocalFileName;
1016 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
1017 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
1018 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
1019 (!bUnicode && URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize)))
1021 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
1023 dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ;
1025 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1026 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1027 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1029 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
1031 if (*lpdwBufferSize >= dwRequiredSize)
1033 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
1034 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
1035 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
1037 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1038 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1039 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1041 if (pUrlEntry->dwOffsetFileExtension)
1043 int lenExtension;
1045 if (bUnicode)
1046 lenExtension = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, NULL, 0);
1047 else
1048 lenExtension = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension) + 1;
1049 dwRequiredSize += lenExtension * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
1051 if (*lpdwBufferSize >= dwRequiredSize)
1053 lpCacheEntryInfo->lpszFileExtension = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenExtension;
1054 if (bUnicode)
1055 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenExtension);
1056 else
1057 memcpy(lpCacheEntryInfo->lpszFileExtension, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, lenExtension * sizeof(CHAR));
1060 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1061 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1062 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1065 if (dwRequiredSize > *lpdwBufferSize)
1067 *lpdwBufferSize = dwRequiredSize;
1068 return ERROR_INSUFFICIENT_BUFFER;
1070 *lpdwBufferSize = dwRequiredSize;
1071 return ERROR_SUCCESS;
1075 /***********************************************************************
1076 * URLCache_SetEntryInfo (Internal)
1078 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1079 * according to the flags set by dwFieldControl.
1081 * RETURNS
1082 * ERROR_SUCCESS if the buffer was big enough
1083 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1086 static DWORD URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1088 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1089 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1090 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1091 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1092 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1093 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1094 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1095 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1096 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1097 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1098 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1099 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1100 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1101 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1102 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1103 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1105 return ERROR_SUCCESS;
1108 /***********************************************************************
1109 * URLCache_HashKey (Internal)
1111 * Returns the hash key for a given string
1113 * RETURNS
1114 * hash key for the string
1117 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1119 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1120 * but the algorithm and result are not the same!
1122 static const unsigned char lookupTable[256] =
1124 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1125 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1126 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1127 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1128 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1129 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1130 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1131 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1132 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1133 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1134 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1135 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1136 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1137 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1138 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1139 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1140 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1141 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1142 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1143 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1144 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1145 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1146 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1147 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1148 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1149 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1150 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1151 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1152 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1153 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1154 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1155 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1157 BYTE key[4];
1158 DWORD i;
1160 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1161 key[i] = lookupTable[i];
1163 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
1165 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1166 key[i] = lookupTable[*lpszKey ^ key[i]];
1169 return *(DWORD *)key;
1172 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
1174 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
1177 static inline BOOL URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY *pHashEntry)
1179 /* check pHashEntry located within acceptable bounds in the URL cache mapping */
1180 return ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) &&
1181 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1184 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1186 /* structure of hash table:
1187 * 448 entries divided into 64 blocks
1188 * each block therefore contains a chain of 7 key/offset pairs
1189 * how position in table is calculated:
1190 * 1. the url is hashed in helper function
1191 * 2. the key % 64 * 8 is the offset
1192 * 3. the key in the hash table is the hash key aligned to 64
1194 * note:
1195 * there can be multiple hash tables in the file and the offset to
1196 * the next one is stored in the header of the hash table
1198 DWORD key = URLCache_HashKey(lpszUrl);
1199 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1200 HASH_CACHEFILE_ENTRY * pHashEntry;
1201 DWORD dwHashTableNumber = 0;
1203 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1205 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1206 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1207 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1209 int i;
1210 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1212 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1213 continue;
1215 /* make sure that it is in fact a hash entry */
1216 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1218 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1219 continue;
1222 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1224 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1225 if (key == (pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
1227 /* FIXME: we should make sure that this is the right element
1228 * before returning and claiming that it is. We can do this
1229 * by doing a simple compare between the URL we were given
1230 * and the URL stored in the entry. However, this assumes
1231 * we know the format of all the entries stored in the
1232 * hash table */
1233 *ppHashEntry = pHashElement;
1234 return TRUE;
1238 return FALSE;
1241 static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1243 LPSTR urlA;
1244 int url_len;
1245 BOOL ret;
1247 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1248 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1249 if (!urlA)
1251 SetLastError(ERROR_OUTOFMEMORY);
1252 return FALSE;
1254 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, urlA, url_len, NULL, NULL);
1255 ret = URLCache_FindHash(pHeader, urlA, ppHashEntry);
1256 HeapFree(GetProcessHeap(), 0, urlA);
1257 return ret;
1260 /***********************************************************************
1261 * URLCache_HashEntrySetUse (Internal)
1263 * Searches all the hash tables in the index for the given URL and
1264 * sets the use count (stored or'ed with key)
1266 * RETURNS
1267 * TRUE if the entry was found
1268 * FALSE if the entry could not be found
1271 static BOOL URLCache_HashEntrySetUse(struct _HASH_ENTRY * pHashEntry, DWORD dwUseCount)
1273 pHashEntry->dwHashKey = dwUseCount | (pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1274 return TRUE;
1277 /***********************************************************************
1278 * URLCache_DeleteEntryFromHash (Internal)
1280 * Searches all the hash tables in the index for the given URL and
1281 * then if found deletes the entry.
1283 * RETURNS
1284 * TRUE if the entry was found
1285 * FALSE if the entry could not be found
1288 static BOOL URLCache_DeleteEntryFromHash(struct _HASH_ENTRY * pHashEntry)
1290 pHashEntry->dwHashKey = HASHTABLE_FREE;
1291 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1292 return TRUE;
1295 /***********************************************************************
1296 * URLCache_AddEntryToHash (Internal)
1298 * Searches all the hash tables for a free slot based on the offset
1299 * generated from the hash key. If a free slot is found, the offset and
1300 * key are entered into the hash table.
1302 * RETURNS
1303 * ERROR_SUCCESS if the entry was added
1304 * Any other Win32 error code if the entry could not be added
1307 static DWORD URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1309 /* see URLCache_FindEntryInHash for structure of hash tables */
1311 DWORD key = URLCache_HashKey(lpszUrl);
1312 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1313 HASH_CACHEFILE_ENTRY * pHashEntry;
1314 DWORD dwHashTableNumber = 0;
1315 DWORD error;
1317 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1319 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1320 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1321 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1323 int i;
1324 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1326 ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1327 break;
1329 /* make sure that it is in fact a hash entry */
1330 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1332 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1333 break;
1336 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1338 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1339 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1341 pHashElement->dwHashKey = key;
1342 pHashElement->dwOffsetEntry = dwOffsetEntry;
1343 return ERROR_SUCCESS;
1347 error = URLCache_CreateHashTable(pHeader, pHashEntry, &pHashEntry);
1348 if (error != ERROR_SUCCESS)
1349 return error;
1351 pHashEntry->HashTable[offset].dwHashKey = key;
1352 pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry;
1353 return ERROR_SUCCESS;
1356 /***********************************************************************
1357 * URLCache_CreateHashTable (Internal)
1359 * Creates a new hash table in free space and adds it to the chain of existing
1360 * hash tables.
1362 * RETURNS
1363 * ERROR_SUCCESS if the hash table was created
1364 * ERROR_DISK_FULL if the hash table could not be created
1367 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash)
1369 DWORD dwOffset;
1370 int i;
1372 if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)ppHash))
1374 FIXME("no free space for hash table\n");
1375 return ERROR_DISK_FULL;
1378 dwOffset = (BYTE *)*ppHash - (BYTE *)pHeader;
1380 if (pPrevHash)
1381 pPrevHash->dwAddressNext = dwOffset;
1382 else
1383 pHeader->dwOffsetFirstHashTable = dwOffset;
1384 (*ppHash)->CacheFileEntry.dwSignature = HASH_SIGNATURE;
1385 (*ppHash)->CacheFileEntry.dwBlocksUsed = 0x20;
1386 (*ppHash)->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0;
1387 for (i = 0; i < HASHTABLE_SIZE; i++)
1389 (*ppHash)->HashTable[i].dwOffsetEntry = 0;
1390 (*ppHash)->HashTable[i].dwHashKey = HASHTABLE_FREE;
1392 return ERROR_SUCCESS;
1395 /***********************************************************************
1396 * URLCache_EnumHashTables (Internal)
1398 * Enumerates the hash tables in a container.
1400 * RETURNS
1401 * TRUE if an entry was found
1402 * FALSE if there are no more tables to enumerate.
1405 static BOOL URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader, DWORD *pdwHashTableNumber, HASH_CACHEFILE_ENTRY ** ppHashEntry)
1407 for (*ppHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1408 URLCache_IsHashEntryValid(pHeader, *ppHashEntry);
1409 *ppHashEntry = URLCache_HashEntryFromOffset(pHeader, (*ppHashEntry)->dwAddressNext))
1411 TRACE("looking at hash table number %d\n", (*ppHashEntry)->dwHashTableNumber);
1412 if ((*ppHashEntry)->dwHashTableNumber != *pdwHashTableNumber)
1413 continue;
1414 /* make sure that it is in fact a hash entry */
1415 if ((*ppHashEntry)->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1417 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&(*ppHashEntry)->CacheFileEntry.dwSignature);
1418 (*pdwHashTableNumber)++;
1419 continue;
1422 TRACE("hash table number %d found\n", *pdwHashTableNumber);
1423 return TRUE;
1425 return FALSE;
1428 /***********************************************************************
1429 * URLCache_EnumHashTableEntries (Internal)
1431 * Enumerates entries in a hash table and returns the next non-free entry.
1433 * RETURNS
1434 * TRUE if an entry was found
1435 * FALSE if the hash table is empty or there are no more entries to
1436 * enumerate.
1439 static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY * pHashEntry,
1440 DWORD * index, const struct _HASH_ENTRY ** ppHashEntry)
1442 for (; *index < HASHTABLE_SIZE ; (*index)++)
1444 if (pHashEntry->HashTable[*index].dwHashKey == HASHTABLE_FREE)
1445 continue;
1447 *ppHashEntry = &pHashEntry->HashTable[*index];
1448 TRACE("entry found %d\n", *index);
1449 return TRUE;
1451 TRACE("no more entries (%d)\n", *index);
1452 return FALSE;
1455 /***********************************************************************
1456 * GetUrlCacheEntryInfoExA (WININET.@)
1459 BOOL WINAPI GetUrlCacheEntryInfoExA(
1460 LPCSTR lpszUrl,
1461 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1462 LPDWORD lpdwCacheEntryInfoBufSize,
1463 LPSTR lpszReserved,
1464 LPDWORD lpdwReserved,
1465 LPVOID lpReserved,
1466 DWORD dwFlags)
1468 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1469 debugstr_a(lpszUrl),
1470 lpCacheEntryInfo,
1471 lpdwCacheEntryInfoBufSize,
1472 lpszReserved,
1473 lpdwReserved,
1474 lpReserved,
1475 dwFlags);
1477 if ((lpszReserved != NULL) ||
1478 (lpdwReserved != NULL) ||
1479 (lpReserved != NULL))
1481 ERR("Reserved value was not 0\n");
1482 SetLastError(ERROR_INVALID_PARAMETER);
1483 return FALSE;
1485 if (dwFlags != 0)
1486 FIXME("Undocumented flag(s): %x\n", dwFlags);
1487 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1490 /***********************************************************************
1491 * GetUrlCacheEntryInfoA (WININET.@)
1494 BOOL WINAPI GetUrlCacheEntryInfoA(
1495 IN LPCSTR lpszUrlName,
1496 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1497 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1500 LPURLCACHE_HEADER pHeader;
1501 struct _HASH_ENTRY * pHashEntry;
1502 const CACHEFILE_ENTRY * pEntry;
1503 const URL_CACHEFILE_ENTRY * pUrlEntry;
1504 URLCACHECONTAINER * pContainer;
1505 DWORD error;
1507 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1509 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1510 if (error != ERROR_SUCCESS)
1512 SetLastError(error);
1513 return FALSE;
1516 error = URLCacheContainer_OpenIndex(pContainer);
1517 if (error != ERROR_SUCCESS)
1519 SetLastError(error);
1520 return FALSE;
1523 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1524 return FALSE;
1526 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1528 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1529 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1530 SetLastError(ERROR_FILE_NOT_FOUND);
1531 return FALSE;
1534 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1535 if (pEntry->dwSignature != URL_SIGNATURE)
1537 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1538 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1539 SetLastError(ERROR_FILE_NOT_FOUND);
1540 return FALSE;
1543 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1544 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1545 if (pUrlEntry->dwOffsetHeaderInfo)
1546 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1548 if (lpdwCacheEntryInfoBufferSize)
1550 if (!lpCacheEntryInfo)
1551 *lpdwCacheEntryInfoBufferSize = 0;
1553 error = URLCache_CopyEntry(
1554 pContainer,
1555 pHeader,
1556 lpCacheEntryInfo,
1557 lpdwCacheEntryInfoBufferSize,
1558 pUrlEntry,
1559 FALSE /* ANSI */);
1560 if (error != ERROR_SUCCESS)
1562 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1563 SetLastError(error);
1564 return FALSE;
1566 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1569 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1571 return TRUE;
1574 /***********************************************************************
1575 * GetUrlCacheEntryInfoW (WININET.@)
1578 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1579 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1580 LPDWORD lpdwCacheEntryInfoBufferSize)
1582 LPURLCACHE_HEADER pHeader;
1583 struct _HASH_ENTRY * pHashEntry;
1584 const CACHEFILE_ENTRY * pEntry;
1585 const URL_CACHEFILE_ENTRY * pUrlEntry;
1586 URLCACHECONTAINER * pContainer;
1587 DWORD error;
1589 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1591 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1592 if (error != ERROR_SUCCESS)
1594 SetLastError(error);
1595 return FALSE;
1598 error = URLCacheContainer_OpenIndex(pContainer);
1599 if (error != ERROR_SUCCESS)
1601 SetLastError(error);
1602 return FALSE;
1605 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1606 return FALSE;
1608 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1610 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1611 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1612 SetLastError(ERROR_FILE_NOT_FOUND);
1613 return FALSE;
1616 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1617 if (pEntry->dwSignature != URL_SIGNATURE)
1619 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1620 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1621 SetLastError(ERROR_FILE_NOT_FOUND);
1622 return FALSE;
1625 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1626 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1627 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1629 if (lpdwCacheEntryInfoBufferSize)
1631 if (!lpCacheEntryInfo)
1632 *lpdwCacheEntryInfoBufferSize = 0;
1634 error = URLCache_CopyEntry(
1635 pContainer,
1636 pHeader,
1637 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1638 lpdwCacheEntryInfoBufferSize,
1639 pUrlEntry,
1640 TRUE /* UNICODE */);
1641 if (error != ERROR_SUCCESS)
1643 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1644 SetLastError(error);
1645 return FALSE;
1647 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1650 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1652 return TRUE;
1655 /***********************************************************************
1656 * GetUrlCacheEntryInfoExW (WININET.@)
1659 BOOL WINAPI GetUrlCacheEntryInfoExW(
1660 LPCWSTR lpszUrl,
1661 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1662 LPDWORD lpdwCacheEntryInfoBufSize,
1663 LPWSTR lpszReserved,
1664 LPDWORD lpdwReserved,
1665 LPVOID lpReserved,
1666 DWORD dwFlags)
1668 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1669 debugstr_w(lpszUrl),
1670 lpCacheEntryInfo,
1671 lpdwCacheEntryInfoBufSize,
1672 lpszReserved,
1673 lpdwReserved,
1674 lpReserved,
1675 dwFlags);
1677 if ((lpszReserved != NULL) ||
1678 (lpdwReserved != NULL) ||
1679 (lpReserved != NULL))
1681 ERR("Reserved value was not 0\n");
1682 SetLastError(ERROR_INVALID_PARAMETER);
1683 return FALSE;
1685 if (dwFlags != 0)
1686 FIXME("Undocumented flag(s): %x\n", dwFlags);
1687 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1690 /***********************************************************************
1691 * SetUrlCacheEntryInfoA (WININET.@)
1693 BOOL WINAPI SetUrlCacheEntryInfoA(
1694 LPCSTR lpszUrlName,
1695 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1696 DWORD dwFieldControl)
1698 LPURLCACHE_HEADER pHeader;
1699 struct _HASH_ENTRY * pHashEntry;
1700 CACHEFILE_ENTRY * pEntry;
1701 URLCACHECONTAINER * pContainer;
1702 DWORD error;
1704 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1706 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1707 if (error != ERROR_SUCCESS)
1709 SetLastError(error);
1710 return FALSE;
1713 error = URLCacheContainer_OpenIndex(pContainer);
1714 if (error != ERROR_SUCCESS)
1716 SetLastError(error);
1717 return FALSE;
1720 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1721 return FALSE;
1723 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1725 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1726 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1727 SetLastError(ERROR_FILE_NOT_FOUND);
1728 return FALSE;
1731 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1732 if (pEntry->dwSignature != URL_SIGNATURE)
1734 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1735 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1736 SetLastError(ERROR_FILE_NOT_FOUND);
1737 return FALSE;
1740 URLCache_SetEntryInfo(
1741 (URL_CACHEFILE_ENTRY *)pEntry,
1742 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1743 dwFieldControl);
1745 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1747 return TRUE;
1750 /***********************************************************************
1751 * SetUrlCacheEntryInfoW (WININET.@)
1753 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1755 LPURLCACHE_HEADER pHeader;
1756 struct _HASH_ENTRY * pHashEntry;
1757 CACHEFILE_ENTRY * pEntry;
1758 URLCACHECONTAINER * pContainer;
1759 DWORD error;
1761 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1763 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1764 if (error != ERROR_SUCCESS)
1766 SetLastError(error);
1767 return FALSE;
1770 error = URLCacheContainer_OpenIndex(pContainer);
1771 if (error != ERROR_SUCCESS)
1773 SetLastError(error);
1774 return FALSE;
1777 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1778 return FALSE;
1780 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1782 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1783 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1784 SetLastError(ERROR_FILE_NOT_FOUND);
1785 return FALSE;
1788 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1789 if (pEntry->dwSignature != URL_SIGNATURE)
1791 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1792 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1793 SetLastError(ERROR_FILE_NOT_FOUND);
1794 return FALSE;
1797 URLCache_SetEntryInfo(
1798 (URL_CACHEFILE_ENTRY *)pEntry,
1799 lpCacheEntryInfo,
1800 dwFieldControl);
1802 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1804 return TRUE;
1807 /***********************************************************************
1808 * RetrieveUrlCacheEntryFileA (WININET.@)
1811 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1812 IN LPCSTR lpszUrlName,
1813 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1814 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1815 IN DWORD dwReserved
1818 LPURLCACHE_HEADER pHeader;
1819 struct _HASH_ENTRY * pHashEntry;
1820 CACHEFILE_ENTRY * pEntry;
1821 URL_CACHEFILE_ENTRY * pUrlEntry;
1822 URLCACHECONTAINER * pContainer;
1823 DWORD error;
1825 TRACE("(%s, %p, %p, 0x%08x)\n",
1826 debugstr_a(lpszUrlName),
1827 lpCacheEntryInfo,
1828 lpdwCacheEntryInfoBufferSize,
1829 dwReserved);
1831 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1832 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1834 SetLastError(ERROR_INVALID_PARAMETER);
1835 return FALSE;
1838 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1839 if (error != ERROR_SUCCESS)
1841 SetLastError(error);
1842 return FALSE;
1845 error = URLCacheContainer_OpenIndex(pContainer);
1846 if (error != ERROR_SUCCESS)
1848 SetLastError(error);
1849 return FALSE;
1852 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1853 return FALSE;
1855 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1857 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1858 TRACE("entry %s not found!\n", lpszUrlName);
1859 SetLastError(ERROR_FILE_NOT_FOUND);
1860 return FALSE;
1863 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1864 if (pEntry->dwSignature != URL_SIGNATURE)
1866 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1867 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1868 SetLastError(ERROR_FILE_NOT_FOUND);
1869 return FALSE;
1872 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1873 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1874 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1876 pUrlEntry->dwHitRate++;
1877 pUrlEntry->dwUseCount++;
1878 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1880 error = URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo,
1881 lpdwCacheEntryInfoBufferSize, pUrlEntry,
1882 FALSE);
1883 if (error != ERROR_SUCCESS)
1885 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1886 SetLastError(error);
1887 return FALSE;
1889 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1891 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1893 return TRUE;
1896 /***********************************************************************
1897 * RetrieveUrlCacheEntryFileW (WININET.@)
1900 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1901 IN LPCWSTR lpszUrlName,
1902 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1903 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1904 IN DWORD dwReserved
1907 LPURLCACHE_HEADER pHeader;
1908 struct _HASH_ENTRY * pHashEntry;
1909 CACHEFILE_ENTRY * pEntry;
1910 URL_CACHEFILE_ENTRY * pUrlEntry;
1911 URLCACHECONTAINER * pContainer;
1912 DWORD error;
1914 TRACE("(%s, %p, %p, 0x%08x)\n",
1915 debugstr_w(lpszUrlName),
1916 lpCacheEntryInfo,
1917 lpdwCacheEntryInfoBufferSize,
1918 dwReserved);
1920 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1921 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1923 SetLastError(ERROR_INVALID_PARAMETER);
1924 return FALSE;
1927 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
1928 if (error != ERROR_SUCCESS)
1930 SetLastError(error);
1931 return FALSE;
1934 error = URLCacheContainer_OpenIndex(pContainer);
1935 if (error != ERROR_SUCCESS)
1937 SetLastError(error);
1938 return FALSE;
1941 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1942 return FALSE;
1944 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1946 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1947 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1948 SetLastError(ERROR_FILE_NOT_FOUND);
1949 return FALSE;
1952 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1953 if (pEntry->dwSignature != URL_SIGNATURE)
1955 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1956 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1957 SetLastError(ERROR_FILE_NOT_FOUND);
1958 return FALSE;
1961 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1962 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1963 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1965 pUrlEntry->dwHitRate++;
1966 pUrlEntry->dwUseCount++;
1967 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1969 error = URLCache_CopyEntry(
1970 pContainer,
1971 pHeader,
1972 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1973 lpdwCacheEntryInfoBufferSize,
1974 pUrlEntry,
1975 TRUE /* UNICODE */);
1976 if (error != ERROR_SUCCESS)
1978 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1979 SetLastError(error);
1980 return FALSE;
1982 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1984 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1986 return TRUE;
1989 /***********************************************************************
1990 * UnlockUrlCacheEntryFileA (WININET.@)
1993 BOOL WINAPI UnlockUrlCacheEntryFileA(
1994 IN LPCSTR lpszUrlName,
1995 IN DWORD dwReserved
1998 LPURLCACHE_HEADER pHeader;
1999 struct _HASH_ENTRY * pHashEntry;
2000 CACHEFILE_ENTRY * pEntry;
2001 URL_CACHEFILE_ENTRY * pUrlEntry;
2002 URLCACHECONTAINER * pContainer;
2003 DWORD error;
2005 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
2007 if (dwReserved)
2009 ERR("dwReserved != 0\n");
2010 SetLastError(ERROR_INVALID_PARAMETER);
2011 return FALSE;
2014 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2015 if (error != ERROR_SUCCESS)
2017 SetLastError(error);
2018 return FALSE;
2021 error = URLCacheContainer_OpenIndex(pContainer);
2022 if (error != ERROR_SUCCESS)
2024 SetLastError(error);
2025 return FALSE;
2028 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2029 return FALSE;
2031 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2033 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2034 TRACE("entry %s not found!\n", lpszUrlName);
2035 SetLastError(ERROR_FILE_NOT_FOUND);
2036 return FALSE;
2039 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2040 if (pEntry->dwSignature != URL_SIGNATURE)
2042 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2043 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2044 SetLastError(ERROR_FILE_NOT_FOUND);
2045 return FALSE;
2048 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2050 if (pUrlEntry->dwUseCount == 0)
2052 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2053 return FALSE;
2055 pUrlEntry->dwUseCount--;
2056 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2058 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2060 return TRUE;
2063 /***********************************************************************
2064 * UnlockUrlCacheEntryFileW (WININET.@)
2067 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
2069 LPURLCACHE_HEADER pHeader;
2070 struct _HASH_ENTRY * pHashEntry;
2071 CACHEFILE_ENTRY * pEntry;
2072 URL_CACHEFILE_ENTRY * pUrlEntry;
2073 URLCACHECONTAINER * pContainer;
2074 DWORD error;
2076 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
2078 if (dwReserved)
2080 ERR("dwReserved != 0\n");
2081 SetLastError(ERROR_INVALID_PARAMETER);
2082 return FALSE;
2085 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2086 if (error != ERROR_SUCCESS)
2088 SetLastError(error);
2089 return FALSE;
2092 error = URLCacheContainer_OpenIndex(pContainer);
2093 if (error != ERROR_SUCCESS)
2095 SetLastError(error);
2096 return FALSE;
2099 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2100 return FALSE;
2102 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
2104 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2105 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
2106 SetLastError(ERROR_FILE_NOT_FOUND);
2107 return FALSE;
2110 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2111 if (pEntry->dwSignature != URL_SIGNATURE)
2113 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2114 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2115 SetLastError(ERROR_FILE_NOT_FOUND);
2116 return FALSE;
2119 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2121 if (pUrlEntry->dwUseCount == 0)
2123 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2124 return FALSE;
2126 pUrlEntry->dwUseCount--;
2127 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2129 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2131 return TRUE;
2134 /***********************************************************************
2135 * CreateUrlCacheEntryA (WININET.@)
2138 BOOL WINAPI CreateUrlCacheEntryA(
2139 IN LPCSTR lpszUrlName,
2140 IN DWORD dwExpectedFileSize,
2141 IN LPCSTR lpszFileExtension,
2142 OUT LPSTR lpszFileName,
2143 IN DWORD dwReserved
2146 DWORD len;
2147 WCHAR *url_name;
2148 WCHAR *file_extension;
2149 WCHAR file_name[MAX_PATH];
2150 BOOL bSuccess = FALSE;
2151 DWORD dwError = 0;
2153 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
2154 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2156 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2157 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 &&
2158 (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2160 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2161 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
2163 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
2165 bSuccess = TRUE;
2167 else
2169 dwError = GetLastError();
2172 else
2174 dwError = GetLastError();
2176 HeapFree(GetProcessHeap(), 0, file_extension);
2178 else
2180 dwError = GetLastError();
2182 HeapFree(GetProcessHeap(), 0, url_name);
2183 if (!bSuccess)
2184 SetLastError(dwError);
2186 return bSuccess;
2188 /***********************************************************************
2189 * CreateUrlCacheEntryW (WININET.@)
2192 BOOL WINAPI CreateUrlCacheEntryW(
2193 IN LPCWSTR lpszUrlName,
2194 IN DWORD dwExpectedFileSize,
2195 IN LPCWSTR lpszFileExtension,
2196 OUT LPWSTR lpszFileName,
2197 IN DWORD dwReserved
2200 URLCACHECONTAINER * pContainer;
2201 LPURLCACHE_HEADER pHeader;
2202 CHAR szFile[MAX_PATH];
2203 WCHAR szExtension[MAX_PATH];
2204 LPCWSTR lpszUrlPart;
2205 LPCWSTR lpszUrlEnd;
2206 LPCWSTR lpszFileNameExtension;
2207 LPWSTR lpszFileNameNoPath;
2208 int i;
2209 int countnoextension;
2210 BYTE CacheDir;
2211 LONG lBufferSize;
2212 BOOL bFound = FALSE;
2213 int count;
2214 DWORD error;
2215 static const WCHAR szWWW[] = {'w','w','w',0};
2217 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2218 debugstr_w(lpszUrlName),
2219 dwExpectedFileSize,
2220 debugstr_w(lpszFileExtension),
2221 lpszFileName,
2222 dwReserved);
2224 if (dwReserved)
2226 ERR("dwReserved != 0\n");
2227 SetLastError(ERROR_INVALID_PARAMETER);
2228 return FALSE;
2231 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2233 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2234 lpszUrlEnd--;
2236 for (lpszUrlPart = lpszUrlEnd;
2237 (lpszUrlPart >= lpszUrlName);
2238 lpszUrlPart--)
2240 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2242 bFound = TRUE;
2243 lpszUrlPart++;
2244 break;
2246 else if(*lpszUrlPart == '?' || *lpszUrlPart == '#')
2248 lpszUrlEnd = lpszUrlPart;
2251 if (!lstrcmpW(lpszUrlPart, szWWW))
2253 lpszUrlPart += lstrlenW(szWWW);
2256 count = lpszUrlEnd - lpszUrlPart;
2258 if (bFound && (count < MAX_PATH))
2260 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2261 if (!len)
2262 return FALSE;
2263 szFile[len] = '\0';
2264 while(len && szFile[--len] == '/') szFile[len] = '\0';
2266 /* FIXME: get rid of illegal characters like \, / and : */
2268 else
2270 FIXME("need to generate a random filename\n");
2273 TRACE("File name: %s\n", debugstr_a(szFile));
2275 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2276 if (error != ERROR_SUCCESS)
2278 SetLastError(error);
2279 return FALSE;
2282 error = URLCacheContainer_OpenIndex(pContainer);
2283 if (error != ERROR_SUCCESS)
2285 SetLastError(error);
2286 return FALSE;
2289 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2290 return FALSE;
2292 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2294 lBufferSize = MAX_PATH * sizeof(WCHAR);
2295 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
2297 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2299 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2300 lpszFileNameNoPath >= lpszFileName;
2301 --lpszFileNameNoPath)
2303 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2304 break;
2307 countnoextension = lstrlenW(lpszFileNameNoPath);
2308 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2309 if (lpszFileNameExtension)
2310 countnoextension -= lstrlenW(lpszFileNameExtension);
2311 *szExtension = '\0';
2313 if (lpszFileExtension)
2315 szExtension[0] = '.';
2316 lstrcpyW(szExtension+1, lpszFileExtension);
2319 for (i = 0; i < 255; i++)
2321 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2322 HANDLE hFile;
2323 WCHAR *p;
2325 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2326 for (p = lpszFileNameNoPath + 1; *p; p++)
2328 switch (*p)
2330 case '<': case '>':
2331 case ':': case '"':
2332 case '/': case '\\':
2333 case '|': case '?':
2334 case '*':
2335 *p = '_'; break;
2336 default: break;
2339 if (p[-1] == ' ' || p[-1] == '.') p[-1] = '_';
2341 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2342 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2343 if (hFile != INVALID_HANDLE_VALUE)
2345 CloseHandle(hFile);
2346 return TRUE;
2350 return FALSE;
2354 /***********************************************************************
2355 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2357 * The bug we are compensating for is that some drongo at Microsoft
2358 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2359 * As a consequence, CommitUrlCacheEntryA has been effectively
2360 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2361 * is still defined as LPCWSTR. The result (other than madness) is
2362 * that we always need to store lpHeaderInfo in CP_ACP rather than
2363 * in UTF16, and we need to avoid converting lpHeaderInfo in
2364 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2365 * result will lose data for arbitrary binary data.
2368 static BOOL CommitUrlCacheEntryInternal(
2369 IN LPCWSTR lpszUrlName,
2370 IN LPCWSTR lpszLocalFileName,
2371 IN FILETIME ExpireTime,
2372 IN FILETIME LastModifiedTime,
2373 IN DWORD CacheEntryType,
2374 IN LPBYTE lpHeaderInfo,
2375 IN DWORD dwHeaderSize,
2376 IN LPCWSTR lpszFileExtension,
2377 IN LPCWSTR lpszOriginalUrl
2380 URLCACHECONTAINER * pContainer;
2381 LPURLCACHE_HEADER pHeader;
2382 struct _HASH_ENTRY * pHashEntry;
2383 CACHEFILE_ENTRY * pEntry;
2384 URL_CACHEFILE_ENTRY * pUrlEntry;
2385 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2386 DWORD dwOffsetLocalFileName = 0;
2387 DWORD dwOffsetHeader = 0;
2388 DWORD dwOffsetFileExtension = 0;
2389 DWORD dwFileSizeLow = 0;
2390 DWORD dwFileSizeHigh = 0;
2391 BYTE cDirectory = 0;
2392 int len;
2393 char achFile[MAX_PATH];
2394 LPSTR lpszUrlNameA = NULL;
2395 LPSTR lpszFileExtensionA = NULL;
2396 char *pchLocalFileName = 0;
2397 DWORD error;
2399 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2400 debugstr_w(lpszUrlName),
2401 debugstr_w(lpszLocalFileName),
2402 CacheEntryType,
2403 lpHeaderInfo,
2404 dwHeaderSize,
2405 debugstr_w(lpszFileExtension),
2406 debugstr_w(lpszOriginalUrl));
2408 if (lpszOriginalUrl)
2409 WARN(": lpszOriginalUrl ignored\n");
2411 if (lpszLocalFileName)
2413 HANDLE hFile;
2415 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2416 if (hFile == INVALID_HANDLE_VALUE)
2418 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2419 return FALSE;
2422 /* Get file size */
2423 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2424 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2426 ERR("couldn't get file size (error is %d)\n", GetLastError());
2427 CloseHandle(hFile);
2428 return FALSE;
2431 CloseHandle(hFile);
2434 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2435 if (error != ERROR_SUCCESS)
2437 SetLastError(error);
2438 return FALSE;
2441 error = URLCacheContainer_OpenIndex(pContainer);
2442 if (error != ERROR_SUCCESS)
2444 SetLastError(error);
2445 return FALSE;
2448 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2449 return FALSE;
2451 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2452 lpszUrlNameA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2453 if (!lpszUrlNameA)
2455 error = GetLastError();
2456 goto cleanup;
2458 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, lpszUrlNameA, len, NULL, NULL);
2460 if (lpszFileExtension)
2462 len = WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, NULL, 0, NULL, NULL);
2463 lpszFileExtensionA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2464 if (!lpszFileExtensionA)
2466 error = GetLastError();
2467 goto cleanup;
2469 WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, lpszFileExtensionA, len, NULL, NULL);
2472 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2474 FIXME("entry already in cache - don't know what to do!\n");
2476 * SetLastError(ERROR_FILE_NOT_FOUND);
2477 * return FALSE;
2479 goto cleanup;
2482 if (lpszLocalFileName)
2484 BOOL bFound = FALSE;
2486 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2488 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2489 error = ERROR_INVALID_PARAMETER;
2490 goto cleanup;
2493 /* skip container path prefix */
2494 lpszLocalFileName += lstrlenW(pContainer->path);
2496 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL);
2497 pchLocalFileName = achFile;
2499 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2501 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2503 bFound = TRUE;
2504 break;
2508 if (!bFound)
2510 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2511 error = ERROR_INVALID_PARAMETER;
2512 goto cleanup;
2515 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2518 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2519 if (lpszLocalFileName)
2521 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2522 dwOffsetLocalFileName = dwBytesNeeded;
2523 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2525 if (lpHeaderInfo)
2527 dwOffsetHeader = dwBytesNeeded;
2528 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2530 if (lpszFileExtensionA)
2532 dwOffsetFileExtension = dwBytesNeeded;
2533 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2536 /* round up to next block */
2537 if (dwBytesNeeded % BLOCKSIZE)
2539 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2540 dwBytesNeeded += BLOCKSIZE;
2543 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2545 ERR("no free entries\n");
2546 error = ERROR_DISK_FULL;
2547 goto cleanup;
2550 /* FindFirstFreeEntry fills in blocks used */
2551 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2552 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2553 pUrlEntry->CacheDir = cDirectory;
2554 pUrlEntry->CacheEntryType = CacheEntryType;
2555 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2556 pUrlEntry->dwExemptDelta = 0;
2557 pUrlEntry->dwHitRate = 0;
2558 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2559 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2560 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2561 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2562 pUrlEntry->dwSizeHigh = 0;
2563 pUrlEntry->dwSizeLow = dwFileSizeLow;
2564 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2565 pUrlEntry->dwUseCount = 0;
2566 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2567 pUrlEntry->LastModifiedTime = LastModifiedTime;
2568 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2569 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2570 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2571 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2573 /*** Unknowns ***/
2574 pUrlEntry->dwUnknown1 = 0;
2575 pUrlEntry->dwUnknown2 = 0;
2576 pUrlEntry->dwUnknown3 = 0x60;
2577 pUrlEntry->Unknown4 = 0;
2578 pUrlEntry->wUnknown5 = 0x1010;
2579 pUrlEntry->dwUnknown7 = 0;
2580 pUrlEntry->dwUnknown8 = 0;
2583 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2584 if (dwOffsetLocalFileName)
2585 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2586 if (dwOffsetHeader)
2587 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2588 if (dwOffsetFileExtension)
2589 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2591 error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA,
2592 (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader));
2593 if (error != ERROR_SUCCESS)
2594 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2596 cleanup:
2597 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2598 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2599 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2601 if (error == ERROR_SUCCESS)
2602 return TRUE;
2603 else
2605 SetLastError(error);
2606 return FALSE;
2610 /***********************************************************************
2611 * CommitUrlCacheEntryA (WININET.@)
2614 BOOL WINAPI CommitUrlCacheEntryA(
2615 IN LPCSTR lpszUrlName,
2616 IN LPCSTR lpszLocalFileName,
2617 IN FILETIME ExpireTime,
2618 IN FILETIME LastModifiedTime,
2619 IN DWORD CacheEntryType,
2620 IN LPBYTE lpHeaderInfo,
2621 IN DWORD dwHeaderSize,
2622 IN LPCSTR lpszFileExtension,
2623 IN LPCSTR lpszOriginalUrl
2626 DWORD len;
2627 WCHAR *url_name = NULL;
2628 WCHAR *local_file_name = NULL;
2629 WCHAR *original_url = NULL;
2630 WCHAR *file_extension = NULL;
2631 BOOL bSuccess = FALSE;
2633 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2634 debugstr_a(lpszUrlName),
2635 debugstr_a(lpszLocalFileName),
2636 CacheEntryType,
2637 lpHeaderInfo,
2638 dwHeaderSize,
2639 debugstr_a(lpszFileExtension),
2640 debugstr_a(lpszOriginalUrl));
2642 len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0);
2643 url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2644 if (!url_name)
2645 goto cleanup;
2646 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2648 if (lpszLocalFileName)
2650 len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0);
2651 local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2652 if (!local_file_name)
2653 goto cleanup;
2654 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2656 if (lpszFileExtension)
2658 len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0);
2659 file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2660 if (!file_extension)
2661 goto cleanup;
2662 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2664 if (lpszOriginalUrl)
2666 len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0);
2667 original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2668 if (!original_url)
2669 goto cleanup;
2670 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2673 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2674 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2675 file_extension, original_url);
2677 cleanup:
2678 HeapFree(GetProcessHeap(), 0, original_url);
2679 HeapFree(GetProcessHeap(), 0, file_extension);
2680 HeapFree(GetProcessHeap(), 0, local_file_name);
2681 HeapFree(GetProcessHeap(), 0, url_name);
2683 return bSuccess;
2686 /***********************************************************************
2687 * CommitUrlCacheEntryW (WININET.@)
2690 BOOL WINAPI CommitUrlCacheEntryW(
2691 IN LPCWSTR lpszUrlName,
2692 IN LPCWSTR lpszLocalFileName,
2693 IN FILETIME ExpireTime,
2694 IN FILETIME LastModifiedTime,
2695 IN DWORD CacheEntryType,
2696 IN LPWSTR lpHeaderInfo,
2697 IN DWORD dwHeaderSize,
2698 IN LPCWSTR lpszFileExtension,
2699 IN LPCWSTR lpszOriginalUrl
2702 DWORD dwError = 0;
2703 BOOL bSuccess = FALSE;
2704 DWORD len = 0;
2705 CHAR *header_info = NULL;
2707 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2708 debugstr_w(lpszUrlName),
2709 debugstr_w(lpszLocalFileName),
2710 CacheEntryType,
2711 lpHeaderInfo,
2712 dwHeaderSize,
2713 debugstr_w(lpszFileExtension),
2714 debugstr_w(lpszOriginalUrl));
2716 if (!lpHeaderInfo ||
2717 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2718 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2720 if (header_info)
2721 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2722 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2723 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2725 bSuccess = TRUE;
2727 else
2729 dwError = GetLastError();
2731 if (header_info)
2733 HeapFree(GetProcessHeap(), 0, header_info);
2734 if (!bSuccess)
2735 SetLastError(dwError);
2738 return bSuccess;
2741 /***********************************************************************
2742 * ReadUrlCacheEntryStream (WININET.@)
2745 BOOL WINAPI ReadUrlCacheEntryStream(
2746 IN HANDLE hUrlCacheStream,
2747 IN DWORD dwLocation,
2748 IN OUT LPVOID lpBuffer,
2749 IN OUT LPDWORD lpdwLen,
2750 IN DWORD dwReserved
2753 /* Get handle to file from 'stream' */
2754 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2756 if (dwReserved != 0)
2758 ERR("dwReserved != 0\n");
2759 SetLastError(ERROR_INVALID_PARAMETER);
2760 return FALSE;
2763 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2765 SetLastError(ERROR_INVALID_HANDLE);
2766 return FALSE;
2769 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2770 return FALSE;
2771 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2774 /***********************************************************************
2775 * RetrieveUrlCacheEntryStreamA (WININET.@)
2778 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2779 IN LPCSTR lpszUrlName,
2780 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2781 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2782 IN BOOL fRandomRead,
2783 IN DWORD dwReserved
2786 /* NOTE: this is not the same as the way that the native
2787 * version allocates 'stream' handles. I did it this way
2788 * as it is much easier and no applications should depend
2789 * on this behaviour. (Native version appears to allocate
2790 * indices into a table)
2792 STREAM_HANDLE * pStream;
2793 HANDLE hFile;
2795 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2796 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2798 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2799 lpCacheEntryInfo,
2800 lpdwCacheEntryInfoBufferSize,
2801 dwReserved))
2803 return NULL;
2806 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2807 GENERIC_READ,
2808 FILE_SHARE_READ,
2809 NULL,
2810 OPEN_EXISTING,
2811 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2812 NULL);
2813 if (hFile == INVALID_HANDLE_VALUE)
2814 return FALSE;
2816 /* allocate handle storage space */
2817 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2818 if (!pStream)
2820 CloseHandle(hFile);
2821 SetLastError(ERROR_OUTOFMEMORY);
2822 return FALSE;
2825 pStream->hFile = hFile;
2826 strcpy(pStream->lpszUrl, lpszUrlName);
2827 return pStream;
2830 /***********************************************************************
2831 * RetrieveUrlCacheEntryStreamW (WININET.@)
2834 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2835 IN LPCWSTR lpszUrlName,
2836 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2837 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2838 IN BOOL fRandomRead,
2839 IN DWORD dwReserved
2842 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2843 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2844 return NULL;
2847 /***********************************************************************
2848 * UnlockUrlCacheEntryStream (WININET.@)
2851 BOOL WINAPI UnlockUrlCacheEntryStream(
2852 IN HANDLE hUrlCacheStream,
2853 IN DWORD dwReserved
2856 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2858 if (dwReserved != 0)
2860 ERR("dwReserved != 0\n");
2861 SetLastError(ERROR_INVALID_PARAMETER);
2862 return FALSE;
2865 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2867 SetLastError(ERROR_INVALID_HANDLE);
2868 return FALSE;
2871 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2872 return FALSE;
2874 /* close file handle */
2875 CloseHandle(pStream->hFile);
2877 /* free allocated space */
2878 HeapFree(GetProcessHeap(), 0, pStream);
2880 return TRUE;
2884 /***********************************************************************
2885 * DeleteUrlCacheEntryA (WININET.@)
2888 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2890 URLCACHECONTAINER * pContainer;
2891 LPURLCACHE_HEADER pHeader;
2892 struct _HASH_ENTRY * pHashEntry;
2893 CACHEFILE_ENTRY * pEntry;
2894 DWORD error;
2896 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2898 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2899 if (error != ERROR_SUCCESS)
2901 SetLastError(error);
2902 return FALSE;
2905 error = URLCacheContainer_OpenIndex(pContainer);
2906 if (error != ERROR_SUCCESS)
2908 SetLastError(error);
2909 return FALSE;
2912 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2913 return FALSE;
2915 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2917 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2918 TRACE("entry %s not found!\n", lpszUrlName);
2919 SetLastError(ERROR_FILE_NOT_FOUND);
2920 return FALSE;
2923 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2924 URLCache_DeleteEntry(pHeader, pEntry);
2926 URLCache_DeleteEntryFromHash(pHashEntry);
2928 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2930 return TRUE;
2933 /***********************************************************************
2934 * DeleteUrlCacheEntryW (WININET.@)
2937 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2939 URLCACHECONTAINER * pContainer;
2940 LPURLCACHE_HEADER pHeader;
2941 struct _HASH_ENTRY * pHashEntry;
2942 CACHEFILE_ENTRY * pEntry;
2943 LPSTR urlA;
2944 int url_len;
2945 DWORD error;
2947 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2949 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2950 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
2951 if (!urlA)
2953 SetLastError(ERROR_OUTOFMEMORY);
2954 return FALSE;
2956 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, urlA, url_len, NULL, NULL);
2958 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2959 if (error != ERROR_SUCCESS)
2961 HeapFree(GetProcessHeap(), 0, urlA);
2962 SetLastError(error);
2963 return FALSE;
2966 error = URLCacheContainer_OpenIndex(pContainer);
2967 if (error != ERROR_SUCCESS)
2969 HeapFree(GetProcessHeap(), 0, urlA);
2970 SetLastError(error);
2971 return FALSE;
2974 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2976 HeapFree(GetProcessHeap(), 0, urlA);
2977 return FALSE;
2980 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
2982 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2983 TRACE("entry %s not found!\n", debugstr_a(urlA));
2984 HeapFree(GetProcessHeap(), 0, urlA);
2985 SetLastError(ERROR_FILE_NOT_FOUND);
2986 return FALSE;
2989 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2990 URLCache_DeleteEntry(pHeader, pEntry);
2992 URLCache_DeleteEntryFromHash(pHashEntry);
2994 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2996 HeapFree(GetProcessHeap(), 0, urlA);
2997 return TRUE;
3000 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
3002 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3003 return TRUE;
3006 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
3008 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3009 return TRUE;
3012 /***********************************************************************
3013 * CreateCacheContainerA (WININET.@)
3015 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3016 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3018 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3019 d1, d2, d3, d4, d5, d6, d7, d8);
3020 return TRUE;
3023 /***********************************************************************
3024 * CreateCacheContainerW (WININET.@)
3026 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3027 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3029 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3030 d1, d2, d3, d4, d5, d6, d7, d8);
3031 return TRUE;
3034 /***********************************************************************
3035 * FindFirstUrlCacheContainerA (WININET.@)
3037 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3039 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3040 return NULL;
3043 /***********************************************************************
3044 * FindFirstUrlCacheContainerW (WININET.@)
3046 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3048 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3049 return NULL;
3052 /***********************************************************************
3053 * FindNextUrlCacheContainerA (WININET.@)
3055 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
3057 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3058 return FALSE;
3061 /***********************************************************************
3062 * FindNextUrlCacheContainerW (WININET.@)
3064 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
3066 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3067 return FALSE;
3070 HANDLE WINAPI FindFirstUrlCacheEntryExA(
3071 LPCSTR lpszUrlSearchPattern,
3072 DWORD dwFlags,
3073 DWORD dwFilter,
3074 GROUPID GroupId,
3075 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3076 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3077 LPVOID lpReserved,
3078 LPDWORD pcbReserved2,
3079 LPVOID lpReserved3
3082 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
3083 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3084 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3085 SetLastError(ERROR_FILE_NOT_FOUND);
3086 return NULL;
3089 HANDLE WINAPI FindFirstUrlCacheEntryExW(
3090 LPCWSTR lpszUrlSearchPattern,
3091 DWORD dwFlags,
3092 DWORD dwFilter,
3093 GROUPID GroupId,
3094 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3095 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3096 LPVOID lpReserved,
3097 LPDWORD pcbReserved2,
3098 LPVOID lpReserved3
3101 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
3102 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3103 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3104 SetLastError(ERROR_FILE_NOT_FOUND);
3105 return NULL;
3108 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3110 typedef struct URLCacheFindEntryHandle
3112 DWORD dwMagic;
3113 LPWSTR lpszUrlSearchPattern;
3114 DWORD dwContainerIndex;
3115 DWORD dwHashTableIndex;
3116 DWORD dwHashEntryIndex;
3117 } URLCacheFindEntryHandle;
3119 /***********************************************************************
3120 * FindFirstUrlCacheEntryA (WININET.@)
3123 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
3124 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3126 URLCacheFindEntryHandle *pEntryHandle;
3128 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3130 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3131 if (!pEntryHandle)
3132 return NULL;
3134 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3135 if (lpszUrlSearchPattern)
3137 int len = MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, NULL, 0);
3138 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3139 if (!pEntryHandle->lpszUrlSearchPattern)
3141 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3142 return NULL;
3144 MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, pEntryHandle->lpszUrlSearchPattern, len);
3146 else
3147 pEntryHandle->lpszUrlSearchPattern = NULL;
3148 pEntryHandle->dwContainerIndex = 0;
3149 pEntryHandle->dwHashTableIndex = 0;
3150 pEntryHandle->dwHashEntryIndex = 0;
3152 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3154 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3155 return NULL;
3157 return pEntryHandle;
3160 /***********************************************************************
3161 * FindFirstUrlCacheEntryW (WININET.@)
3164 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3165 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3167 URLCacheFindEntryHandle *pEntryHandle;
3169 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3171 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3172 if (!pEntryHandle)
3173 return NULL;
3175 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3176 if (lpszUrlSearchPattern)
3178 int len = strlenW(lpszUrlSearchPattern);
3179 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
3180 if (!pEntryHandle->lpszUrlSearchPattern)
3182 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3183 return NULL;
3185 memcpy(pEntryHandle->lpszUrlSearchPattern, lpszUrlSearchPattern, (len + 1) * sizeof(WCHAR));
3187 else
3188 pEntryHandle->lpszUrlSearchPattern = NULL;
3189 pEntryHandle->dwContainerIndex = 0;
3190 pEntryHandle->dwHashTableIndex = 0;
3191 pEntryHandle->dwHashEntryIndex = 0;
3193 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3195 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3196 return NULL;
3198 return pEntryHandle;
3201 /***********************************************************************
3202 * FindNextUrlCacheEntryA (WININET.@)
3204 BOOL WINAPI FindNextUrlCacheEntryA(
3205 HANDLE hEnumHandle,
3206 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3207 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3209 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3210 URLCACHECONTAINER * pContainer;
3212 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3214 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3216 SetLastError(ERROR_INVALID_HANDLE);
3217 return FALSE;
3220 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3221 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3223 LPURLCACHE_HEADER pHeader;
3224 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3225 DWORD error;
3227 error = URLCacheContainer_OpenIndex(pContainer);
3228 if (error != ERROR_SUCCESS)
3230 SetLastError(error);
3231 return FALSE;
3234 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3235 return FALSE;
3237 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3238 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3240 const struct _HASH_ENTRY *pHashEntry = NULL;
3241 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3242 pEntryHandle->dwHashEntryIndex++)
3244 const URL_CACHEFILE_ENTRY *pUrlEntry;
3245 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3247 if (pEntry->dwSignature != URL_SIGNATURE)
3248 continue;
3250 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3251 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3252 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3254 error = URLCache_CopyEntry(
3255 pContainer,
3256 pHeader,
3257 lpNextCacheEntryInfo,
3258 lpdwNextCacheEntryInfoBufferSize,
3259 pUrlEntry,
3260 FALSE /* not UNICODE */);
3261 if (error != ERROR_SUCCESS)
3263 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3264 SetLastError(error);
3265 return FALSE;
3267 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
3269 /* increment the current index so that next time the function
3270 * is called the next entry is returned */
3271 pEntryHandle->dwHashEntryIndex++;
3272 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3273 return TRUE;
3277 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3280 SetLastError(ERROR_NO_MORE_ITEMS);
3281 return FALSE;
3284 /***********************************************************************
3285 * FindNextUrlCacheEntryW (WININET.@)
3287 BOOL WINAPI FindNextUrlCacheEntryW(
3288 HANDLE hEnumHandle,
3289 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3290 LPDWORD lpdwNextCacheEntryInfoBufferSize
3293 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3294 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3295 return FALSE;
3298 /***********************************************************************
3299 * FindCloseUrlCache (WININET.@)
3301 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3303 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3305 TRACE("(%p)\n", hEnumHandle);
3307 if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3309 SetLastError(ERROR_INVALID_HANDLE);
3310 return FALSE;
3313 pEntryHandle->dwMagic = 0;
3314 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3315 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3317 return TRUE;
3320 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3321 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3323 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3324 dwSearchCondition, lpGroupId, lpReserved);
3325 return NULL;
3328 BOOL WINAPI FindNextUrlCacheEntryExA(
3329 HANDLE hEnumHandle,
3330 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3331 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3332 LPVOID lpReserved,
3333 LPDWORD pcbReserved2,
3334 LPVOID lpReserved3
3337 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3338 lpReserved, pcbReserved2, lpReserved3);
3339 return FALSE;
3342 BOOL WINAPI FindNextUrlCacheEntryExW(
3343 HANDLE hEnumHandle,
3344 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3345 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3346 LPVOID lpReserved,
3347 LPDWORD pcbReserved2,
3348 LPVOID lpReserved3
3351 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3352 lpReserved, pcbReserved2, lpReserved3);
3353 return FALSE;
3356 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3358 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3359 return FALSE;
3362 /***********************************************************************
3363 * CreateUrlCacheGroup (WININET.@)
3366 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3368 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3369 return FALSE;
3372 /***********************************************************************
3373 * DeleteUrlCacheGroup (WININET.@)
3376 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3378 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3379 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3380 return FALSE;
3383 /***********************************************************************
3384 * SetUrlCacheEntryGroupA (WININET.@)
3387 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3388 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3389 LPVOID lpReserved)
3391 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3392 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3393 pbGroupAttributes, cbGroupAttributes, lpReserved);
3394 SetLastError(ERROR_FILE_NOT_FOUND);
3395 return FALSE;
3398 /***********************************************************************
3399 * SetUrlCacheEntryGroupW (WININET.@)
3402 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3403 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3404 LPVOID lpReserved)
3406 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3407 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3408 pbGroupAttributes, cbGroupAttributes, lpReserved);
3409 SetLastError(ERROR_FILE_NOT_FOUND);
3410 return FALSE;
3413 /***********************************************************************
3414 * GetUrlCacheConfigInfoW (WININET.@)
3416 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3418 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3419 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3420 return FALSE;
3423 /***********************************************************************
3424 * GetUrlCacheConfigInfoA (WININET.@)
3426 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3428 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3430 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3431 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3432 return FALSE;
3435 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3436 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3437 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3439 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3440 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3441 lpdwGroupInfo, lpReserved);
3442 return FALSE;
3445 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3446 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3447 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3449 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3450 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3451 lpdwGroupInfo, lpReserved);
3452 return FALSE;
3455 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3456 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3458 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3459 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3460 return TRUE;
3463 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3464 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3466 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3467 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3468 return TRUE;
3471 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3473 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3474 return TRUE;
3477 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3479 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3480 return TRUE;
3483 /***********************************************************************
3484 * DeleteIE3Cache (WININET.@)
3486 * Deletes the files used by the IE3 URL caching system.
3488 * PARAMS
3489 * hWnd [I] A dummy window.
3490 * hInst [I] Instance of process calling the function.
3491 * lpszCmdLine [I] Options used by function.
3492 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3494 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3496 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3497 return 0;
3500 /***********************************************************************
3501 * IsUrlCacheEntryExpiredA (WININET.@)
3503 * PARAMS
3504 * url [I] Url
3505 * dwFlags [I] Unknown
3506 * pftLastModified [O] Last modified time
3508 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3510 LPURLCACHE_HEADER pHeader;
3511 struct _HASH_ENTRY * pHashEntry;
3512 const CACHEFILE_ENTRY * pEntry;
3513 const URL_CACHEFILE_ENTRY * pUrlEntry;
3514 URLCACHECONTAINER * pContainer;
3515 DWORD error;
3517 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3519 error = URLCacheContainers_FindContainerA(url, &pContainer);
3520 if (error != ERROR_SUCCESS)
3522 SetLastError(error);
3523 return FALSE;
3526 error = URLCacheContainer_OpenIndex(pContainer);
3527 if (error != ERROR_SUCCESS)
3529 SetLastError(error);
3530 return FALSE;
3533 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3534 return FALSE;
3536 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3538 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3539 TRACE("entry %s not found!\n", url);
3540 SetLastError(ERROR_FILE_NOT_FOUND);
3541 return FALSE;
3544 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3545 if (pEntry->dwSignature != URL_SIGNATURE)
3547 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3548 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3549 SetLastError(ERROR_FILE_NOT_FOUND);
3550 return FALSE;
3553 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3555 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3557 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3559 return TRUE;
3562 /***********************************************************************
3563 * IsUrlCacheEntryExpiredW (WININET.@)
3565 * PARAMS
3566 * url [I] Url
3567 * dwFlags [I] Unknown
3568 * pftLastModified [O] Last modified time
3570 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3572 LPURLCACHE_HEADER pHeader;
3573 struct _HASH_ENTRY * pHashEntry;
3574 const CACHEFILE_ENTRY * pEntry;
3575 const URL_CACHEFILE_ENTRY * pUrlEntry;
3576 URLCACHECONTAINER * pContainer;
3577 DWORD error;
3579 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3581 error = URLCacheContainers_FindContainerW(url, &pContainer);
3582 if (error != ERROR_SUCCESS)
3584 SetLastError(error);
3585 return FALSE;
3588 error = URLCacheContainer_OpenIndex(pContainer);
3589 if (error != ERROR_SUCCESS)
3591 SetLastError(error);
3592 return FALSE;
3595 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3596 return FALSE;
3598 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3600 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3601 TRACE("entry %s not found!\n", debugstr_w(url));
3602 SetLastError(ERROR_FILE_NOT_FOUND);
3603 return FALSE;
3606 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3607 if (pEntry->dwSignature != URL_SIGNATURE)
3609 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3610 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3611 SetLastError(ERROR_FILE_NOT_FOUND);
3612 return FALSE;
3615 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3617 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3619 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3621 return TRUE;
3624 /***********************************************************************
3625 * GetDiskInfoA (WININET.@)
3627 DWORD WINAPI GetDiskInfoA(void *p0, void *p1, void *p2, void *p3)
3629 FIXME("(%p, %p, %p, %p)\n", p0, p1, p2, p3);
3630 return 0;
3633 /***********************************************************************
3634 * RegisterUrlCacheNotification (WININET.@)
3636 DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
3638 FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f);
3639 return 0;