push cc8bc80451cc24f4d7cf75168b569f0ebfe19547
[wine/hacks.git] / dlls / wininet / urlcache.c
blob418f508f6500e712f845bc5d25957f595eeeb40b
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)
2225 FIXME("dwReserved 0x%08x\n", dwReserved);
2227 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2229 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2230 lpszUrlEnd--;
2232 for (lpszUrlPart = lpszUrlEnd;
2233 (lpszUrlPart >= lpszUrlName);
2234 lpszUrlPart--)
2236 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2238 bFound = TRUE;
2239 lpszUrlPart++;
2240 break;
2242 else if(*lpszUrlPart == '?' || *lpszUrlPart == '#')
2244 lpszUrlEnd = lpszUrlPart;
2247 if (!lstrcmpW(lpszUrlPart, szWWW))
2249 lpszUrlPart += lstrlenW(szWWW);
2252 count = lpszUrlEnd - lpszUrlPart;
2254 if (bFound && (count < MAX_PATH))
2256 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2257 if (!len)
2258 return FALSE;
2259 szFile[len] = '\0';
2260 while(len && szFile[--len] == '/') szFile[len] = '\0';
2262 /* FIXME: get rid of illegal characters like \, / and : */
2264 else
2266 FIXME("need to generate a random filename\n");
2269 TRACE("File name: %s\n", debugstr_a(szFile));
2271 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2272 if (error != ERROR_SUCCESS)
2274 SetLastError(error);
2275 return FALSE;
2278 error = URLCacheContainer_OpenIndex(pContainer);
2279 if (error != ERROR_SUCCESS)
2281 SetLastError(error);
2282 return FALSE;
2285 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2286 return FALSE;
2288 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2290 lBufferSize = MAX_PATH * sizeof(WCHAR);
2291 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
2293 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2295 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2296 lpszFileNameNoPath >= lpszFileName;
2297 --lpszFileNameNoPath)
2299 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2300 break;
2303 countnoextension = lstrlenW(lpszFileNameNoPath);
2304 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2305 if (lpszFileNameExtension)
2306 countnoextension -= lstrlenW(lpszFileNameExtension);
2307 *szExtension = '\0';
2309 if (lpszFileExtension)
2311 szExtension[0] = '.';
2312 lstrcpyW(szExtension+1, lpszFileExtension);
2315 for (i = 0; i < 255; i++)
2317 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2318 HANDLE hFile;
2319 WCHAR *p;
2321 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2322 for (p = lpszFileNameNoPath + 1; *p; p++)
2324 switch (*p)
2326 case '<': case '>':
2327 case ':': case '"':
2328 case '/': case '\\':
2329 case '|': case '?':
2330 case '*':
2331 *p = '_'; break;
2332 default: break;
2335 if (p[-1] == ' ' || p[-1] == '.') p[-1] = '_';
2337 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2338 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2339 if (hFile != INVALID_HANDLE_VALUE)
2341 CloseHandle(hFile);
2342 return TRUE;
2346 return FALSE;
2350 /***********************************************************************
2351 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2353 * The bug we are compensating for is that some drongo at Microsoft
2354 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2355 * As a consequence, CommitUrlCacheEntryA has been effectively
2356 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2357 * is still defined as LPCWSTR. The result (other than madness) is
2358 * that we always need to store lpHeaderInfo in CP_ACP rather than
2359 * in UTF16, and we need to avoid converting lpHeaderInfo in
2360 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2361 * result will lose data for arbitrary binary data.
2364 static BOOL CommitUrlCacheEntryInternal(
2365 IN LPCWSTR lpszUrlName,
2366 IN LPCWSTR lpszLocalFileName,
2367 IN FILETIME ExpireTime,
2368 IN FILETIME LastModifiedTime,
2369 IN DWORD CacheEntryType,
2370 IN LPBYTE lpHeaderInfo,
2371 IN DWORD dwHeaderSize,
2372 IN LPCWSTR lpszFileExtension,
2373 IN LPCWSTR lpszOriginalUrl
2376 URLCACHECONTAINER * pContainer;
2377 LPURLCACHE_HEADER pHeader;
2378 struct _HASH_ENTRY * pHashEntry;
2379 CACHEFILE_ENTRY * pEntry;
2380 URL_CACHEFILE_ENTRY * pUrlEntry;
2381 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2382 DWORD dwOffsetLocalFileName = 0;
2383 DWORD dwOffsetHeader = 0;
2384 DWORD dwOffsetFileExtension = 0;
2385 DWORD dwFileSizeLow = 0;
2386 DWORD dwFileSizeHigh = 0;
2387 BYTE cDirectory = 0;
2388 int len;
2389 char achFile[MAX_PATH];
2390 LPSTR lpszUrlNameA = NULL;
2391 LPSTR lpszFileExtensionA = NULL;
2392 char *pchLocalFileName = 0;
2393 DWORD error;
2395 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2396 debugstr_w(lpszUrlName),
2397 debugstr_w(lpszLocalFileName),
2398 CacheEntryType,
2399 lpHeaderInfo,
2400 dwHeaderSize,
2401 debugstr_w(lpszFileExtension),
2402 debugstr_w(lpszOriginalUrl));
2404 if (lpszOriginalUrl)
2405 WARN(": lpszOriginalUrl ignored\n");
2407 if (lpszLocalFileName)
2409 HANDLE hFile;
2411 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2412 if (hFile == INVALID_HANDLE_VALUE)
2414 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2415 return FALSE;
2418 /* Get file size */
2419 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2420 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2422 ERR("couldn't get file size (error is %d)\n", GetLastError());
2423 CloseHandle(hFile);
2424 return FALSE;
2427 CloseHandle(hFile);
2430 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2431 if (error != ERROR_SUCCESS)
2433 SetLastError(error);
2434 return FALSE;
2437 error = URLCacheContainer_OpenIndex(pContainer);
2438 if (error != ERROR_SUCCESS)
2440 SetLastError(error);
2441 return FALSE;
2444 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2445 return FALSE;
2447 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2448 lpszUrlNameA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2449 if (!lpszUrlNameA)
2451 error = GetLastError();
2452 goto cleanup;
2454 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, lpszUrlNameA, len, NULL, NULL);
2456 if (lpszFileExtension)
2458 len = WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, NULL, 0, NULL, NULL);
2459 lpszFileExtensionA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2460 if (!lpszFileExtensionA)
2462 error = GetLastError();
2463 goto cleanup;
2465 WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, lpszFileExtensionA, len, NULL, NULL);
2468 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2470 FIXME("entry already in cache - don't know what to do!\n");
2472 * SetLastError(ERROR_FILE_NOT_FOUND);
2473 * return FALSE;
2475 goto cleanup;
2478 if (lpszLocalFileName)
2480 BOOL bFound = FALSE;
2482 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2484 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2485 error = ERROR_INVALID_PARAMETER;
2486 goto cleanup;
2489 /* skip container path prefix */
2490 lpszLocalFileName += lstrlenW(pContainer->path);
2492 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL);
2493 pchLocalFileName = achFile;
2495 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2497 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2499 bFound = TRUE;
2500 break;
2504 if (!bFound)
2506 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2507 error = ERROR_INVALID_PARAMETER;
2508 goto cleanup;
2511 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2514 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2515 if (lpszLocalFileName)
2517 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2518 dwOffsetLocalFileName = dwBytesNeeded;
2519 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2521 if (lpHeaderInfo)
2523 dwOffsetHeader = dwBytesNeeded;
2524 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2526 if (lpszFileExtensionA)
2528 dwOffsetFileExtension = dwBytesNeeded;
2529 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2532 /* round up to next block */
2533 if (dwBytesNeeded % BLOCKSIZE)
2535 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2536 dwBytesNeeded += BLOCKSIZE;
2539 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2541 ERR("no free entries\n");
2542 error = ERROR_DISK_FULL;
2543 goto cleanup;
2546 /* FindFirstFreeEntry fills in blocks used */
2547 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2548 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2549 pUrlEntry->CacheDir = cDirectory;
2550 pUrlEntry->CacheEntryType = CacheEntryType;
2551 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2552 pUrlEntry->dwExemptDelta = 0;
2553 pUrlEntry->dwHitRate = 0;
2554 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2555 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2556 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2557 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2558 pUrlEntry->dwSizeHigh = 0;
2559 pUrlEntry->dwSizeLow = dwFileSizeLow;
2560 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2561 pUrlEntry->dwUseCount = 0;
2562 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2563 pUrlEntry->LastModifiedTime = LastModifiedTime;
2564 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2565 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2566 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2567 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2569 /*** Unknowns ***/
2570 pUrlEntry->dwUnknown1 = 0;
2571 pUrlEntry->dwUnknown2 = 0;
2572 pUrlEntry->dwUnknown3 = 0x60;
2573 pUrlEntry->Unknown4 = 0;
2574 pUrlEntry->wUnknown5 = 0x1010;
2575 pUrlEntry->dwUnknown7 = 0;
2576 pUrlEntry->dwUnknown8 = 0;
2579 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2580 if (dwOffsetLocalFileName)
2581 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2582 if (dwOffsetHeader)
2583 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2584 if (dwOffsetFileExtension)
2585 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2587 error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA,
2588 (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader));
2589 if (error != ERROR_SUCCESS)
2590 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2592 cleanup:
2593 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2594 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2595 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2597 if (error == ERROR_SUCCESS)
2598 return TRUE;
2599 else
2601 SetLastError(error);
2602 return FALSE;
2606 /***********************************************************************
2607 * CommitUrlCacheEntryA (WININET.@)
2610 BOOL WINAPI CommitUrlCacheEntryA(
2611 IN LPCSTR lpszUrlName,
2612 IN LPCSTR lpszLocalFileName,
2613 IN FILETIME ExpireTime,
2614 IN FILETIME LastModifiedTime,
2615 IN DWORD CacheEntryType,
2616 IN LPBYTE lpHeaderInfo,
2617 IN DWORD dwHeaderSize,
2618 IN LPCSTR lpszFileExtension,
2619 IN LPCSTR lpszOriginalUrl
2622 DWORD len;
2623 WCHAR *url_name = NULL;
2624 WCHAR *local_file_name = NULL;
2625 WCHAR *original_url = NULL;
2626 WCHAR *file_extension = NULL;
2627 BOOL bSuccess = FALSE;
2629 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2630 debugstr_a(lpszUrlName),
2631 debugstr_a(lpszLocalFileName),
2632 CacheEntryType,
2633 lpHeaderInfo,
2634 dwHeaderSize,
2635 debugstr_a(lpszFileExtension),
2636 debugstr_a(lpszOriginalUrl));
2638 len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0);
2639 url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2640 if (!url_name)
2641 goto cleanup;
2642 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2644 if (lpszLocalFileName)
2646 len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0);
2647 local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2648 if (!local_file_name)
2649 goto cleanup;
2650 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2652 if (lpszFileExtension)
2654 len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0);
2655 file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2656 if (!file_extension)
2657 goto cleanup;
2658 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2660 if (lpszOriginalUrl)
2662 len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0);
2663 original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2664 if (!original_url)
2665 goto cleanup;
2666 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2669 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2670 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2671 file_extension, original_url);
2673 cleanup:
2674 HeapFree(GetProcessHeap(), 0, original_url);
2675 HeapFree(GetProcessHeap(), 0, file_extension);
2676 HeapFree(GetProcessHeap(), 0, local_file_name);
2677 HeapFree(GetProcessHeap(), 0, url_name);
2679 return bSuccess;
2682 /***********************************************************************
2683 * CommitUrlCacheEntryW (WININET.@)
2686 BOOL WINAPI CommitUrlCacheEntryW(
2687 IN LPCWSTR lpszUrlName,
2688 IN LPCWSTR lpszLocalFileName,
2689 IN FILETIME ExpireTime,
2690 IN FILETIME LastModifiedTime,
2691 IN DWORD CacheEntryType,
2692 IN LPWSTR lpHeaderInfo,
2693 IN DWORD dwHeaderSize,
2694 IN LPCWSTR lpszFileExtension,
2695 IN LPCWSTR lpszOriginalUrl
2698 DWORD dwError = 0;
2699 BOOL bSuccess = FALSE;
2700 DWORD len = 0;
2701 CHAR *header_info = NULL;
2703 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2704 debugstr_w(lpszUrlName),
2705 debugstr_w(lpszLocalFileName),
2706 CacheEntryType,
2707 lpHeaderInfo,
2708 dwHeaderSize,
2709 debugstr_w(lpszFileExtension),
2710 debugstr_w(lpszOriginalUrl));
2712 if (!lpHeaderInfo ||
2713 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2714 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2716 if (header_info)
2717 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2718 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2719 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2721 bSuccess = TRUE;
2723 else
2725 dwError = GetLastError();
2727 if (header_info)
2729 HeapFree(GetProcessHeap(), 0, header_info);
2730 if (!bSuccess)
2731 SetLastError(dwError);
2734 return bSuccess;
2737 /***********************************************************************
2738 * ReadUrlCacheEntryStream (WININET.@)
2741 BOOL WINAPI ReadUrlCacheEntryStream(
2742 IN HANDLE hUrlCacheStream,
2743 IN DWORD dwLocation,
2744 IN OUT LPVOID lpBuffer,
2745 IN OUT LPDWORD lpdwLen,
2746 IN DWORD dwReserved
2749 /* Get handle to file from 'stream' */
2750 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2752 if (dwReserved != 0)
2754 ERR("dwReserved != 0\n");
2755 SetLastError(ERROR_INVALID_PARAMETER);
2756 return FALSE;
2759 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2761 SetLastError(ERROR_INVALID_HANDLE);
2762 return FALSE;
2765 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2766 return FALSE;
2767 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2770 /***********************************************************************
2771 * RetrieveUrlCacheEntryStreamA (WININET.@)
2774 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2775 IN LPCSTR lpszUrlName,
2776 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2777 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2778 IN BOOL fRandomRead,
2779 IN DWORD dwReserved
2782 /* NOTE: this is not the same as the way that the native
2783 * version allocates 'stream' handles. I did it this way
2784 * as it is much easier and no applications should depend
2785 * on this behaviour. (Native version appears to allocate
2786 * indices into a table)
2788 STREAM_HANDLE * pStream;
2789 HANDLE hFile;
2791 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2792 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2794 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2795 lpCacheEntryInfo,
2796 lpdwCacheEntryInfoBufferSize,
2797 dwReserved))
2799 return NULL;
2802 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2803 GENERIC_READ,
2804 FILE_SHARE_READ,
2805 NULL,
2806 OPEN_EXISTING,
2807 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2808 NULL);
2809 if (hFile == INVALID_HANDLE_VALUE)
2810 return FALSE;
2812 /* allocate handle storage space */
2813 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2814 if (!pStream)
2816 CloseHandle(hFile);
2817 SetLastError(ERROR_OUTOFMEMORY);
2818 return FALSE;
2821 pStream->hFile = hFile;
2822 strcpy(pStream->lpszUrl, lpszUrlName);
2823 return pStream;
2826 /***********************************************************************
2827 * RetrieveUrlCacheEntryStreamW (WININET.@)
2830 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2831 IN LPCWSTR lpszUrlName,
2832 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2833 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2834 IN BOOL fRandomRead,
2835 IN DWORD dwReserved
2838 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2839 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2840 return NULL;
2843 /***********************************************************************
2844 * UnlockUrlCacheEntryStream (WININET.@)
2847 BOOL WINAPI UnlockUrlCacheEntryStream(
2848 IN HANDLE hUrlCacheStream,
2849 IN DWORD dwReserved
2852 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2854 if (dwReserved != 0)
2856 ERR("dwReserved != 0\n");
2857 SetLastError(ERROR_INVALID_PARAMETER);
2858 return FALSE;
2861 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2863 SetLastError(ERROR_INVALID_HANDLE);
2864 return FALSE;
2867 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2868 return FALSE;
2870 /* close file handle */
2871 CloseHandle(pStream->hFile);
2873 /* free allocated space */
2874 HeapFree(GetProcessHeap(), 0, pStream);
2876 return TRUE;
2880 /***********************************************************************
2881 * DeleteUrlCacheEntryA (WININET.@)
2884 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2886 URLCACHECONTAINER * pContainer;
2887 LPURLCACHE_HEADER pHeader;
2888 struct _HASH_ENTRY * pHashEntry;
2889 CACHEFILE_ENTRY * pEntry;
2890 DWORD error;
2892 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2894 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2895 if (error != ERROR_SUCCESS)
2897 SetLastError(error);
2898 return FALSE;
2901 error = URLCacheContainer_OpenIndex(pContainer);
2902 if (error != ERROR_SUCCESS)
2904 SetLastError(error);
2905 return FALSE;
2908 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2909 return FALSE;
2911 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2913 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2914 TRACE("entry %s not found!\n", lpszUrlName);
2915 SetLastError(ERROR_FILE_NOT_FOUND);
2916 return FALSE;
2919 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2920 URLCache_DeleteEntry(pHeader, pEntry);
2922 URLCache_DeleteEntryFromHash(pHashEntry);
2924 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2926 return TRUE;
2929 /***********************************************************************
2930 * DeleteUrlCacheEntryW (WININET.@)
2933 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2935 URLCACHECONTAINER * pContainer;
2936 LPURLCACHE_HEADER pHeader;
2937 struct _HASH_ENTRY * pHashEntry;
2938 CACHEFILE_ENTRY * pEntry;
2939 LPSTR urlA;
2940 int url_len;
2941 DWORD error;
2943 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2945 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2946 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
2947 if (!urlA)
2949 SetLastError(ERROR_OUTOFMEMORY);
2950 return FALSE;
2952 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, urlA, url_len, NULL, NULL);
2954 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2955 if (error != ERROR_SUCCESS)
2957 HeapFree(GetProcessHeap(), 0, urlA);
2958 SetLastError(error);
2959 return FALSE;
2962 error = URLCacheContainer_OpenIndex(pContainer);
2963 if (error != ERROR_SUCCESS)
2965 HeapFree(GetProcessHeap(), 0, urlA);
2966 SetLastError(error);
2967 return FALSE;
2970 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2972 HeapFree(GetProcessHeap(), 0, urlA);
2973 return FALSE;
2976 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
2978 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2979 TRACE("entry %s not found!\n", debugstr_a(urlA));
2980 HeapFree(GetProcessHeap(), 0, urlA);
2981 SetLastError(ERROR_FILE_NOT_FOUND);
2982 return FALSE;
2985 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2986 URLCache_DeleteEntry(pHeader, pEntry);
2988 URLCache_DeleteEntryFromHash(pHashEntry);
2990 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2992 HeapFree(GetProcessHeap(), 0, urlA);
2993 return TRUE;
2996 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2998 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2999 return TRUE;
3002 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
3004 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3005 return TRUE;
3008 /***********************************************************************
3009 * CreateCacheContainerA (WININET.@)
3011 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3012 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3014 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3015 d1, d2, d3, d4, d5, d6, d7, d8);
3016 return TRUE;
3019 /***********************************************************************
3020 * CreateCacheContainerW (WININET.@)
3022 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3023 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3025 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3026 d1, d2, d3, d4, d5, d6, d7, d8);
3027 return TRUE;
3030 /***********************************************************************
3031 * FindFirstUrlCacheContainerA (WININET.@)
3033 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3035 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3036 return NULL;
3039 /***********************************************************************
3040 * FindFirstUrlCacheContainerW (WININET.@)
3042 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3044 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3045 return NULL;
3048 /***********************************************************************
3049 * FindNextUrlCacheContainerA (WININET.@)
3051 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
3053 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3054 return FALSE;
3057 /***********************************************************************
3058 * FindNextUrlCacheContainerW (WININET.@)
3060 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
3062 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3063 return FALSE;
3066 HANDLE WINAPI FindFirstUrlCacheEntryExA(
3067 LPCSTR lpszUrlSearchPattern,
3068 DWORD dwFlags,
3069 DWORD dwFilter,
3070 GROUPID GroupId,
3071 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3072 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3073 LPVOID lpReserved,
3074 LPDWORD pcbReserved2,
3075 LPVOID lpReserved3
3078 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
3079 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3080 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3081 SetLastError(ERROR_FILE_NOT_FOUND);
3082 return NULL;
3085 HANDLE WINAPI FindFirstUrlCacheEntryExW(
3086 LPCWSTR lpszUrlSearchPattern,
3087 DWORD dwFlags,
3088 DWORD dwFilter,
3089 GROUPID GroupId,
3090 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3091 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3092 LPVOID lpReserved,
3093 LPDWORD pcbReserved2,
3094 LPVOID lpReserved3
3097 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
3098 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3099 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3100 SetLastError(ERROR_FILE_NOT_FOUND);
3101 return NULL;
3104 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3106 typedef struct URLCacheFindEntryHandle
3108 DWORD dwMagic;
3109 LPWSTR lpszUrlSearchPattern;
3110 DWORD dwContainerIndex;
3111 DWORD dwHashTableIndex;
3112 DWORD dwHashEntryIndex;
3113 } URLCacheFindEntryHandle;
3115 /***********************************************************************
3116 * FindFirstUrlCacheEntryA (WININET.@)
3119 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
3120 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3122 URLCacheFindEntryHandle *pEntryHandle;
3124 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3126 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3127 if (!pEntryHandle)
3128 return NULL;
3130 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3131 if (lpszUrlSearchPattern)
3133 int len = MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, NULL, 0);
3134 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3135 if (!pEntryHandle->lpszUrlSearchPattern)
3137 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3138 return NULL;
3140 MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, pEntryHandle->lpszUrlSearchPattern, len);
3142 else
3143 pEntryHandle->lpszUrlSearchPattern = NULL;
3144 pEntryHandle->dwContainerIndex = 0;
3145 pEntryHandle->dwHashTableIndex = 0;
3146 pEntryHandle->dwHashEntryIndex = 0;
3148 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3150 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3151 return NULL;
3153 return pEntryHandle;
3156 /***********************************************************************
3157 * FindFirstUrlCacheEntryW (WININET.@)
3160 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3161 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3163 URLCacheFindEntryHandle *pEntryHandle;
3165 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3167 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3168 if (!pEntryHandle)
3169 return NULL;
3171 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3172 if (lpszUrlSearchPattern)
3174 int len = strlenW(lpszUrlSearchPattern);
3175 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
3176 if (!pEntryHandle->lpszUrlSearchPattern)
3178 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3179 return NULL;
3181 memcpy(pEntryHandle->lpszUrlSearchPattern, lpszUrlSearchPattern, (len + 1) * sizeof(WCHAR));
3183 else
3184 pEntryHandle->lpszUrlSearchPattern = NULL;
3185 pEntryHandle->dwContainerIndex = 0;
3186 pEntryHandle->dwHashTableIndex = 0;
3187 pEntryHandle->dwHashEntryIndex = 0;
3189 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3191 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3192 return NULL;
3194 return pEntryHandle;
3197 /***********************************************************************
3198 * FindNextUrlCacheEntryA (WININET.@)
3200 BOOL WINAPI FindNextUrlCacheEntryA(
3201 HANDLE hEnumHandle,
3202 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3203 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3205 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3206 URLCACHECONTAINER * pContainer;
3208 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3210 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3212 SetLastError(ERROR_INVALID_HANDLE);
3213 return FALSE;
3216 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3217 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3219 LPURLCACHE_HEADER pHeader;
3220 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3221 DWORD error;
3223 error = URLCacheContainer_OpenIndex(pContainer);
3224 if (error != ERROR_SUCCESS)
3226 SetLastError(error);
3227 return FALSE;
3230 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3231 return FALSE;
3233 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3234 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3236 const struct _HASH_ENTRY *pHashEntry = NULL;
3237 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3238 pEntryHandle->dwHashEntryIndex++)
3240 const URL_CACHEFILE_ENTRY *pUrlEntry;
3241 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3243 if (pEntry->dwSignature != URL_SIGNATURE)
3244 continue;
3246 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3247 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3248 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3250 error = URLCache_CopyEntry(
3251 pContainer,
3252 pHeader,
3253 lpNextCacheEntryInfo,
3254 lpdwNextCacheEntryInfoBufferSize,
3255 pUrlEntry,
3256 FALSE /* not UNICODE */);
3257 if (error != ERROR_SUCCESS)
3259 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3260 SetLastError(error);
3261 return FALSE;
3263 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
3265 /* increment the current index so that next time the function
3266 * is called the next entry is returned */
3267 pEntryHandle->dwHashEntryIndex++;
3268 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3269 return TRUE;
3273 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3276 SetLastError(ERROR_NO_MORE_ITEMS);
3277 return FALSE;
3280 /***********************************************************************
3281 * FindNextUrlCacheEntryW (WININET.@)
3283 BOOL WINAPI FindNextUrlCacheEntryW(
3284 HANDLE hEnumHandle,
3285 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3286 LPDWORD lpdwNextCacheEntryInfoBufferSize
3289 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3290 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3291 return FALSE;
3294 /***********************************************************************
3295 * FindCloseUrlCache (WININET.@)
3297 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3299 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3301 TRACE("(%p)\n", hEnumHandle);
3303 if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3305 SetLastError(ERROR_INVALID_HANDLE);
3306 return FALSE;
3309 pEntryHandle->dwMagic = 0;
3310 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3311 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3313 return TRUE;
3316 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3317 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3319 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3320 dwSearchCondition, lpGroupId, lpReserved);
3321 return NULL;
3324 BOOL WINAPI FindNextUrlCacheEntryExA(
3325 HANDLE hEnumHandle,
3326 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3327 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3328 LPVOID lpReserved,
3329 LPDWORD pcbReserved2,
3330 LPVOID lpReserved3
3333 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3334 lpReserved, pcbReserved2, lpReserved3);
3335 return FALSE;
3338 BOOL WINAPI FindNextUrlCacheEntryExW(
3339 HANDLE hEnumHandle,
3340 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3341 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3342 LPVOID lpReserved,
3343 LPDWORD pcbReserved2,
3344 LPVOID lpReserved3
3347 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3348 lpReserved, pcbReserved2, lpReserved3);
3349 return FALSE;
3352 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3354 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3355 return FALSE;
3358 /***********************************************************************
3359 * CreateUrlCacheGroup (WININET.@)
3362 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3364 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3365 return FALSE;
3368 /***********************************************************************
3369 * DeleteUrlCacheGroup (WININET.@)
3372 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3374 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3375 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3376 return FALSE;
3379 /***********************************************************************
3380 * SetUrlCacheEntryGroupA (WININET.@)
3383 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3384 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3385 LPVOID lpReserved)
3387 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3388 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3389 pbGroupAttributes, cbGroupAttributes, lpReserved);
3390 SetLastError(ERROR_FILE_NOT_FOUND);
3391 return FALSE;
3394 /***********************************************************************
3395 * SetUrlCacheEntryGroupW (WININET.@)
3398 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3399 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3400 LPVOID lpReserved)
3402 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3403 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3404 pbGroupAttributes, cbGroupAttributes, lpReserved);
3405 SetLastError(ERROR_FILE_NOT_FOUND);
3406 return FALSE;
3409 /***********************************************************************
3410 * GetUrlCacheConfigInfoW (WININET.@)
3412 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3414 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3415 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3416 return FALSE;
3419 /***********************************************************************
3420 * GetUrlCacheConfigInfoA (WININET.@)
3422 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3424 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3426 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3427 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3428 return FALSE;
3431 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3432 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3433 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3435 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3436 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3437 lpdwGroupInfo, lpReserved);
3438 return FALSE;
3441 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3442 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3443 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3445 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3446 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3447 lpdwGroupInfo, lpReserved);
3448 return FALSE;
3451 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3452 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3454 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3455 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3456 return TRUE;
3459 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3460 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3462 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3463 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3464 return TRUE;
3467 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3469 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3470 return TRUE;
3473 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3475 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3476 return TRUE;
3479 /***********************************************************************
3480 * DeleteIE3Cache (WININET.@)
3482 * Deletes the files used by the IE3 URL caching system.
3484 * PARAMS
3485 * hWnd [I] A dummy window.
3486 * hInst [I] Instance of process calling the function.
3487 * lpszCmdLine [I] Options used by function.
3488 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3490 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3492 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3493 return 0;
3496 /***********************************************************************
3497 * IsUrlCacheEntryExpiredA (WININET.@)
3499 * PARAMS
3500 * url [I] Url
3501 * dwFlags [I] Unknown
3502 * pftLastModified [O] Last modified time
3504 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3506 LPURLCACHE_HEADER pHeader;
3507 struct _HASH_ENTRY * pHashEntry;
3508 const CACHEFILE_ENTRY * pEntry;
3509 const URL_CACHEFILE_ENTRY * pUrlEntry;
3510 URLCACHECONTAINER * pContainer;
3511 DWORD error;
3513 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3515 error = URLCacheContainers_FindContainerA(url, &pContainer);
3516 if (error != ERROR_SUCCESS)
3518 SetLastError(error);
3519 return FALSE;
3522 error = URLCacheContainer_OpenIndex(pContainer);
3523 if (error != ERROR_SUCCESS)
3525 SetLastError(error);
3526 return FALSE;
3529 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3530 return FALSE;
3532 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3534 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3535 TRACE("entry %s not found!\n", url);
3536 SetLastError(ERROR_FILE_NOT_FOUND);
3537 return FALSE;
3540 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3541 if (pEntry->dwSignature != URL_SIGNATURE)
3543 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3544 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3545 SetLastError(ERROR_FILE_NOT_FOUND);
3546 return FALSE;
3549 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3551 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3553 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3555 return TRUE;
3558 /***********************************************************************
3559 * IsUrlCacheEntryExpiredW (WININET.@)
3561 * PARAMS
3562 * url [I] Url
3563 * dwFlags [I] Unknown
3564 * pftLastModified [O] Last modified time
3566 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3568 LPURLCACHE_HEADER pHeader;
3569 struct _HASH_ENTRY * pHashEntry;
3570 const CACHEFILE_ENTRY * pEntry;
3571 const URL_CACHEFILE_ENTRY * pUrlEntry;
3572 URLCACHECONTAINER * pContainer;
3573 DWORD error;
3575 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3577 error = URLCacheContainers_FindContainerW(url, &pContainer);
3578 if (error != ERROR_SUCCESS)
3580 SetLastError(error);
3581 return FALSE;
3584 error = URLCacheContainer_OpenIndex(pContainer);
3585 if (error != ERROR_SUCCESS)
3587 SetLastError(error);
3588 return FALSE;
3591 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3592 return FALSE;
3594 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3596 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3597 TRACE("entry %s not found!\n", debugstr_w(url));
3598 SetLastError(ERROR_FILE_NOT_FOUND);
3599 return FALSE;
3602 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3603 if (pEntry->dwSignature != URL_SIGNATURE)
3605 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3606 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3607 SetLastError(ERROR_FILE_NOT_FOUND);
3608 return FALSE;
3611 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3613 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3615 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3617 return TRUE;
3620 /***********************************************************************
3621 * GetDiskInfoA (WININET.@)
3623 BOOL WINAPI GetDiskInfoA(PCSTR path, PDWORD cluster_size, PDWORDLONG free, PDWORDLONG total)
3625 BOOL ret;
3626 ULARGE_INTEGER bytes_free, bytes_total;
3628 TRACE("(%s, %p, %p, %p)\n", debugstr_a(path), cluster_size, free, total);
3630 if (!path)
3632 SetLastError(ERROR_INVALID_PARAMETER);
3633 return FALSE;
3636 if ((ret = GetDiskFreeSpaceExA(path, NULL, &bytes_total, &bytes_free)))
3638 if (cluster_size) *cluster_size = 1;
3639 if (free) *free = bytes_free.QuadPart;
3640 if (total) *total = bytes_total.QuadPart;
3642 return ret;
3645 /***********************************************************************
3646 * RegisterUrlCacheNotification (WININET.@)
3648 DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
3650 FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f);
3651 return 0;
3654 /***********************************************************************
3655 * IncrementUrlCacheHeaderData (WININET.@)
3657 BOOL WINAPI IncrementUrlCacheHeaderData(DWORD index, LPDWORD data)
3659 FIXME("(%u, %p)\n", index, data);
3660 return FALSE;