gdi32: PATH_ExtTextOut remove incorrect shift to DC origin.
[wine/hacks.git] / dlls / wininet / urlcache.c
blobbf67fecec03bc13b9699a18ecce2a8e5cfa25233
1 /*
2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003-2008 Robert Shearman
7 * Eric Kohl
8 * Aric Stewart
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
26 #include "wine/port.h"
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
31 #if defined(__MINGW32__) || defined (_MSC_VER)
32 #include <ws2tcpip.h>
33 #endif
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
42 #endif
43 #include <time.h>
45 #include "windef.h"
46 #include "winbase.h"
47 #include "winuser.h"
48 #include "wininet.h"
49 #include "winineti.h"
50 #include "winerror.h"
51 #include "internet.h"
52 #include "winreg.h"
53 #include "shlwapi.h"
54 #include "shlobj.h"
56 #include "wine/unicode.h"
57 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
61 #define ENTRY_START_OFFSET 0x4000
62 #define DIR_LENGTH 8
63 #define BLOCKSIZE 128
64 #define HASHTABLE_SIZE 448
65 #define HASHTABLE_BLOCKSIZE 7
66 #define HASHTABLE_FREE 3
67 #define ALLOCATION_TABLE_OFFSET 0x250
68 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
69 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
70 #define NEWFILE_NUM_BLOCKS 0xd80
71 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
73 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
74 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
75 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
76 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
77 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
79 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
81 typedef struct _CACHEFILE_ENTRY
83 /* union
84 {*/
85 DWORD dwSignature; /* e.g. "URL " */
86 /* CHAR szSignature[4];
87 };*/
88 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
89 } CACHEFILE_ENTRY;
91 typedef struct _URL_CACHEFILE_ENTRY
93 CACHEFILE_ENTRY CacheFileEntry;
94 FILETIME LastModifiedTime;
95 FILETIME LastAccessTime;
96 WORD wExpiredDate; /* expire date in dos format */
97 WORD wExpiredTime; /* expire time in dos format */
98 DWORD dwUnknown1; /* usually zero */
99 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
100 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
101 DWORD dwUnknown2; /* usually zero */
102 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
103 DWORD dwUnknown3; /* usually 0x60 */
104 DWORD dwOffsetUrl; /* offset of start of url from start of entry */
105 BYTE CacheDir; /* index of cache directory this url is stored in */
106 BYTE Unknown4; /* usually zero */
107 WORD wUnknown5; /* usually 0x1010 */
108 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
109 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
110 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
111 DWORD dwHeaderInfoSize;
112 DWORD dwOffsetFileExtension; /* offset of start of file extension from start of entry */
113 WORD wLastSyncDate; /* last sync date in dos format */
114 WORD wLastSyncTime; /* last sync time in dos format */
115 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
116 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
117 WORD wUnknownDate; /* usually same as wLastSyncDate */
118 WORD wUnknownTime; /* usually same as wLastSyncTime */
119 DWORD dwUnknown7; /* usually zero */
120 DWORD dwUnknown8; /* usually zero */
121 /* packing to dword align start of next field */
122 /* CHAR szSourceUrlName[]; (url) */
123 /* packing to dword align start of next field */
124 /* CHAR szLocalFileName[]; (local file name excluding path) */
125 /* packing to dword align start of next field */
126 /* CHAR szHeaderInfo[]; (header info) */
127 } URL_CACHEFILE_ENTRY;
129 struct _HASH_ENTRY
131 DWORD dwHashKey;
132 DWORD dwOffsetEntry;
135 typedef struct _HASH_CACHEFILE_ENTRY
137 CACHEFILE_ENTRY CacheFileEntry;
138 DWORD dwAddressNext;
139 DWORD dwHashTableNumber;
140 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
141 } HASH_CACHEFILE_ENTRY;
143 typedef struct _DIRECTORY_DATA
145 DWORD dwUnknown;
146 char filename[DIR_LENGTH];
147 } DIRECTORY_DATA;
149 typedef struct _URLCACHE_HEADER
151 char szSignature[28];
152 DWORD dwFileSize;
153 DWORD dwOffsetFirstHashTable;
154 DWORD dwIndexCapacityInBlocks;
155 DWORD dwBlocksInUse;
156 DWORD dwUnknown1;
157 DWORD dwCacheLimitLow; /* disk space limit for cache */
158 DWORD dwCacheLimitHigh; /* disk space limit for cache */
159 DWORD dwUnknown4; /* current disk space usage for cache */
160 DWORD dwUnknown5; /* current disk space usage for cache */
161 DWORD dwUnknown6; /* possibly a flag? */
162 DWORD dwUnknown7;
163 BYTE DirectoryCount; /* number of directory_data's */
164 BYTE Unknown8[3]; /* just padding? */
165 DIRECTORY_DATA directory_data[1]; /* first directory entry */
166 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
167 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
169 typedef struct _STREAM_HANDLE
171 HANDLE hFile;
172 CHAR lpszUrl[1];
173 } STREAM_HANDLE;
175 typedef struct _URLCACHECONTAINER
177 struct list entry; /* part of a list */
178 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
179 LPWSTR path; /* path to url container directory */
180 HANDLE hMapping; /* handle of file mapping */
181 DWORD file_size; /* size of file when mapping was opened */
182 HANDLE hMutex; /* handle of mutex */
183 } URLCACHECONTAINER;
186 /* List of all containers available */
187 static struct list UrlContainers = LIST_INIT(UrlContainers);
189 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash);
191 /***********************************************************************
192 * URLCache_PathToObjectName (Internal)
194 * Converts a path to a name suitable for use as a Win32 object name.
195 * Replaces '\\' characters in-place with the specified character
196 * (usually '_' or '!')
198 * RETURNS
199 * nothing
202 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
204 for (; *lpszPath; lpszPath++)
206 if (*lpszPath == '\\')
207 *lpszPath = replace;
211 /***********************************************************************
212 * URLCacheContainer_OpenIndex (Internal)
214 * Opens the index file and saves mapping handle in hCacheIndexMapping
216 * RETURNS
217 * ERROR_SUCCESS if succeeded
218 * Any other Win32 error code if failed
221 static DWORD URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
223 HANDLE hFile;
224 WCHAR wszFilePath[MAX_PATH];
225 DWORD dwFileSize;
227 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
228 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
230 if (pContainer->hMapping)
231 return ERROR_SUCCESS;
233 strcpyW(wszFilePath, pContainer->path);
234 strcatW(wszFilePath, wszIndex);
236 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
237 if (hFile == INVALID_HANDLE_VALUE)
239 /* Maybe the directory wasn't there? Try to create it */
240 if (CreateDirectoryW(pContainer->path, 0))
241 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
243 if (hFile == INVALID_HANDLE_VALUE)
245 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath));
246 return GetLastError();
249 /* At this stage we need the mutex because we may be about to create the
250 * file.
252 WaitForSingleObject(pContainer->hMutex, INFINITE);
254 dwFileSize = GetFileSize(hFile, NULL);
255 if (dwFileSize == INVALID_FILE_SIZE)
257 ReleaseMutex(pContainer->hMutex);
258 return GetLastError();
261 if (dwFileSize == 0)
263 static const CHAR szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content";
264 HKEY key;
265 char achZeroes[0x1000];
266 DWORD dwOffset;
267 DWORD dwError = ERROR_SUCCESS;
269 /* Write zeroes to the entire file so we can safely map it without
270 * fear of getting a SEGV because the disk is full.
272 memset(achZeroes, 0, sizeof(achZeroes));
273 for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes))
275 DWORD dwWrite = sizeof(achZeroes);
276 DWORD dwWritten;
278 if (NEWFILE_SIZE - dwOffset < dwWrite)
279 dwWrite = NEWFILE_SIZE - dwOffset;
280 if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) ||
281 dwWritten != dwWrite)
283 /* If we fail to write, we need to return the error that
284 * cause the problem and also make sure the file is no
285 * longer there, if possible.
287 dwError = GetLastError();
289 break;
293 if (dwError == ERROR_SUCCESS)
295 HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL);
297 if (hMapping)
299 URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE);
301 if (pHeader)
303 WCHAR *pwchDir;
304 WCHAR wszDirPath[MAX_PATH];
305 FILETIME ft;
306 int i, j;
307 HASH_CACHEFILE_ENTRY *pHashEntry;
309 dwFileSize = NEWFILE_SIZE;
311 /* First set some constants and defaults in the header */
312 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
313 pHeader->dwFileSize = dwFileSize;
314 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
315 /* 127MB - taken from default for Windows 2000 */
316 pHeader->dwCacheLimitHigh = 0;
317 pHeader->dwCacheLimitLow = 0x07ff5400;
318 /* Copied from a Windows 2000 cache index */
319 pHeader->DirectoryCount = 4;
321 /* If the registry has a cache size set, use the registry value */
322 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
324 DWORD dw;
325 DWORD len = sizeof(dw);
326 DWORD keytype;
328 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
329 (BYTE *) &dw, &len) == ERROR_SUCCESS &&
330 keytype == REG_DWORD)
332 pHeader->dwCacheLimitHigh = (dw >> 22);
333 pHeader->dwCacheLimitLow = dw << 10;
335 RegCloseKey(key);
338 URLCache_CreateHashTable(pHeader, NULL, &pHashEntry);
340 /* Last step - create the directories */
342 strcpyW(wszDirPath, pContainer->path);
343 pwchDir = wszDirPath + strlenW(wszDirPath);
344 pwchDir[8] = 0;
346 GetSystemTimeAsFileTime(&ft);
348 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
350 /* The following values were copied from a Windows index.
351 * I don't know what the values are supposed to mean but
352 * have made them the same in the hope that this will
353 * be better for compatibility
355 pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
356 for (j = 0;; ++j)
358 int k;
359 ULONGLONG n = ft.dwHighDateTime;
361 /* Generate a file name to attempt to create.
362 * This algorithm will create what will appear
363 * to be random and unrelated directory names
364 * of up to 9 characters in length.
366 n <<= 32;
367 n += ft.dwLowDateTime;
368 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
370 for (k = 0; k < 8; ++k)
372 int r = (n % 36);
374 /* Dividing by a prime greater than 36 helps
375 * with the appearance of randomness
377 n /= 37;
379 if (r < 10)
380 pwchDir[k] = '0' + r;
381 else
382 pwchDir[k] = 'A' + (r - 10);
385 if (CreateDirectoryW(wszDirPath, 0))
387 /* The following is OK because we generated an
388 * 8 character directory name made from characters
389 * [A-Z0-9], which are equivalent for all code
390 * pages and for UTF-16
392 for (k = 0; k < 8; ++k)
393 pHeader->directory_data[i].filename[k] = pwchDir[k];
394 break;
396 else if (j >= 255)
398 /* Give up. The most likely cause of this
399 * is a full disk, but whatever the cause
400 * is, it should be more than apparent that
401 * we won't succeed.
403 dwError = GetLastError();
404 break;
409 UnmapViewOfFile(pHeader);
411 else
413 dwError = GetLastError();
415 CloseHandle(hMapping);
417 else
419 dwError = GetLastError();
423 if (dwError)
425 CloseHandle(hFile);
426 DeleteFileW(wszFilePath);
427 ReleaseMutex(pContainer->hMutex);
428 return dwError;
433 ReleaseMutex(pContainer->hMutex);
435 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
436 URLCache_PathToObjectName(wszFilePath, '_');
437 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
438 if (!pContainer->hMapping)
439 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
440 CloseHandle(hFile);
441 if (!pContainer->hMapping)
443 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
444 return GetLastError();
447 return ERROR_SUCCESS;
450 /***********************************************************************
451 * URLCacheContainer_CloseIndex (Internal)
453 * Closes the index
455 * RETURNS
456 * nothing
459 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
461 CloseHandle(pContainer->hMapping);
462 pContainer->hMapping = NULL;
465 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
467 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
468 int path_len = strlenW(path);
469 int cache_prefix_len = strlenW(cache_prefix);
471 if (!pContainer)
473 return FALSE;
476 pContainer->hMapping = NULL;
477 pContainer->file_size = 0;
479 pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR));
480 if (!pContainer->path)
482 HeapFree(GetProcessHeap(), 0, pContainer);
483 return FALSE;
486 memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR));
488 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
489 if (!pContainer->cache_prefix)
491 HeapFree(GetProcessHeap(), 0, pContainer->path);
492 HeapFree(GetProcessHeap(), 0, pContainer);
493 return FALSE;
496 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
498 CharLowerW(mutex_name);
499 URLCache_PathToObjectName(mutex_name, '!');
501 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
503 ERR("couldn't create mutex (error is %d)\n", GetLastError());
504 HeapFree(GetProcessHeap(), 0, pContainer->path);
505 HeapFree(GetProcessHeap(), 0, pContainer);
506 return FALSE;
509 list_add_head(&UrlContainers, &pContainer->entry);
511 return TRUE;
514 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
516 list_remove(&pContainer->entry);
518 URLCacheContainer_CloseIndex(pContainer);
519 CloseHandle(pContainer->hMutex);
520 HeapFree(GetProcessHeap(), 0, pContainer->path);
521 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
522 HeapFree(GetProcessHeap(), 0, pContainer);
525 void URLCacheContainers_CreateDefaults(void)
527 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
528 static const WCHAR UrlPrefix[] = {0};
529 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
530 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
531 static const WCHAR CookieSuffix[] = {0};
532 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
533 static const struct
535 int nFolder; /* CSIDL_* constant */
536 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
537 const WCHAR * cache_prefix; /* prefix used to reference the container */
538 } DefaultContainerData[] =
540 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
541 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
542 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
544 DWORD i;
546 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
548 WCHAR wszCachePath[MAX_PATH];
549 WCHAR wszMutexName[MAX_PATH];
550 int path_len, suffix_len;
552 if (!SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE))
554 ERR("Couldn't get path for default container %u\n", i);
555 continue;
557 path_len = strlenW(wszCachePath);
558 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
560 if (path_len + suffix_len + 2 > MAX_PATH)
562 ERR("Path too long\n");
563 continue;
566 wszCachePath[path_len] = '\\';
567 wszCachePath[path_len+1] = 0;
569 strcpyW(wszMutexName, wszCachePath);
571 if (suffix_len)
573 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
574 wszCachePath[path_len + suffix_len + 1] = '\\';
575 wszCachePath[path_len + suffix_len + 2] = '\0';
578 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
582 void URLCacheContainers_DeleteAll(void)
584 while(!list_empty(&UrlContainers))
585 URLCacheContainer_DeleteContainer(
586 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
590 static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
592 URLCACHECONTAINER * pContainer;
594 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
596 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
598 int prefix_len = strlenW(pContainer->cache_prefix);
599 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
601 TRACE("found container with prefix %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
602 *ppContainer = pContainer;
603 return ERROR_SUCCESS;
606 ERR("no container found\n");
607 return ERROR_FILE_NOT_FOUND;
610 static DWORD URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
612 DWORD ret;
613 LPWSTR lpwszUrl;
614 int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
615 if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR))))
617 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len);
618 ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer);
619 HeapFree(GetProcessHeap(), 0, lpwszUrl);
620 return ret;
622 return GetLastError();
625 static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, URLCACHECONTAINER ** ppContainer)
627 DWORD i = 0;
628 URLCACHECONTAINER * pContainer;
630 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern));
632 /* non-NULL search pattern only returns one container ever */
633 if (lpwszSearchPattern && dwIndex > 0)
634 return FALSE;
636 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
638 if (lpwszSearchPattern)
640 if (!strcmpW(pContainer->cache_prefix, lpwszSearchPattern))
642 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
643 *ppContainer = pContainer;
644 return TRUE;
647 else
649 if (i == dwIndex)
651 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
652 *ppContainer = pContainer;
653 return TRUE;
656 i++;
658 return FALSE;
661 /***********************************************************************
662 * URLCacheContainer_LockIndex (Internal)
664 * Locks the index for system-wide exclusive access.
666 * RETURNS
667 * Cache file header if successful
668 * NULL if failed and calls SetLastError.
670 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
672 BYTE index;
673 LPVOID pIndexData;
674 URLCACHE_HEADER * pHeader;
675 DWORD error;
677 /* acquire mutex */
678 WaitForSingleObject(pContainer->hMutex, INFINITE);
680 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
682 if (!pIndexData)
684 ReleaseMutex(pContainer->hMutex);
685 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
686 return NULL;
688 pHeader = (URLCACHE_HEADER *)pIndexData;
690 /* file has grown - we need to remap to prevent us getting
691 * access violations when we try and access beyond the end
692 * of the memory mapped file */
693 if (pHeader->dwFileSize != pContainer->file_size)
695 URLCacheContainer_CloseIndex(pContainer);
696 error = URLCacheContainer_OpenIndex(pContainer);
697 if (error != ERROR_SUCCESS)
699 ReleaseMutex(pContainer->hMutex);
700 SetLastError(error);
701 return NULL;
703 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
705 if (!pIndexData)
707 ReleaseMutex(pContainer->hMutex);
708 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
709 return NULL;
711 pHeader = (URLCACHE_HEADER *)pIndexData;
714 TRACE("Signature: %s, file size: %d bytes\n", pHeader->szSignature, pHeader->dwFileSize);
716 for (index = 0; index < pHeader->DirectoryCount; index++)
718 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
721 return pHeader;
724 /***********************************************************************
725 * URLCacheContainer_UnlockIndex (Internal)
728 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
730 /* release mutex */
731 ReleaseMutex(pContainer->hMutex);
732 return UnmapViewOfFile(pHeader);
736 #ifndef CHAR_BIT
737 #define CHAR_BIT (8 * sizeof(CHAR))
738 #endif
740 /***********************************************************************
741 * URLCache_Allocation_BlockIsFree (Internal)
743 * Is the specified block number free?
745 * RETURNS
746 * zero if free
747 * non-zero otherwise
750 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
752 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
753 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
756 /***********************************************************************
757 * URLCache_Allocation_BlockFree (Internal)
759 * Marks the specified block as free
761 * RETURNS
762 * nothing
765 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
767 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
768 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
771 /***********************************************************************
772 * URLCache_Allocation_BlockAllocate (Internal)
774 * Marks the specified block as allocated
776 * RETURNS
777 * nothing
780 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
782 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
783 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
786 /***********************************************************************
787 * URLCache_FindFirstFreeEntry (Internal)
789 * Finds and allocates the first block of free space big enough and
790 * sets ppEntry to point to it.
792 * RETURNS
793 * TRUE if it had enough space
794 * FALSE if it couldn't find enough space
797 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
799 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
800 DWORD dwBlockNumber;
801 DWORD dwFreeCounter;
802 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
804 for (dwFreeCounter = 0;
805 dwFreeCounter < dwBlocksNeeded &&
806 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
807 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
808 dwFreeCounter++)
809 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
811 if (dwFreeCounter == dwBlocksNeeded)
813 DWORD index;
814 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
815 for (index = 0; index < dwBlocksNeeded; index++)
816 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
817 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
818 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
819 return TRUE;
822 FIXME("Grow file\n");
823 return FALSE;
826 /***********************************************************************
827 * URLCache_DeleteEntry (Internal)
829 * Deletes the specified entry and frees the space allocated to it
831 * RETURNS
832 * TRUE if it succeeded
833 * FALSE if it failed
836 static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, CACHEFILE_ENTRY * pEntry)
838 DWORD dwStartBlock;
839 DWORD dwBlock;
840 BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
842 /* update allocation table */
843 dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE;
844 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
845 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
847 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
848 return TRUE;
851 /***********************************************************************
852 * URLCache_LocalFileNameToPathW (Internal)
854 * Copies the full path to the specified buffer given the local file
855 * name and the index of the directory it is in. Always sets value in
856 * lpBufferSize to the required buffer size (in bytes).
858 * RETURNS
859 * TRUE if the buffer was big enough
860 * FALSE if the buffer was too small
863 static BOOL URLCache_LocalFileNameToPathW(
864 const URLCACHECONTAINER * pContainer,
865 LPCURLCACHE_HEADER pHeader,
866 LPCSTR szLocalFileName,
867 BYTE Directory,
868 LPWSTR wszPath,
869 LPLONG lpBufferSize)
871 LONG nRequired;
872 int path_len = strlenW(pContainer->path);
873 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
874 if (Directory >= pHeader->DirectoryCount)
876 *lpBufferSize = 0;
877 return FALSE;
880 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
881 if (nRequired < *lpBufferSize)
883 int dir_len;
885 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
886 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
887 wszPath[dir_len + path_len] = '\\';
888 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
889 *lpBufferSize = nRequired;
890 return TRUE;
892 *lpBufferSize = nRequired;
893 return FALSE;
896 /***********************************************************************
897 * URLCache_LocalFileNameToPathA (Internal)
899 * Copies the full path to the specified buffer given the local file
900 * name and the index of the directory it is in. Always sets value in
901 * lpBufferSize to the required buffer size.
903 * RETURNS
904 * TRUE if the buffer was big enough
905 * FALSE if the buffer was too small
908 static BOOL URLCache_LocalFileNameToPathA(
909 const URLCACHECONTAINER * pContainer,
910 LPCURLCACHE_HEADER pHeader,
911 LPCSTR szLocalFileName,
912 BYTE Directory,
913 LPSTR szPath,
914 LPLONG lpBufferSize)
916 LONG nRequired;
917 int path_len, file_name_len, dir_len;
919 if (Directory >= pHeader->DirectoryCount)
921 *lpBufferSize = 0;
922 return FALSE;
925 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL) - 1;
926 file_name_len = strlen(szLocalFileName) + 1 /* for nul-terminator */;
927 dir_len = DIR_LENGTH;
929 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(char);
930 if (nRequired < *lpBufferSize)
932 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, path_len, NULL, NULL);
933 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
934 szPath[path_len + dir_len] = '\\';
935 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
936 *lpBufferSize = nRequired;
937 return TRUE;
939 *lpBufferSize = nRequired;
940 return FALSE;
943 /***********************************************************************
944 * URLCache_CopyEntry (Internal)
946 * Copies an entry from the cache index file to the Win32 structure
948 * RETURNS
949 * ERROR_SUCCESS if the buffer was big enough
950 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
953 static DWORD URLCache_CopyEntry(
954 URLCACHECONTAINER * pContainer,
955 LPCURLCACHE_HEADER pHeader,
956 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
957 LPDWORD lpdwBufferSize,
958 const URL_CACHEFILE_ENTRY * pUrlEntry,
959 BOOL bUnicode)
961 int lenUrl;
962 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
964 if (*lpdwBufferSize >= dwRequiredSize)
966 lpCacheEntryInfo->lpHeaderInfo = NULL;
967 lpCacheEntryInfo->lpszFileExtension = NULL;
968 lpCacheEntryInfo->lpszLocalFileName = NULL;
969 lpCacheEntryInfo->lpszSourceUrlName = NULL;
970 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
971 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
972 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
973 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
974 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
975 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
976 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
977 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
978 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
979 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
980 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
981 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
982 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
983 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
986 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
987 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
988 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
989 if (bUnicode)
990 lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0);
991 else
992 lenUrl = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
993 dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
995 /* FIXME: is source url optional? */
996 if (*lpdwBufferSize >= dwRequiredSize)
998 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrl - 1;
999 if (bUnicode)
1000 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
1001 else
1002 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, (lenUrl + 1) * sizeof(CHAR));
1005 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1006 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1007 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1009 if (pUrlEntry->dwOffsetLocalName)
1011 LONG nLocalFilePathSize;
1012 LPSTR lpszLocalFileName;
1013 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
1014 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
1015 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
1016 (!bUnicode && URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize)))
1018 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
1020 dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ;
1022 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1023 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1024 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1026 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
1028 if (*lpdwBufferSize >= dwRequiredSize)
1030 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
1031 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
1032 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
1034 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1035 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1036 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1038 if (pUrlEntry->dwOffsetFileExtension)
1040 int lenExtension;
1042 if (bUnicode)
1043 lenExtension = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, NULL, 0);
1044 else
1045 lenExtension = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension) + 1;
1046 dwRequiredSize += lenExtension * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
1048 if (*lpdwBufferSize >= dwRequiredSize)
1050 lpCacheEntryInfo->lpszFileExtension = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenExtension;
1051 if (bUnicode)
1052 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenExtension);
1053 else
1054 memcpy(lpCacheEntryInfo->lpszFileExtension, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, lenExtension * sizeof(CHAR));
1057 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1058 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1059 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1062 if (dwRequiredSize > *lpdwBufferSize)
1064 *lpdwBufferSize = dwRequiredSize;
1065 return ERROR_INSUFFICIENT_BUFFER;
1067 *lpdwBufferSize = dwRequiredSize;
1068 return ERROR_SUCCESS;
1072 /***********************************************************************
1073 * URLCache_SetEntryInfo (Internal)
1075 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1076 * according to the flags set by dwFieldControl.
1078 * RETURNS
1079 * ERROR_SUCCESS if the buffer was big enough
1080 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1083 static DWORD URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1085 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1086 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1087 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1088 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1089 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1090 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1091 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1092 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1093 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1094 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1095 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1096 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1097 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1098 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1099 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1100 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1102 return ERROR_SUCCESS;
1105 /***********************************************************************
1106 * URLCache_HashKey (Internal)
1108 * Returns the hash key for a given string
1110 * RETURNS
1111 * hash key for the string
1114 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1116 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1117 * but the algorithm and result are not the same!
1119 static const unsigned char lookupTable[256] =
1121 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1122 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1123 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1124 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1125 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1126 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1127 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1128 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1129 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1130 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1131 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1132 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1133 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1134 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1135 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1136 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1137 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1138 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1139 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1140 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1141 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1142 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1143 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1144 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1145 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1146 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1147 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1148 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1149 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1150 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1151 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1152 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1154 BYTE key[4];
1155 DWORD i;
1157 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1158 key[i] = lookupTable[i];
1160 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
1162 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1163 key[i] = lookupTable[*lpszKey ^ key[i]];
1166 return *(DWORD *)key;
1169 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
1171 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
1174 static inline BOOL URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY *pHashEntry)
1176 /* check pHashEntry located within acceptable bounds in the URL cache mapping */
1177 return ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) &&
1178 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1181 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1183 /* structure of hash table:
1184 * 448 entries divided into 64 blocks
1185 * each block therefore contains a chain of 7 key/offset pairs
1186 * how position in table is calculated:
1187 * 1. the url is hashed in helper function
1188 * 2. the key % 64 * 8 is the offset
1189 * 3. the key in the hash table is the hash key aligned to 64
1191 * note:
1192 * there can be multiple hash tables in the file and the offset to
1193 * the next one is stored in the header of the hash table
1195 DWORD key = URLCache_HashKey(lpszUrl);
1196 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1197 HASH_CACHEFILE_ENTRY * pHashEntry;
1198 DWORD dwHashTableNumber = 0;
1200 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1202 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1203 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1204 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1206 int i;
1207 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1209 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1210 continue;
1212 /* make sure that it is in fact a hash entry */
1213 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1215 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1216 continue;
1219 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1221 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1222 if (key == (pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
1224 /* FIXME: we should make sure that this is the right element
1225 * before returning and claiming that it is. We can do this
1226 * by doing a simple compare between the URL we were given
1227 * and the URL stored in the entry. However, this assumes
1228 * we know the format of all the entries stored in the
1229 * hash table */
1230 *ppHashEntry = pHashElement;
1231 return TRUE;
1235 return FALSE;
1238 static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1240 LPSTR urlA;
1241 int url_len;
1242 BOOL ret;
1244 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1245 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1246 if (!urlA)
1248 SetLastError(ERROR_OUTOFMEMORY);
1249 return FALSE;
1251 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, urlA, url_len, NULL, NULL);
1252 ret = URLCache_FindHash(pHeader, urlA, ppHashEntry);
1253 HeapFree(GetProcessHeap(), 0, urlA);
1254 return ret;
1257 /***********************************************************************
1258 * URLCache_HashEntrySetUse (Internal)
1260 * Searches all the hash tables in the index for the given URL and
1261 * sets the use count (stored or'ed with key)
1263 * RETURNS
1264 * TRUE if the entry was found
1265 * FALSE if the entry could not be found
1268 static BOOL URLCache_HashEntrySetUse(struct _HASH_ENTRY * pHashEntry, DWORD dwUseCount)
1270 pHashEntry->dwHashKey = dwUseCount | (pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1271 return TRUE;
1274 /***********************************************************************
1275 * URLCache_DeleteEntryFromHash (Internal)
1277 * Searches all the hash tables in the index for the given URL and
1278 * then if found deletes the entry.
1280 * RETURNS
1281 * TRUE if the entry was found
1282 * FALSE if the entry could not be found
1285 static BOOL URLCache_DeleteEntryFromHash(struct _HASH_ENTRY * pHashEntry)
1287 pHashEntry->dwHashKey = HASHTABLE_FREE;
1288 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1289 return TRUE;
1292 /***********************************************************************
1293 * URLCache_AddEntryToHash (Internal)
1295 * Searches all the hash tables for a free slot based on the offset
1296 * generated from the hash key. If a free slot is found, the offset and
1297 * key are entered into the hash table.
1299 * RETURNS
1300 * ERROR_SUCCESS if the entry was added
1301 * Any other Win32 error code if the entry could not be added
1304 static DWORD URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1306 /* see URLCache_FindEntryInHash for structure of hash tables */
1308 DWORD key = URLCache_HashKey(lpszUrl);
1309 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1310 HASH_CACHEFILE_ENTRY * pHashEntry;
1311 DWORD dwHashTableNumber = 0;
1312 DWORD error;
1314 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1316 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1317 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1318 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1320 int i;
1321 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1323 ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1324 break;
1326 /* make sure that it is in fact a hash entry */
1327 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1329 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1330 break;
1333 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1335 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1336 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1338 pHashElement->dwHashKey = key;
1339 pHashElement->dwOffsetEntry = dwOffsetEntry;
1340 return ERROR_SUCCESS;
1344 error = URLCache_CreateHashTable(pHeader, pHashEntry, &pHashEntry);
1345 if (error != ERROR_SUCCESS)
1346 return error;
1348 pHashEntry->HashTable[offset].dwHashKey = key;
1349 pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry;
1350 return ERROR_SUCCESS;
1353 /***********************************************************************
1354 * URLCache_CreateHashTable (Internal)
1356 * Creates a new hash table in free space and adds it to the chain of existing
1357 * hash tables.
1359 * RETURNS
1360 * ERROR_SUCCESS if the hash table was created
1361 * ERROR_DISK_FULL if the hash table could not be created
1364 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash)
1366 DWORD dwOffset;
1367 int i;
1369 if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)ppHash))
1371 FIXME("no free space for hash table\n");
1372 return ERROR_DISK_FULL;
1375 dwOffset = (BYTE *)*ppHash - (BYTE *)pHeader;
1377 if (pPrevHash)
1378 pPrevHash->dwAddressNext = dwOffset;
1379 else
1380 pHeader->dwOffsetFirstHashTable = dwOffset;
1381 (*ppHash)->CacheFileEntry.dwSignature = HASH_SIGNATURE;
1382 (*ppHash)->CacheFileEntry.dwBlocksUsed = 0x20;
1383 (*ppHash)->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0;
1384 for (i = 0; i < HASHTABLE_SIZE; i++)
1386 (*ppHash)->HashTable[i].dwOffsetEntry = 0;
1387 (*ppHash)->HashTable[i].dwHashKey = HASHTABLE_FREE;
1389 return ERROR_SUCCESS;
1392 /***********************************************************************
1393 * URLCache_EnumHashTables (Internal)
1395 * Enumerates the hash tables in a container.
1397 * RETURNS
1398 * TRUE if an entry was found
1399 * FALSE if there are no more tables to enumerate.
1402 static BOOL URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader, DWORD *pdwHashTableNumber, HASH_CACHEFILE_ENTRY ** ppHashEntry)
1404 for (*ppHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1405 URLCache_IsHashEntryValid(pHeader, *ppHashEntry);
1406 *ppHashEntry = URLCache_HashEntryFromOffset(pHeader, (*ppHashEntry)->dwAddressNext))
1408 TRACE("looking at hash table number %d\n", (*ppHashEntry)->dwHashTableNumber);
1409 if ((*ppHashEntry)->dwHashTableNumber != *pdwHashTableNumber)
1410 continue;
1411 /* make sure that it is in fact a hash entry */
1412 if ((*ppHashEntry)->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1414 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&(*ppHashEntry)->CacheFileEntry.dwSignature);
1415 (*pdwHashTableNumber)++;
1416 continue;
1419 TRACE("hash table number %d found\n", *pdwHashTableNumber);
1420 return TRUE;
1422 return FALSE;
1425 /***********************************************************************
1426 * URLCache_EnumHashTableEntries (Internal)
1428 * Enumerates entries in a hash table and returns the next non-free entry.
1430 * RETURNS
1431 * TRUE if an entry was found
1432 * FALSE if the hash table is empty or there are no more entries to
1433 * enumerate.
1436 static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY * pHashEntry,
1437 DWORD * index, const struct _HASH_ENTRY ** ppHashEntry)
1439 for (; *index < HASHTABLE_SIZE ; (*index)++)
1441 if (pHashEntry->HashTable[*index].dwHashKey == HASHTABLE_FREE)
1442 continue;
1444 *ppHashEntry = &pHashEntry->HashTable[*index];
1445 TRACE("entry found %d\n", *index);
1446 return TRUE;
1448 TRACE("no more entries (%d)\n", *index);
1449 return FALSE;
1452 /***********************************************************************
1453 * GetUrlCacheEntryInfoExA (WININET.@)
1456 BOOL WINAPI GetUrlCacheEntryInfoExA(
1457 LPCSTR lpszUrl,
1458 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1459 LPDWORD lpdwCacheEntryInfoBufSize,
1460 LPSTR lpszReserved,
1461 LPDWORD lpdwReserved,
1462 LPVOID lpReserved,
1463 DWORD dwFlags)
1465 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1466 debugstr_a(lpszUrl),
1467 lpCacheEntryInfo,
1468 lpdwCacheEntryInfoBufSize,
1469 lpszReserved,
1470 lpdwReserved,
1471 lpReserved,
1472 dwFlags);
1474 if ((lpszReserved != NULL) ||
1475 (lpdwReserved != NULL) ||
1476 (lpReserved != NULL))
1478 ERR("Reserved value was not 0\n");
1479 SetLastError(ERROR_INVALID_PARAMETER);
1480 return FALSE;
1482 if (dwFlags != 0)
1483 FIXME("Undocumented flag(s): %x\n", dwFlags);
1484 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1487 /***********************************************************************
1488 * GetUrlCacheEntryInfoA (WININET.@)
1491 BOOL WINAPI GetUrlCacheEntryInfoA(
1492 IN LPCSTR lpszUrlName,
1493 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1494 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1497 LPURLCACHE_HEADER pHeader;
1498 struct _HASH_ENTRY * pHashEntry;
1499 const CACHEFILE_ENTRY * pEntry;
1500 const URL_CACHEFILE_ENTRY * pUrlEntry;
1501 URLCACHECONTAINER * pContainer;
1502 DWORD error;
1504 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1506 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1507 if (error != ERROR_SUCCESS)
1509 SetLastError(error);
1510 return FALSE;
1513 error = URLCacheContainer_OpenIndex(pContainer);
1514 if (error != ERROR_SUCCESS)
1516 SetLastError(error);
1517 return FALSE;
1520 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1521 return FALSE;
1523 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1525 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1526 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1527 SetLastError(ERROR_FILE_NOT_FOUND);
1528 return FALSE;
1531 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1532 if (pEntry->dwSignature != URL_SIGNATURE)
1534 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1535 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1536 SetLastError(ERROR_FILE_NOT_FOUND);
1537 return FALSE;
1540 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1541 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1542 if (pUrlEntry->dwOffsetHeaderInfo)
1543 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1545 if (lpdwCacheEntryInfoBufferSize)
1547 if (!lpCacheEntryInfo)
1548 *lpdwCacheEntryInfoBufferSize = 0;
1550 error = URLCache_CopyEntry(
1551 pContainer,
1552 pHeader,
1553 lpCacheEntryInfo,
1554 lpdwCacheEntryInfoBufferSize,
1555 pUrlEntry,
1556 FALSE /* ANSI */);
1557 if (error != ERROR_SUCCESS)
1559 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1560 SetLastError(error);
1561 return FALSE;
1563 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1566 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1568 return TRUE;
1571 /***********************************************************************
1572 * GetUrlCacheEntryInfoW (WININET.@)
1575 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1576 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1577 LPDWORD lpdwCacheEntryInfoBufferSize)
1579 LPURLCACHE_HEADER pHeader;
1580 struct _HASH_ENTRY * pHashEntry;
1581 const CACHEFILE_ENTRY * pEntry;
1582 const URL_CACHEFILE_ENTRY * pUrlEntry;
1583 URLCACHECONTAINER * pContainer;
1584 DWORD error;
1586 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1588 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1589 if (error != ERROR_SUCCESS)
1591 SetLastError(error);
1592 return FALSE;
1595 error = URLCacheContainer_OpenIndex(pContainer);
1596 if (error != ERROR_SUCCESS)
1598 SetLastError(error);
1599 return FALSE;
1602 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1603 return FALSE;
1605 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1607 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1608 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1609 SetLastError(ERROR_FILE_NOT_FOUND);
1610 return FALSE;
1613 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1614 if (pEntry->dwSignature != URL_SIGNATURE)
1616 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1617 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1618 SetLastError(ERROR_FILE_NOT_FOUND);
1619 return FALSE;
1622 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1623 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1624 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1626 if (lpdwCacheEntryInfoBufferSize)
1628 if (!lpCacheEntryInfo)
1629 *lpdwCacheEntryInfoBufferSize = 0;
1631 error = URLCache_CopyEntry(
1632 pContainer,
1633 pHeader,
1634 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1635 lpdwCacheEntryInfoBufferSize,
1636 pUrlEntry,
1637 TRUE /* UNICODE */);
1638 if (error != ERROR_SUCCESS)
1640 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1641 SetLastError(error);
1642 return FALSE;
1644 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1647 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1649 return TRUE;
1652 /***********************************************************************
1653 * GetUrlCacheEntryInfoExW (WININET.@)
1656 BOOL WINAPI GetUrlCacheEntryInfoExW(
1657 LPCWSTR lpszUrl,
1658 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1659 LPDWORD lpdwCacheEntryInfoBufSize,
1660 LPWSTR lpszReserved,
1661 LPDWORD lpdwReserved,
1662 LPVOID lpReserved,
1663 DWORD dwFlags)
1665 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1666 debugstr_w(lpszUrl),
1667 lpCacheEntryInfo,
1668 lpdwCacheEntryInfoBufSize,
1669 lpszReserved,
1670 lpdwReserved,
1671 lpReserved,
1672 dwFlags);
1674 if ((lpszReserved != NULL) ||
1675 (lpdwReserved != NULL) ||
1676 (lpReserved != NULL))
1678 ERR("Reserved value was not 0\n");
1679 SetLastError(ERROR_INVALID_PARAMETER);
1680 return FALSE;
1682 if (dwFlags != 0)
1683 FIXME("Undocumented flag(s): %x\n", dwFlags);
1684 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1687 /***********************************************************************
1688 * SetUrlCacheEntryInfoA (WININET.@)
1690 BOOL WINAPI SetUrlCacheEntryInfoA(
1691 LPCSTR lpszUrlName,
1692 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1693 DWORD dwFieldControl)
1695 LPURLCACHE_HEADER pHeader;
1696 struct _HASH_ENTRY * pHashEntry;
1697 CACHEFILE_ENTRY * pEntry;
1698 URLCACHECONTAINER * pContainer;
1699 DWORD error;
1701 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1703 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1704 if (error != ERROR_SUCCESS)
1706 SetLastError(error);
1707 return FALSE;
1710 error = URLCacheContainer_OpenIndex(pContainer);
1711 if (error != ERROR_SUCCESS)
1713 SetLastError(error);
1714 return FALSE;
1717 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1718 return FALSE;
1720 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1722 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1723 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1724 SetLastError(ERROR_FILE_NOT_FOUND);
1725 return FALSE;
1728 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1729 if (pEntry->dwSignature != URL_SIGNATURE)
1731 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1732 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1733 SetLastError(ERROR_FILE_NOT_FOUND);
1734 return FALSE;
1737 URLCache_SetEntryInfo(
1738 (URL_CACHEFILE_ENTRY *)pEntry,
1739 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1740 dwFieldControl);
1742 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1744 return TRUE;
1747 /***********************************************************************
1748 * SetUrlCacheEntryInfoW (WININET.@)
1750 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1752 LPURLCACHE_HEADER pHeader;
1753 struct _HASH_ENTRY * pHashEntry;
1754 CACHEFILE_ENTRY * pEntry;
1755 URLCACHECONTAINER * pContainer;
1756 DWORD error;
1758 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1760 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1761 if (error != ERROR_SUCCESS)
1763 SetLastError(error);
1764 return FALSE;
1767 error = URLCacheContainer_OpenIndex(pContainer);
1768 if (error != ERROR_SUCCESS)
1770 SetLastError(error);
1771 return FALSE;
1774 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1775 return FALSE;
1777 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1779 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1780 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1781 SetLastError(ERROR_FILE_NOT_FOUND);
1782 return FALSE;
1785 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1786 if (pEntry->dwSignature != URL_SIGNATURE)
1788 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1789 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1790 SetLastError(ERROR_FILE_NOT_FOUND);
1791 return FALSE;
1794 URLCache_SetEntryInfo(
1795 (URL_CACHEFILE_ENTRY *)pEntry,
1796 lpCacheEntryInfo,
1797 dwFieldControl);
1799 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1801 return TRUE;
1804 /***********************************************************************
1805 * RetrieveUrlCacheEntryFileA (WININET.@)
1808 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1809 IN LPCSTR lpszUrlName,
1810 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1811 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1812 IN DWORD dwReserved
1815 LPURLCACHE_HEADER pHeader;
1816 struct _HASH_ENTRY * pHashEntry;
1817 CACHEFILE_ENTRY * pEntry;
1818 URL_CACHEFILE_ENTRY * pUrlEntry;
1819 URLCACHECONTAINER * pContainer;
1820 DWORD error;
1822 TRACE("(%s, %p, %p, 0x%08x)\n",
1823 debugstr_a(lpszUrlName),
1824 lpCacheEntryInfo,
1825 lpdwCacheEntryInfoBufferSize,
1826 dwReserved);
1828 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1829 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1831 SetLastError(ERROR_INVALID_PARAMETER);
1832 return FALSE;
1835 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1836 if (error != ERROR_SUCCESS)
1838 SetLastError(error);
1839 return FALSE;
1842 error = URLCacheContainer_OpenIndex(pContainer);
1843 if (error != ERROR_SUCCESS)
1845 SetLastError(error);
1846 return FALSE;
1849 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1850 return FALSE;
1852 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1854 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1855 TRACE("entry %s not found!\n", lpszUrlName);
1856 SetLastError(ERROR_FILE_NOT_FOUND);
1857 return FALSE;
1860 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1861 if (pEntry->dwSignature != URL_SIGNATURE)
1863 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1864 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1865 SetLastError(ERROR_FILE_NOT_FOUND);
1866 return FALSE;
1869 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1870 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1871 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1873 pUrlEntry->dwHitRate++;
1874 pUrlEntry->dwUseCount++;
1875 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1877 error = URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo,
1878 lpdwCacheEntryInfoBufferSize, pUrlEntry,
1879 FALSE);
1880 if (error != ERROR_SUCCESS)
1882 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1883 SetLastError(error);
1884 return FALSE;
1886 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1888 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1890 return TRUE;
1893 /***********************************************************************
1894 * RetrieveUrlCacheEntryFileW (WININET.@)
1897 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1898 IN LPCWSTR lpszUrlName,
1899 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1900 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1901 IN DWORD dwReserved
1904 LPURLCACHE_HEADER pHeader;
1905 struct _HASH_ENTRY * pHashEntry;
1906 CACHEFILE_ENTRY * pEntry;
1907 URL_CACHEFILE_ENTRY * pUrlEntry;
1908 URLCACHECONTAINER * pContainer;
1909 DWORD error;
1911 TRACE("(%s, %p, %p, 0x%08x)\n",
1912 debugstr_w(lpszUrlName),
1913 lpCacheEntryInfo,
1914 lpdwCacheEntryInfoBufferSize,
1915 dwReserved);
1917 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1918 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1920 SetLastError(ERROR_INVALID_PARAMETER);
1921 return FALSE;
1924 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
1925 if (error != ERROR_SUCCESS)
1927 SetLastError(error);
1928 return FALSE;
1931 error = URLCacheContainer_OpenIndex(pContainer);
1932 if (error != ERROR_SUCCESS)
1934 SetLastError(error);
1935 return FALSE;
1938 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1939 return FALSE;
1941 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1943 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1944 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1945 SetLastError(ERROR_FILE_NOT_FOUND);
1946 return FALSE;
1949 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1950 if (pEntry->dwSignature != URL_SIGNATURE)
1952 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1953 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1954 SetLastError(ERROR_FILE_NOT_FOUND);
1955 return FALSE;
1958 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1959 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1960 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1962 pUrlEntry->dwHitRate++;
1963 pUrlEntry->dwUseCount++;
1964 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1966 error = URLCache_CopyEntry(
1967 pContainer,
1968 pHeader,
1969 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1970 lpdwCacheEntryInfoBufferSize,
1971 pUrlEntry,
1972 TRUE /* UNICODE */);
1973 if (error != ERROR_SUCCESS)
1975 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1976 SetLastError(error);
1977 return FALSE;
1979 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1981 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1983 return TRUE;
1986 /***********************************************************************
1987 * UnlockUrlCacheEntryFileA (WININET.@)
1990 BOOL WINAPI UnlockUrlCacheEntryFileA(
1991 IN LPCSTR lpszUrlName,
1992 IN DWORD dwReserved
1995 LPURLCACHE_HEADER pHeader;
1996 struct _HASH_ENTRY * pHashEntry;
1997 CACHEFILE_ENTRY * pEntry;
1998 URL_CACHEFILE_ENTRY * pUrlEntry;
1999 URLCACHECONTAINER * pContainer;
2000 DWORD error;
2002 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
2004 if (dwReserved)
2006 ERR("dwReserved != 0\n");
2007 SetLastError(ERROR_INVALID_PARAMETER);
2008 return FALSE;
2011 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2012 if (error != ERROR_SUCCESS)
2014 SetLastError(error);
2015 return FALSE;
2018 error = URLCacheContainer_OpenIndex(pContainer);
2019 if (error != ERROR_SUCCESS)
2021 SetLastError(error);
2022 return FALSE;
2025 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2026 return FALSE;
2028 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2030 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2031 TRACE("entry %s not found!\n", lpszUrlName);
2032 SetLastError(ERROR_FILE_NOT_FOUND);
2033 return FALSE;
2036 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2037 if (pEntry->dwSignature != URL_SIGNATURE)
2039 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2040 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2041 SetLastError(ERROR_FILE_NOT_FOUND);
2042 return FALSE;
2045 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2047 if (pUrlEntry->dwUseCount == 0)
2049 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2050 return FALSE;
2052 pUrlEntry->dwUseCount--;
2053 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2055 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2057 return TRUE;
2060 /***********************************************************************
2061 * UnlockUrlCacheEntryFileW (WININET.@)
2064 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
2066 LPURLCACHE_HEADER pHeader;
2067 struct _HASH_ENTRY * pHashEntry;
2068 CACHEFILE_ENTRY * pEntry;
2069 URL_CACHEFILE_ENTRY * pUrlEntry;
2070 URLCACHECONTAINER * pContainer;
2071 DWORD error;
2073 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
2075 if (dwReserved)
2077 ERR("dwReserved != 0\n");
2078 SetLastError(ERROR_INVALID_PARAMETER);
2079 return FALSE;
2082 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2083 if (error != ERROR_SUCCESS)
2085 SetLastError(error);
2086 return FALSE;
2089 error = URLCacheContainer_OpenIndex(pContainer);
2090 if (error != ERROR_SUCCESS)
2092 SetLastError(error);
2093 return FALSE;
2096 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2097 return FALSE;
2099 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
2101 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2102 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
2103 SetLastError(ERROR_FILE_NOT_FOUND);
2104 return FALSE;
2107 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2108 if (pEntry->dwSignature != URL_SIGNATURE)
2110 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2111 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2112 SetLastError(ERROR_FILE_NOT_FOUND);
2113 return FALSE;
2116 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2118 if (pUrlEntry->dwUseCount == 0)
2120 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2121 return FALSE;
2123 pUrlEntry->dwUseCount--;
2124 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2126 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2128 return TRUE;
2131 /***********************************************************************
2132 * CreateUrlCacheEntryA (WININET.@)
2135 BOOL WINAPI CreateUrlCacheEntryA(
2136 IN LPCSTR lpszUrlName,
2137 IN DWORD dwExpectedFileSize,
2138 IN LPCSTR lpszFileExtension,
2139 OUT LPSTR lpszFileName,
2140 IN DWORD dwReserved
2143 DWORD len;
2144 WCHAR *url_name;
2145 WCHAR *file_extension;
2146 WCHAR file_name[MAX_PATH];
2147 BOOL bSuccess = FALSE;
2148 DWORD dwError = 0;
2150 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
2151 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2153 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2154 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 &&
2155 (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2157 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2158 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
2160 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
2162 bSuccess = TRUE;
2164 else
2166 dwError = GetLastError();
2169 else
2171 dwError = GetLastError();
2173 HeapFree(GetProcessHeap(), 0, file_extension);
2175 else
2177 dwError = GetLastError();
2179 HeapFree(GetProcessHeap(), 0, url_name);
2180 if (!bSuccess)
2181 SetLastError(dwError);
2183 return bSuccess;
2185 /***********************************************************************
2186 * CreateUrlCacheEntryW (WININET.@)
2189 BOOL WINAPI CreateUrlCacheEntryW(
2190 IN LPCWSTR lpszUrlName,
2191 IN DWORD dwExpectedFileSize,
2192 IN LPCWSTR lpszFileExtension,
2193 OUT LPWSTR lpszFileName,
2194 IN DWORD dwReserved
2197 URLCACHECONTAINER * pContainer;
2198 LPURLCACHE_HEADER pHeader;
2199 CHAR szFile[MAX_PATH];
2200 WCHAR szExtension[MAX_PATH];
2201 LPCWSTR lpszUrlPart;
2202 LPCWSTR lpszUrlEnd;
2203 LPCWSTR lpszFileNameExtension;
2204 LPWSTR lpszFileNameNoPath;
2205 int i;
2206 int countnoextension;
2207 BYTE CacheDir;
2208 LONG lBufferSize;
2209 BOOL bFound = FALSE;
2210 int count;
2211 DWORD error;
2212 static const WCHAR szWWW[] = {'w','w','w',0};
2214 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2215 debugstr_w(lpszUrlName),
2216 dwExpectedFileSize,
2217 debugstr_w(lpszFileExtension),
2218 lpszFileName,
2219 dwReserved);
2221 if (dwReserved)
2223 ERR("dwReserved != 0\n");
2224 SetLastError(ERROR_INVALID_PARAMETER);
2225 return FALSE;
2228 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2230 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2231 lpszUrlEnd--;
2233 for (lpszUrlPart = lpszUrlEnd;
2234 (lpszUrlPart >= lpszUrlName);
2235 lpszUrlPart--)
2237 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2239 bFound = TRUE;
2240 lpszUrlPart++;
2241 break;
2243 else if(*lpszUrlPart == '?' || *lpszUrlPart == '#')
2245 lpszUrlEnd = lpszUrlPart;
2248 if (!lstrcmpW(lpszUrlPart, szWWW))
2250 lpszUrlPart += lstrlenW(szWWW);
2253 count = lpszUrlEnd - lpszUrlPart;
2255 if (bFound && (count < MAX_PATH))
2257 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2258 if (!len)
2259 return FALSE;
2260 szFile[len] = '\0';
2261 while(len && szFile[--len] == '/') szFile[len] = '\0';
2263 /* FIXME: get rid of illegal characters like \, / and : */
2265 else
2267 FIXME("need to generate a random filename\n");
2270 TRACE("File name: %s\n", debugstr_a(szFile));
2272 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2273 if (error != ERROR_SUCCESS)
2275 SetLastError(error);
2276 return FALSE;
2279 error = URLCacheContainer_OpenIndex(pContainer);
2280 if (error != ERROR_SUCCESS)
2282 SetLastError(error);
2283 return FALSE;
2286 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2287 return FALSE;
2289 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2291 lBufferSize = MAX_PATH * sizeof(WCHAR);
2292 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
2294 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2296 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2297 lpszFileNameNoPath >= lpszFileName;
2298 --lpszFileNameNoPath)
2300 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2301 break;
2304 countnoextension = lstrlenW(lpszFileNameNoPath);
2305 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2306 if (lpszFileNameExtension)
2307 countnoextension -= lstrlenW(lpszFileNameExtension);
2308 *szExtension = '\0';
2310 if (lpszFileExtension)
2312 szExtension[0] = '.';
2313 lstrcpyW(szExtension+1, lpszFileExtension);
2316 for (i = 0; i < 255; i++)
2318 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2319 HANDLE hFile;
2320 WCHAR *p;
2322 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2323 for (p = lpszFileNameNoPath + 1; *p; p++)
2325 switch (*p)
2327 case '<': case '>':
2328 case ':': case '"':
2329 case '/': case '\\':
2330 case '|': case '?':
2331 case '*':
2332 *p = '_'; break;
2333 default: break;
2336 if (p[-1] == ' ' || p[-1] == '.') p[-1] = '_';
2338 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2339 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2340 if (hFile != INVALID_HANDLE_VALUE)
2342 CloseHandle(hFile);
2343 return TRUE;
2347 return FALSE;
2351 /***********************************************************************
2352 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2354 * The bug we are compensating for is that some drongo at Microsoft
2355 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2356 * As a consequence, CommitUrlCacheEntryA has been effectively
2357 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2358 * is still defined as LPCWSTR. The result (other than madness) is
2359 * that we always need to store lpHeaderInfo in CP_ACP rather than
2360 * in UTF16, and we need to avoid converting lpHeaderInfo in
2361 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2362 * result will lose data for arbitrary binary data.
2365 static BOOL CommitUrlCacheEntryInternal(
2366 IN LPCWSTR lpszUrlName,
2367 IN LPCWSTR lpszLocalFileName,
2368 IN FILETIME ExpireTime,
2369 IN FILETIME LastModifiedTime,
2370 IN DWORD CacheEntryType,
2371 IN LPBYTE lpHeaderInfo,
2372 IN DWORD dwHeaderSize,
2373 IN LPCWSTR lpszFileExtension,
2374 IN LPCWSTR lpszOriginalUrl
2377 URLCACHECONTAINER * pContainer;
2378 LPURLCACHE_HEADER pHeader;
2379 struct _HASH_ENTRY * pHashEntry;
2380 CACHEFILE_ENTRY * pEntry;
2381 URL_CACHEFILE_ENTRY * pUrlEntry;
2382 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2383 DWORD dwOffsetLocalFileName = 0;
2384 DWORD dwOffsetHeader = 0;
2385 DWORD dwOffsetFileExtension = 0;
2386 DWORD dwFileSizeLow = 0;
2387 DWORD dwFileSizeHigh = 0;
2388 BYTE cDirectory = 0;
2389 int len;
2390 char achFile[MAX_PATH];
2391 LPSTR lpszUrlNameA = NULL;
2392 LPSTR lpszFileExtensionA = NULL;
2393 char *pchLocalFileName = 0;
2394 DWORD error;
2396 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2397 debugstr_w(lpszUrlName),
2398 debugstr_w(lpszLocalFileName),
2399 CacheEntryType,
2400 lpHeaderInfo,
2401 dwHeaderSize,
2402 debugstr_w(lpszFileExtension),
2403 debugstr_w(lpszOriginalUrl));
2405 if (lpszOriginalUrl)
2406 WARN(": lpszOriginalUrl ignored\n");
2408 if (lpszLocalFileName)
2410 HANDLE hFile;
2412 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2413 if (hFile == INVALID_HANDLE_VALUE)
2415 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2416 return FALSE;
2419 /* Get file size */
2420 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2421 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2423 ERR("couldn't get file size (error is %d)\n", GetLastError());
2424 CloseHandle(hFile);
2425 return FALSE;
2428 CloseHandle(hFile);
2431 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2432 if (error != ERROR_SUCCESS)
2434 SetLastError(error);
2435 return FALSE;
2438 error = URLCacheContainer_OpenIndex(pContainer);
2439 if (error != ERROR_SUCCESS)
2441 SetLastError(error);
2442 return FALSE;
2445 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2446 return FALSE;
2448 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2449 lpszUrlNameA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2450 if (!lpszUrlNameA)
2452 error = GetLastError();
2453 goto cleanup;
2455 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, lpszUrlNameA, len, NULL, NULL);
2457 if (lpszFileExtension)
2459 len = WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, NULL, 0, NULL, NULL);
2460 lpszFileExtensionA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2461 if (!lpszFileExtensionA)
2463 error = GetLastError();
2464 goto cleanup;
2466 WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, lpszFileExtensionA, len, NULL, NULL);
2469 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2471 FIXME("entry already in cache - don't know what to do!\n");
2473 * SetLastError(ERROR_FILE_NOT_FOUND);
2474 * return FALSE;
2476 goto cleanup;
2479 if (lpszLocalFileName)
2481 BOOL bFound = FALSE;
2483 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2485 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2486 error = ERROR_INVALID_PARAMETER;
2487 goto cleanup;
2490 /* skip container path prefix */
2491 lpszLocalFileName += lstrlenW(pContainer->path);
2493 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL);
2494 pchLocalFileName = achFile;
2496 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2498 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2500 bFound = TRUE;
2501 break;
2505 if (!bFound)
2507 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2508 error = ERROR_INVALID_PARAMETER;
2509 goto cleanup;
2512 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2515 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2516 if (lpszLocalFileName)
2518 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2519 dwOffsetLocalFileName = dwBytesNeeded;
2520 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2522 if (lpHeaderInfo)
2524 dwOffsetHeader = dwBytesNeeded;
2525 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2527 if (lpszFileExtensionA)
2529 dwOffsetFileExtension = dwBytesNeeded;
2530 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2533 /* round up to next block */
2534 if (dwBytesNeeded % BLOCKSIZE)
2536 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2537 dwBytesNeeded += BLOCKSIZE;
2540 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2542 ERR("no free entries\n");
2543 error = ERROR_DISK_FULL;
2544 goto cleanup;
2547 /* FindFirstFreeEntry fills in blocks used */
2548 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2549 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2550 pUrlEntry->CacheDir = cDirectory;
2551 pUrlEntry->CacheEntryType = CacheEntryType;
2552 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2553 pUrlEntry->dwExemptDelta = 0;
2554 pUrlEntry->dwHitRate = 0;
2555 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2556 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2557 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2558 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2559 pUrlEntry->dwSizeHigh = 0;
2560 pUrlEntry->dwSizeLow = dwFileSizeLow;
2561 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2562 pUrlEntry->dwUseCount = 0;
2563 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2564 pUrlEntry->LastModifiedTime = LastModifiedTime;
2565 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2566 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2567 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2568 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2570 /*** Unknowns ***/
2571 pUrlEntry->dwUnknown1 = 0;
2572 pUrlEntry->dwUnknown2 = 0;
2573 pUrlEntry->dwUnknown3 = 0x60;
2574 pUrlEntry->Unknown4 = 0;
2575 pUrlEntry->wUnknown5 = 0x1010;
2576 pUrlEntry->dwUnknown7 = 0;
2577 pUrlEntry->dwUnknown8 = 0;
2580 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2581 if (dwOffsetLocalFileName)
2582 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2583 if (dwOffsetHeader)
2584 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2585 if (dwOffsetFileExtension)
2586 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2588 error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA,
2589 (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader));
2590 if (error != ERROR_SUCCESS)
2591 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2593 cleanup:
2594 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2595 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2596 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2598 if (error == ERROR_SUCCESS)
2599 return TRUE;
2600 else
2602 SetLastError(error);
2603 return FALSE;
2607 /***********************************************************************
2608 * CommitUrlCacheEntryA (WININET.@)
2611 BOOL WINAPI CommitUrlCacheEntryA(
2612 IN LPCSTR lpszUrlName,
2613 IN LPCSTR lpszLocalFileName,
2614 IN FILETIME ExpireTime,
2615 IN FILETIME LastModifiedTime,
2616 IN DWORD CacheEntryType,
2617 IN LPBYTE lpHeaderInfo,
2618 IN DWORD dwHeaderSize,
2619 IN LPCSTR lpszFileExtension,
2620 IN LPCSTR lpszOriginalUrl
2623 DWORD len;
2624 WCHAR *url_name = NULL;
2625 WCHAR *local_file_name = NULL;
2626 WCHAR *original_url = NULL;
2627 WCHAR *file_extension = NULL;
2628 BOOL bSuccess = FALSE;
2630 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2631 debugstr_a(lpszUrlName),
2632 debugstr_a(lpszLocalFileName),
2633 CacheEntryType,
2634 lpHeaderInfo,
2635 dwHeaderSize,
2636 debugstr_a(lpszFileExtension),
2637 debugstr_a(lpszOriginalUrl));
2639 len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0);
2640 url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2641 if (!url_name)
2642 goto cleanup;
2643 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2645 if (lpszLocalFileName)
2647 len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0);
2648 local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2649 if (!local_file_name)
2650 goto cleanup;
2651 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2653 if (lpszFileExtension)
2655 len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0);
2656 file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2657 if (!file_extension)
2658 goto cleanup;
2659 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2661 if (lpszOriginalUrl)
2663 len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0);
2664 original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2665 if (!original_url)
2666 goto cleanup;
2667 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2670 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2671 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2672 file_extension, original_url);
2674 cleanup:
2675 HeapFree(GetProcessHeap(), 0, original_url);
2676 HeapFree(GetProcessHeap(), 0, file_extension);
2677 HeapFree(GetProcessHeap(), 0, local_file_name);
2678 HeapFree(GetProcessHeap(), 0, url_name);
2680 return bSuccess;
2683 /***********************************************************************
2684 * CommitUrlCacheEntryW (WININET.@)
2687 BOOL WINAPI CommitUrlCacheEntryW(
2688 IN LPCWSTR lpszUrlName,
2689 IN LPCWSTR lpszLocalFileName,
2690 IN FILETIME ExpireTime,
2691 IN FILETIME LastModifiedTime,
2692 IN DWORD CacheEntryType,
2693 IN LPWSTR lpHeaderInfo,
2694 IN DWORD dwHeaderSize,
2695 IN LPCWSTR lpszFileExtension,
2696 IN LPCWSTR lpszOriginalUrl
2699 DWORD dwError = 0;
2700 BOOL bSuccess = FALSE;
2701 DWORD len = 0;
2702 CHAR *header_info = NULL;
2704 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2705 debugstr_w(lpszUrlName),
2706 debugstr_w(lpszLocalFileName),
2707 CacheEntryType,
2708 lpHeaderInfo,
2709 dwHeaderSize,
2710 debugstr_w(lpszFileExtension),
2711 debugstr_w(lpszOriginalUrl));
2713 if (!lpHeaderInfo ||
2714 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2715 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2717 if (header_info)
2718 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2719 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2720 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2722 bSuccess = TRUE;
2724 else
2726 dwError = GetLastError();
2728 if (header_info)
2730 HeapFree(GetProcessHeap(), 0, header_info);
2731 if (!bSuccess)
2732 SetLastError(dwError);
2735 return bSuccess;
2738 /***********************************************************************
2739 * ReadUrlCacheEntryStream (WININET.@)
2742 BOOL WINAPI ReadUrlCacheEntryStream(
2743 IN HANDLE hUrlCacheStream,
2744 IN DWORD dwLocation,
2745 IN OUT LPVOID lpBuffer,
2746 IN OUT LPDWORD lpdwLen,
2747 IN DWORD dwReserved
2750 /* Get handle to file from 'stream' */
2751 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2753 if (dwReserved != 0)
2755 ERR("dwReserved != 0\n");
2756 SetLastError(ERROR_INVALID_PARAMETER);
2757 return FALSE;
2760 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2762 SetLastError(ERROR_INVALID_HANDLE);
2763 return FALSE;
2766 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2767 return FALSE;
2768 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2771 /***********************************************************************
2772 * RetrieveUrlCacheEntryStreamA (WININET.@)
2775 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2776 IN LPCSTR lpszUrlName,
2777 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2778 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2779 IN BOOL fRandomRead,
2780 IN DWORD dwReserved
2783 /* NOTE: this is not the same as the way that the native
2784 * version allocates 'stream' handles. I did it this way
2785 * as it is much easier and no applications should depend
2786 * on this behaviour. (Native version appears to allocate
2787 * indices into a table)
2789 STREAM_HANDLE * pStream;
2790 HANDLE hFile;
2792 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2793 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2795 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2796 lpCacheEntryInfo,
2797 lpdwCacheEntryInfoBufferSize,
2798 dwReserved))
2800 return NULL;
2803 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2804 GENERIC_READ,
2805 FILE_SHARE_READ,
2806 NULL,
2807 OPEN_EXISTING,
2808 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2809 NULL);
2810 if (hFile == INVALID_HANDLE_VALUE)
2811 return FALSE;
2813 /* allocate handle storage space */
2814 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2815 if (!pStream)
2817 CloseHandle(hFile);
2818 SetLastError(ERROR_OUTOFMEMORY);
2819 return FALSE;
2822 pStream->hFile = hFile;
2823 strcpy(pStream->lpszUrl, lpszUrlName);
2824 return pStream;
2827 /***********************************************************************
2828 * RetrieveUrlCacheEntryStreamW (WININET.@)
2831 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2832 IN LPCWSTR lpszUrlName,
2833 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2834 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2835 IN BOOL fRandomRead,
2836 IN DWORD dwReserved
2839 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2840 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2841 return NULL;
2844 /***********************************************************************
2845 * UnlockUrlCacheEntryStream (WININET.@)
2848 BOOL WINAPI UnlockUrlCacheEntryStream(
2849 IN HANDLE hUrlCacheStream,
2850 IN DWORD dwReserved
2853 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2855 if (dwReserved != 0)
2857 ERR("dwReserved != 0\n");
2858 SetLastError(ERROR_INVALID_PARAMETER);
2859 return FALSE;
2862 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2864 SetLastError(ERROR_INVALID_HANDLE);
2865 return FALSE;
2868 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2869 return FALSE;
2871 /* close file handle */
2872 CloseHandle(pStream->hFile);
2874 /* free allocated space */
2875 HeapFree(GetProcessHeap(), 0, pStream);
2877 return TRUE;
2881 /***********************************************************************
2882 * DeleteUrlCacheEntryA (WININET.@)
2885 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2887 URLCACHECONTAINER * pContainer;
2888 LPURLCACHE_HEADER pHeader;
2889 struct _HASH_ENTRY * pHashEntry;
2890 CACHEFILE_ENTRY * pEntry;
2891 DWORD error;
2893 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2895 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2896 if (error != ERROR_SUCCESS)
2898 SetLastError(error);
2899 return FALSE;
2902 error = URLCacheContainer_OpenIndex(pContainer);
2903 if (error != ERROR_SUCCESS)
2905 SetLastError(error);
2906 return FALSE;
2909 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2910 return FALSE;
2912 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2914 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2915 TRACE("entry %s not found!\n", lpszUrlName);
2916 SetLastError(ERROR_FILE_NOT_FOUND);
2917 return FALSE;
2920 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2921 URLCache_DeleteEntry(pHeader, pEntry);
2923 URLCache_DeleteEntryFromHash(pHashEntry);
2925 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2927 return TRUE;
2930 /***********************************************************************
2931 * DeleteUrlCacheEntryW (WININET.@)
2934 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2936 URLCACHECONTAINER * pContainer;
2937 LPURLCACHE_HEADER pHeader;
2938 struct _HASH_ENTRY * pHashEntry;
2939 CACHEFILE_ENTRY * pEntry;
2940 LPSTR urlA;
2941 int url_len;
2942 DWORD error;
2944 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2946 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2947 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
2948 if (!urlA)
2950 SetLastError(ERROR_OUTOFMEMORY);
2951 return FALSE;
2953 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, urlA, url_len, NULL, NULL);
2955 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2956 if (error != ERROR_SUCCESS)
2958 HeapFree(GetProcessHeap(), 0, urlA);
2959 SetLastError(error);
2960 return FALSE;
2963 error = URLCacheContainer_OpenIndex(pContainer);
2964 if (error != ERROR_SUCCESS)
2966 HeapFree(GetProcessHeap(), 0, urlA);
2967 SetLastError(error);
2968 return FALSE;
2971 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2973 HeapFree(GetProcessHeap(), 0, urlA);
2974 return FALSE;
2977 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
2979 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2980 TRACE("entry %s not found!\n", debugstr_a(urlA));
2981 HeapFree(GetProcessHeap(), 0, urlA);
2982 SetLastError(ERROR_FILE_NOT_FOUND);
2983 return FALSE;
2986 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2987 URLCache_DeleteEntry(pHeader, pEntry);
2989 URLCache_DeleteEntryFromHash(pHashEntry);
2991 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2993 HeapFree(GetProcessHeap(), 0, urlA);
2994 return TRUE;
2997 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2999 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3000 return TRUE;
3003 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
3005 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3006 return TRUE;
3009 /***********************************************************************
3010 * CreateCacheContainerA (WININET.@)
3012 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3013 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3015 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3016 d1, d2, d3, d4, d5, d6, d7, d8);
3017 return TRUE;
3020 /***********************************************************************
3021 * CreateCacheContainerW (WININET.@)
3023 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3024 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3026 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3027 d1, d2, d3, d4, d5, d6, d7, d8);
3028 return TRUE;
3031 /***********************************************************************
3032 * FindFirstUrlCacheContainerA (WININET.@)
3034 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3036 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3037 return NULL;
3040 /***********************************************************************
3041 * FindFirstUrlCacheContainerW (WININET.@)
3043 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3045 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3046 return NULL;
3049 /***********************************************************************
3050 * FindNextUrlCacheContainerA (WININET.@)
3052 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
3054 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3055 return FALSE;
3058 /***********************************************************************
3059 * FindNextUrlCacheContainerW (WININET.@)
3061 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
3063 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3064 return FALSE;
3067 HANDLE WINAPI FindFirstUrlCacheEntryExA(
3068 LPCSTR lpszUrlSearchPattern,
3069 DWORD dwFlags,
3070 DWORD dwFilter,
3071 GROUPID GroupId,
3072 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3073 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3074 LPVOID lpReserved,
3075 LPDWORD pcbReserved2,
3076 LPVOID lpReserved3
3079 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
3080 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3081 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3082 SetLastError(ERROR_FILE_NOT_FOUND);
3083 return NULL;
3086 HANDLE WINAPI FindFirstUrlCacheEntryExW(
3087 LPCWSTR lpszUrlSearchPattern,
3088 DWORD dwFlags,
3089 DWORD dwFilter,
3090 GROUPID GroupId,
3091 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3092 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3093 LPVOID lpReserved,
3094 LPDWORD pcbReserved2,
3095 LPVOID lpReserved3
3098 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
3099 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3100 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3101 SetLastError(ERROR_FILE_NOT_FOUND);
3102 return NULL;
3105 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3107 typedef struct URLCacheFindEntryHandle
3109 DWORD dwMagic;
3110 LPWSTR lpszUrlSearchPattern;
3111 DWORD dwContainerIndex;
3112 DWORD dwHashTableIndex;
3113 DWORD dwHashEntryIndex;
3114 } URLCacheFindEntryHandle;
3116 /***********************************************************************
3117 * FindFirstUrlCacheEntryA (WININET.@)
3120 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
3121 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3123 URLCacheFindEntryHandle *pEntryHandle;
3125 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3127 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3128 if (!pEntryHandle)
3129 return NULL;
3131 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3132 if (lpszUrlSearchPattern)
3134 int len = MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, NULL, 0);
3135 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3136 if (!pEntryHandle->lpszUrlSearchPattern)
3138 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3139 return NULL;
3141 MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, pEntryHandle->lpszUrlSearchPattern, len);
3143 else
3144 pEntryHandle->lpszUrlSearchPattern = NULL;
3145 pEntryHandle->dwContainerIndex = 0;
3146 pEntryHandle->dwHashTableIndex = 0;
3147 pEntryHandle->dwHashEntryIndex = 0;
3149 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3151 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3152 return NULL;
3154 return pEntryHandle;
3157 /***********************************************************************
3158 * FindFirstUrlCacheEntryW (WININET.@)
3161 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3162 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3164 URLCacheFindEntryHandle *pEntryHandle;
3166 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3168 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3169 if (!pEntryHandle)
3170 return NULL;
3172 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3173 if (lpszUrlSearchPattern)
3175 int len = strlenW(lpszUrlSearchPattern);
3176 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
3177 if (!pEntryHandle->lpszUrlSearchPattern)
3179 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3180 return NULL;
3182 memcpy(pEntryHandle->lpszUrlSearchPattern, lpszUrlSearchPattern, (len + 1) * sizeof(WCHAR));
3184 else
3185 pEntryHandle->lpszUrlSearchPattern = NULL;
3186 pEntryHandle->dwContainerIndex = 0;
3187 pEntryHandle->dwHashTableIndex = 0;
3188 pEntryHandle->dwHashEntryIndex = 0;
3190 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3192 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3193 return NULL;
3195 return pEntryHandle;
3198 /***********************************************************************
3199 * FindNextUrlCacheEntryA (WININET.@)
3201 BOOL WINAPI FindNextUrlCacheEntryA(
3202 HANDLE hEnumHandle,
3203 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3204 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3206 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3207 URLCACHECONTAINER * pContainer;
3209 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3211 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3213 SetLastError(ERROR_INVALID_HANDLE);
3214 return FALSE;
3217 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3218 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3220 LPURLCACHE_HEADER pHeader;
3221 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3222 DWORD error;
3224 error = URLCacheContainer_OpenIndex(pContainer);
3225 if (error != ERROR_SUCCESS)
3227 SetLastError(error);
3228 return FALSE;
3231 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3232 return FALSE;
3234 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3235 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3237 const struct _HASH_ENTRY *pHashEntry = NULL;
3238 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3239 pEntryHandle->dwHashEntryIndex++)
3241 const URL_CACHEFILE_ENTRY *pUrlEntry;
3242 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3244 if (pEntry->dwSignature != URL_SIGNATURE)
3245 continue;
3247 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3248 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3249 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3251 error = URLCache_CopyEntry(
3252 pContainer,
3253 pHeader,
3254 lpNextCacheEntryInfo,
3255 lpdwNextCacheEntryInfoBufferSize,
3256 pUrlEntry,
3257 FALSE /* not UNICODE */);
3258 if (error != ERROR_SUCCESS)
3260 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3261 SetLastError(error);
3262 return FALSE;
3264 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
3266 /* increment the current index so that next time the function
3267 * is called the next entry is returned */
3268 pEntryHandle->dwHashEntryIndex++;
3269 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3270 return TRUE;
3274 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3277 SetLastError(ERROR_NO_MORE_ITEMS);
3278 return FALSE;
3281 /***********************************************************************
3282 * FindNextUrlCacheEntryW (WININET.@)
3284 BOOL WINAPI FindNextUrlCacheEntryW(
3285 HANDLE hEnumHandle,
3286 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3287 LPDWORD lpdwNextCacheEntryInfoBufferSize
3290 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3291 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3292 return FALSE;
3295 /***********************************************************************
3296 * FindCloseUrlCache (WININET.@)
3298 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3300 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3302 TRACE("(%p)\n", hEnumHandle);
3304 if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3306 SetLastError(ERROR_INVALID_HANDLE);
3307 return FALSE;
3310 pEntryHandle->dwMagic = 0;
3311 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3312 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3314 return TRUE;
3317 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3318 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3320 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3321 dwSearchCondition, lpGroupId, lpReserved);
3322 return NULL;
3325 BOOL WINAPI FindNextUrlCacheEntryExA(
3326 HANDLE hEnumHandle,
3327 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3328 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3329 LPVOID lpReserved,
3330 LPDWORD pcbReserved2,
3331 LPVOID lpReserved3
3334 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3335 lpReserved, pcbReserved2, lpReserved3);
3336 return FALSE;
3339 BOOL WINAPI FindNextUrlCacheEntryExW(
3340 HANDLE hEnumHandle,
3341 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3342 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3343 LPVOID lpReserved,
3344 LPDWORD pcbReserved2,
3345 LPVOID lpReserved3
3348 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3349 lpReserved, pcbReserved2, lpReserved3);
3350 return FALSE;
3353 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3355 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3356 return FALSE;
3359 /***********************************************************************
3360 * CreateUrlCacheGroup (WININET.@)
3363 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3365 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3366 return FALSE;
3369 /***********************************************************************
3370 * DeleteUrlCacheGroup (WININET.@)
3373 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3375 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3376 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3377 return FALSE;
3380 /***********************************************************************
3381 * SetUrlCacheEntryGroupA (WININET.@)
3384 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3385 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3386 LPVOID lpReserved)
3388 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3389 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3390 pbGroupAttributes, cbGroupAttributes, lpReserved);
3391 SetLastError(ERROR_FILE_NOT_FOUND);
3392 return FALSE;
3395 /***********************************************************************
3396 * SetUrlCacheEntryGroupW (WININET.@)
3399 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3400 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3401 LPVOID lpReserved)
3403 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3404 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3405 pbGroupAttributes, cbGroupAttributes, lpReserved);
3406 SetLastError(ERROR_FILE_NOT_FOUND);
3407 return FALSE;
3410 /***********************************************************************
3411 * GetUrlCacheConfigInfoW (WININET.@)
3413 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3415 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3416 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3417 return FALSE;
3420 /***********************************************************************
3421 * GetUrlCacheConfigInfoA (WININET.@)
3423 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3425 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3427 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3428 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3429 return FALSE;
3432 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3433 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3434 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3436 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3437 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3438 lpdwGroupInfo, lpReserved);
3439 return FALSE;
3442 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3443 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3444 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3446 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3447 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3448 lpdwGroupInfo, lpReserved);
3449 return FALSE;
3452 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3453 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3455 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3456 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3457 return TRUE;
3460 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3461 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3463 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3464 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3465 return TRUE;
3468 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3470 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3471 return TRUE;
3474 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3476 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3477 return TRUE;
3480 /***********************************************************************
3481 * DeleteIE3Cache (WININET.@)
3483 * Deletes the files used by the IE3 URL caching system.
3485 * PARAMS
3486 * hWnd [I] A dummy window.
3487 * hInst [I] Instance of process calling the function.
3488 * lpszCmdLine [I] Options used by function.
3489 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3491 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3493 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3494 return 0;
3497 /***********************************************************************
3498 * IsUrlCacheEntryExpiredA (WININET.@)
3500 * PARAMS
3501 * url [I] Url
3502 * dwFlags [I] Unknown
3503 * pftLastModified [O] Last modified time
3505 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3507 LPURLCACHE_HEADER pHeader;
3508 struct _HASH_ENTRY * pHashEntry;
3509 const CACHEFILE_ENTRY * pEntry;
3510 const URL_CACHEFILE_ENTRY * pUrlEntry;
3511 URLCACHECONTAINER * pContainer;
3512 DWORD error;
3514 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3516 error = URLCacheContainers_FindContainerA(url, &pContainer);
3517 if (error != ERROR_SUCCESS)
3519 SetLastError(error);
3520 return FALSE;
3523 error = URLCacheContainer_OpenIndex(pContainer);
3524 if (error != ERROR_SUCCESS)
3526 SetLastError(error);
3527 return FALSE;
3530 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3531 return FALSE;
3533 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3535 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3536 TRACE("entry %s not found!\n", url);
3537 SetLastError(ERROR_FILE_NOT_FOUND);
3538 return FALSE;
3541 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3542 if (pEntry->dwSignature != URL_SIGNATURE)
3544 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3545 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3546 SetLastError(ERROR_FILE_NOT_FOUND);
3547 return FALSE;
3550 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3552 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3554 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3556 return TRUE;
3559 /***********************************************************************
3560 * IsUrlCacheEntryExpiredW (WININET.@)
3562 * PARAMS
3563 * url [I] Url
3564 * dwFlags [I] Unknown
3565 * pftLastModified [O] Last modified time
3567 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3569 LPURLCACHE_HEADER pHeader;
3570 struct _HASH_ENTRY * pHashEntry;
3571 const CACHEFILE_ENTRY * pEntry;
3572 const URL_CACHEFILE_ENTRY * pUrlEntry;
3573 URLCACHECONTAINER * pContainer;
3574 DWORD error;
3576 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3578 error = URLCacheContainers_FindContainerW(url, &pContainer);
3579 if (error != ERROR_SUCCESS)
3581 SetLastError(error);
3582 return FALSE;
3585 error = URLCacheContainer_OpenIndex(pContainer);
3586 if (error != ERROR_SUCCESS)
3588 SetLastError(error);
3589 return FALSE;
3592 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3593 return FALSE;
3595 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3597 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3598 TRACE("entry %s not found!\n", debugstr_w(url));
3599 SetLastError(ERROR_FILE_NOT_FOUND);
3600 return FALSE;
3603 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3604 if (pEntry->dwSignature != URL_SIGNATURE)
3606 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3607 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3608 SetLastError(ERROR_FILE_NOT_FOUND);
3609 return FALSE;
3612 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3614 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3616 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3618 return TRUE;
3621 /***********************************************************************
3622 * GetDiskInfoA (WININET.@)
3624 DWORD WINAPI GetDiskInfoA(void *p0, void *p1, void *p2, void *p3)
3626 FIXME("(%p, %p, %p, %p)\n", p0, p1, p2, p3);
3627 return 0;
3630 /***********************************************************************
3631 * RegisterUrlCacheNotification (WININET.@)
3633 DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
3635 FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f);
3636 return 0;