advapi32: Fix the failing QueryServiceConfig2 test on platforms win2k3 and vista.
[wine/multimedia.git] / dlls / wininet / urlcache.c
blob7dfb20aec10e669d4ece1117fd365141dc42379d
1 /*
2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003 Robert Shearman
7 * Eric Kohl
8 * Aric Stewart
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
26 #include "wine/port.h"
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <time.h>
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winuser.h"
40 #include "wininet.h"
41 #include "winineti.h"
42 #include "winerror.h"
43 #include "internet.h"
44 #include "winreg.h"
45 #include "shlwapi.h"
46 #include "shlobj.h"
48 #include "wine/unicode.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
53 #define ENTRY_START_OFFSET 0x4000
54 #define DIR_LENGTH 8
55 #define BLOCKSIZE 128
56 #define HASHTABLE_SIZE 448
57 #define HASHTABLE_BLOCKSIZE 7
58 #define HASHTABLE_FREE 3
59 #define ALLOCATION_TABLE_OFFSET 0x250
60 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
61 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
62 #define NEWFILE_NUM_BLOCKS 0xd80
63 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
65 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
66 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
67 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
68 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
69 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
71 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
73 typedef struct _CACHEFILE_ENTRY
75 /* union
76 {*/
77 DWORD dwSignature; /* e.g. "URL " */
78 /* CHAR szSignature[4];
79 };*/
80 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
81 } CACHEFILE_ENTRY;
83 typedef struct _URL_CACHEFILE_ENTRY
85 CACHEFILE_ENTRY CacheFileEntry;
86 FILETIME LastModifiedTime;
87 FILETIME LastAccessTime;
88 WORD wExpiredDate; /* expire date in dos format */
89 WORD wExpiredTime; /* expire time in dos format */
90 DWORD dwUnknown1; /* usually zero */
91 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
92 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
93 DWORD dwUnknown2; /* usually zero */
94 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
95 DWORD dwUnknown3; /* usually 0x60 */
96 DWORD dwOffsetUrl; /* offset of start of url from start of entry */
97 BYTE CacheDir; /* index of cache directory this url is stored in */
98 BYTE Unknown4; /* usually zero */
99 WORD wUnknown5; /* usually 0x1010 */
100 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
101 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
102 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
103 DWORD dwHeaderInfoSize;
104 DWORD dwUnknown6; /* usually zero */
105 WORD wLastSyncDate; /* last sync date in dos format */
106 WORD wLastSyncTime; /* last sync time in dos format */
107 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
108 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
109 WORD wUnknownDate; /* usually same as wLastSyncDate */
110 WORD wUnknownTime; /* usually same as wLastSyncTime */
111 DWORD dwUnknown7; /* usually zero */
112 DWORD dwUnknown8; /* usually zero */
113 /* packing to dword align start of next field */
114 /* CHAR szSourceUrlName[]; (url) */
115 /* packing to dword align start of next field */
116 /* CHAR szLocalFileName[]; (local file name excluding path) */
117 /* packing to dword align start of next field */
118 /* CHAR szHeaderInfo[]; (header info) */
119 } URL_CACHEFILE_ENTRY;
121 struct _HASH_ENTRY
123 DWORD dwHashKey;
124 DWORD dwOffsetEntry;
127 typedef struct _HASH_CACHEFILE_ENTRY
129 CACHEFILE_ENTRY CacheFileEntry;
130 DWORD dwAddressNext;
131 DWORD dwHashTableNumber;
132 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
133 } HASH_CACHEFILE_ENTRY;
135 typedef struct _DIRECTORY_DATA
137 DWORD dwUnknown;
138 char filename[DIR_LENGTH];
139 } DIRECTORY_DATA;
141 typedef struct _URLCACHE_HEADER
143 char szSignature[28];
144 DWORD dwFileSize;
145 DWORD dwOffsetFirstHashTable;
146 DWORD dwIndexCapacityInBlocks;
147 DWORD dwBlocksInUse;
148 DWORD dwUnknown1;
149 DWORD dwCacheLimitLow; /* disk space limit for cache */
150 DWORD dwCacheLimitHigh; /* disk space limit for cache */
151 DWORD dwUnknown4; /* current disk space usage for cache */
152 DWORD dwUnknown5; /* current disk space usage for cache */
153 DWORD dwUnknown6; /* possibly a flag? */
154 DWORD dwUnknown7;
155 BYTE DirectoryCount; /* number of directory_data's */
156 BYTE Unknown8[3]; /* just padding? */
157 DIRECTORY_DATA directory_data[1]; /* first directory entry */
158 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
159 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
161 typedef struct _STREAM_HANDLE
163 HANDLE hFile;
164 CHAR lpszUrl[1];
165 } STREAM_HANDLE;
167 typedef struct _URLCACHECONTAINER
169 struct list entry; /* part of a list */
170 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
171 LPWSTR path; /* path to url container directory */
172 HANDLE hMapping; /* handle of file mapping */
173 DWORD file_size; /* size of file when mapping was opened */
174 HANDLE hMutex; /* handle of mutex */
175 } URLCACHECONTAINER;
178 /* List of all containers available */
179 static struct list UrlContainers = LIST_INIT(UrlContainers);
181 static HASH_CACHEFILE_ENTRY *URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash);
183 /***********************************************************************
184 * URLCache_PathToObjectName (Internal)
186 * Converts a path to a name suitable for use as a Win32 object name.
187 * Replaces '\\' characters in-place with the specified character
188 * (usually '_' or '!')
190 * RETURNS
191 * nothing
194 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
196 for (; *lpszPath; lpszPath++)
198 if (*lpszPath == '\\')
199 *lpszPath = replace;
203 /***********************************************************************
204 * URLCacheContainer_OpenIndex (Internal)
206 * Opens the index file and saves mapping handle in hCacheIndexMapping
208 * RETURNS
209 * TRUE if succeeded
210 * FALSE if failed
213 static BOOL URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
215 HANDLE hFile;
216 WCHAR wszFilePath[MAX_PATH];
217 DWORD dwFileSize;
219 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
220 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
222 if (pContainer->hMapping)
223 return TRUE;
225 strcpyW(wszFilePath, pContainer->path);
226 strcatW(wszFilePath, wszIndex);
228 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
229 if (hFile == INVALID_HANDLE_VALUE)
231 /* Maybe the directory wasn't there? Try to create it */
232 if (CreateDirectoryW(pContainer->path, 0))
233 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
235 if (hFile == INVALID_HANDLE_VALUE)
237 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath));
238 return FALSE;
241 /* At this stage we need the mutex because we may be about to create the
242 * file.
244 WaitForSingleObject(pContainer->hMutex, INFINITE);
246 dwFileSize = GetFileSize(hFile, NULL);
247 if (dwFileSize == INVALID_FILE_SIZE)
249 ReleaseMutex(pContainer->hMutex);
250 return FALSE;
253 if (dwFileSize == 0)
255 static const CHAR szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content";
256 HKEY key;
257 char achZeroes[0x1000];
258 DWORD dwOffset;
259 DWORD dwError = 0;
261 /* Write zeroes to the entire file so we can safely map it without
262 * fear of getting a SEGV because the disk is full.
264 memset(achZeroes, 0, sizeof(achZeroes));
265 for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes))
267 DWORD dwWrite = sizeof(achZeroes);
268 DWORD dwWritten;
270 if (NEWFILE_SIZE - dwOffset < dwWrite)
271 dwWrite = NEWFILE_SIZE - dwOffset;
272 if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) ||
273 dwWritten != dwWrite)
275 /* If we fail to write, we need to return the error that
276 * cause the problem and also make sure the file is no
277 * longer there, if possible.
279 dwError = GetLastError();
281 break;
285 if (!dwError)
287 HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL);
289 if (hMapping)
291 URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE);
293 if (pHeader)
295 WCHAR *pwchDir;
296 WCHAR wszDirPath[MAX_PATH];
297 FILETIME ft;
298 int i, j;
300 dwFileSize = NEWFILE_SIZE;
302 /* First set some constants and defaults in the header */
303 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
304 pHeader->dwFileSize = dwFileSize;
305 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
306 /* 127MB - taken from default for Windows 2000 */
307 pHeader->dwCacheLimitHigh = 0;
308 pHeader->dwCacheLimitLow = 0x07ff5400;
309 /* Copied from a Windows 2000 cache index */
310 pHeader->DirectoryCount = 4;
312 /* If the registry has a cache size set, use the registry value */
313 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
315 DWORD dw;
316 DWORD len = sizeof(dw);
317 DWORD keytype;
319 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
320 (BYTE *) &dw, &len) == ERROR_SUCCESS &&
321 keytype == REG_DWORD)
323 pHeader->dwCacheLimitHigh = (dw >> 22);
324 pHeader->dwCacheLimitLow = dw << 10;
326 RegCloseKey(key);
329 URLCache_CreateHashTable(pHeader, NULL);
331 /* Last step - create the directories */
333 strcpyW(wszDirPath, pContainer->path);
334 pwchDir = wszDirPath + strlenW(wszDirPath);
335 pwchDir[8] = 0;
337 GetSystemTimeAsFileTime(&ft);
339 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
341 /* The following values were copied from a Windows index.
342 * I don't know what the values are supposed to mean but
343 * have made them the same in the hope that this will
344 * be better for compatibility
346 pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
347 for (j = 0;; ++j)
349 int k;
350 ULONGLONG n = ft.dwHighDateTime;
352 /* Generate a file name to attempt to create.
353 * This algorithm will create what will appear
354 * to be random and unrelated directory names
355 * of up to 9 characters in length.
357 n <<= 32;
358 n += ft.dwLowDateTime;
359 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
361 for (k = 0; k < 8; ++k)
363 int r = (n % 36);
365 /* Dividing by a prime greater than 36 helps
366 * with the appearance of randomness
368 n /= 37;
370 if (r < 10)
371 pwchDir[k] = '0' + r;
372 else
373 pwchDir[k] = 'A' + (r - 10);
376 if (CreateDirectoryW(wszDirPath, 0))
378 int k;
380 /* The following is OK because we generated an
381 * 8 character directory name made from characters
382 * [A-Z0-9], which are equivalent for all code
383 * pages and for UTF-16
385 for (k = 0; k < 8; ++k)
386 pHeader->directory_data[i].filename[k] = pwchDir[k];
387 break;
389 else if (j >= 255)
391 /* Give up. The most likely cause of this
392 * is a full disk, but whatever the cause
393 * is, it should be more than apparent that
394 * we won't succeed.
396 dwError = GetLastError();
397 break;
402 UnmapViewOfFile(pHeader);
404 else
406 dwError = GetLastError();
408 CloseHandle(hMapping);
410 else
412 dwError = GetLastError();
416 if (dwError)
418 CloseHandle(hFile);
419 DeleteFileW(wszFilePath);
420 ReleaseMutex(pContainer->hMutex);
421 SetLastError(dwError);
422 return FALSE;
427 ReleaseMutex(pContainer->hMutex);
429 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
430 URLCache_PathToObjectName(wszFilePath, '_');
431 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
432 if (!pContainer->hMapping)
433 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
434 CloseHandle(hFile);
435 if (!pContainer->hMapping)
437 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
438 return FALSE;
441 return TRUE;
444 /***********************************************************************
445 * URLCacheContainer_CloseIndex (Internal)
447 * Closes the index
449 * RETURNS
450 * nothing
453 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
455 CloseHandle(pContainer->hMapping);
456 pContainer->hMapping = NULL;
459 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
461 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
462 int path_len = strlenW(path);
463 int cache_prefix_len = strlenW(cache_prefix);
465 if (!pContainer)
467 return FALSE;
470 pContainer->hMapping = NULL;
471 pContainer->file_size = 0;
473 pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR));
474 if (!pContainer->path)
476 HeapFree(GetProcessHeap(), 0, pContainer);
477 return FALSE;
480 memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR));
482 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
483 if (!pContainer->cache_prefix)
485 HeapFree(GetProcessHeap(), 0, pContainer->path);
486 HeapFree(GetProcessHeap(), 0, pContainer);
487 return FALSE;
490 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
492 CharLowerW(mutex_name);
493 URLCache_PathToObjectName(mutex_name, '!');
495 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
497 ERR("couldn't create mutex (error is %d)\n", GetLastError());
498 HeapFree(GetProcessHeap(), 0, pContainer->path);
499 HeapFree(GetProcessHeap(), 0, pContainer);
500 return FALSE;
503 list_add_head(&UrlContainers, &pContainer->entry);
505 return TRUE;
508 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
510 list_remove(&pContainer->entry);
512 URLCacheContainer_CloseIndex(pContainer);
513 CloseHandle(pContainer->hMutex);
514 HeapFree(GetProcessHeap(), 0, pContainer->path);
515 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
516 HeapFree(GetProcessHeap(), 0, pContainer);
519 void URLCacheContainers_CreateDefaults(void)
521 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
522 static const WCHAR UrlPrefix[] = {0};
523 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
524 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
525 static const WCHAR CookieSuffix[] = {0};
526 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
527 static const struct
529 int nFolder; /* CSIDL_* constant */
530 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
531 const WCHAR * cache_prefix; /* prefix used to reference the container */
532 } DefaultContainerData[] =
534 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
535 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
536 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
538 DWORD i;
540 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
542 WCHAR wszCachePath[MAX_PATH];
543 WCHAR wszMutexName[MAX_PATH];
544 int path_len, suffix_len;
546 if (FAILED(SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE)))
548 ERR("Couldn't get path for default container %u\n", i);
549 continue;
551 path_len = strlenW(wszCachePath);
552 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
554 if (path_len + suffix_len + 2 > MAX_PATH)
556 ERR("Path too long\n");
557 continue;
560 wszCachePath[path_len] = '\\';
561 wszCachePath[path_len+1] = 0;
563 strcpyW(wszMutexName, wszCachePath);
565 if (suffix_len)
567 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
568 wszCachePath[path_len + suffix_len + 1] = '\\';
569 wszCachePath[path_len + suffix_len + 2] = '\0';
572 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
576 void URLCacheContainers_DeleteAll(void)
578 while(!list_empty(&UrlContainers))
579 URLCacheContainer_DeleteContainer(
580 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
584 static BOOL URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
586 struct list * cursor;
588 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
590 LIST_FOR_EACH(cursor, &UrlContainers)
592 URLCACHECONTAINER * pContainer = LIST_ENTRY(cursor, URLCACHECONTAINER, entry);
593 int prefix_len = strlenW(pContainer->cache_prefix);
594 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
596 TRACE("found container with prefx %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
597 *ppContainer = pContainer;
598 return TRUE;
601 ERR("no container found\n");
602 SetLastError(ERROR_FILE_NOT_FOUND);
603 return FALSE;
606 static BOOL URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
608 BOOL ret;
609 LPWSTR lpwszUrl;
610 int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
611 if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR))))
613 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len);
614 ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer);
615 HeapFree(GetProcessHeap(), 0, lpwszUrl);
616 return ret;
618 return FALSE;
621 /***********************************************************************
622 * URLCacheContainer_LockIndex (Internal)
625 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
627 BYTE index;
628 LPVOID pIndexData;
629 URLCACHE_HEADER * pHeader;
631 /* acquire mutex */
632 WaitForSingleObject(pContainer->hMutex, INFINITE);
634 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
636 if (!pIndexData)
638 ReleaseMutex(pContainer->hMutex);
639 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
640 return FALSE;
642 pHeader = (URLCACHE_HEADER *)pIndexData;
644 /* file has grown - we need to remap to prevent us getting
645 * access violations when we try and access beyond the end
646 * of the memory mapped file */
647 if (pHeader->dwFileSize != pContainer->file_size)
649 URLCacheContainer_CloseIndex(pContainer);
650 if (!URLCacheContainer_OpenIndex(pContainer))
652 ReleaseMutex(pContainer->hMutex);
653 return FALSE;
655 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
657 if (!pIndexData)
659 ReleaseMutex(pContainer->hMutex);
660 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
661 return FALSE;
663 pHeader = (URLCACHE_HEADER *)pIndexData;
666 TRACE("Signature: %s, file size: %d bytes\n", pHeader->szSignature, pHeader->dwFileSize);
668 for (index = 0; index < pHeader->DirectoryCount; index++)
670 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
673 return pHeader;
676 /***********************************************************************
677 * URLCacheContainer_UnlockIndex (Internal)
680 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
682 /* release mutex */
683 ReleaseMutex(pContainer->hMutex);
684 return UnmapViewOfFile(pHeader);
688 #ifndef CHAR_BIT
689 #define CHAR_BIT (8 * sizeof(CHAR))
690 #endif
692 /***********************************************************************
693 * URLCache_Allocation_BlockIsFree (Internal)
695 * Is the specified block number free?
697 * RETURNS
698 * zero if free
699 * non-zero otherwise
702 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
704 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
705 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
708 /***********************************************************************
709 * URLCache_Allocation_BlockFree (Internal)
711 * Marks the specified block as free
713 * RETURNS
714 * nothing
717 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
719 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
720 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
723 /***********************************************************************
724 * URLCache_Allocation_BlockAllocate (Internal)
726 * Marks the specified block as allocated
728 * RETURNS
729 * nothing
732 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
734 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
735 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
738 /***********************************************************************
739 * URLCache_FindFirstFreeEntry (Internal)
741 * Finds and allocates the first block of free space big enough and
742 * sets ppEntry to point to it.
744 * RETURNS
745 * TRUE if it had enough space
746 * FALSE if it couldn't find enough space
749 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
751 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
752 DWORD dwBlockNumber;
753 DWORD dwFreeCounter;
754 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
756 for (dwFreeCounter = 0;
757 dwFreeCounter < dwBlocksNeeded &&
758 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
759 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
760 dwFreeCounter++)
761 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
763 if (dwFreeCounter == dwBlocksNeeded)
765 DWORD index;
766 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
767 for (index = 0; index < dwBlocksNeeded; index++)
768 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
769 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
770 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
771 return TRUE;
774 FIXME("Grow file\n");
775 return FALSE;
778 /***********************************************************************
779 * URLCache_DeleteEntry (Internal)
781 * Deletes the specified entry and frees the space allocated to it
783 * RETURNS
784 * TRUE if it succeeded
785 * FALSE if it failed
788 static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, CACHEFILE_ENTRY * pEntry)
790 DWORD dwStartBlock;
791 DWORD dwBlock;
792 BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
794 /* update allocation table */
795 dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE;
796 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
797 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
799 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
800 return TRUE;
803 /***********************************************************************
804 * URLCache_LocalFileNameToPathW (Internal)
806 * Copies the full path to the specified buffer given the local file
807 * name and the index of the directory it is in. Always sets value in
808 * lpBufferSize to the required buffer size (in bytes).
810 * RETURNS
811 * TRUE if the buffer was big enough
812 * FALSE if the buffer was too small
815 static BOOL URLCache_LocalFileNameToPathW(
816 const URLCACHECONTAINER * pContainer,
817 LPCURLCACHE_HEADER pHeader,
818 LPCSTR szLocalFileName,
819 BYTE Directory,
820 LPWSTR wszPath,
821 LPLONG lpBufferSize)
823 LONG nRequired;
824 int path_len = strlenW(pContainer->path);
825 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
826 if (Directory >= pHeader->DirectoryCount)
828 *lpBufferSize = 0;
829 return FALSE;
832 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
833 if (nRequired < *lpBufferSize)
835 int dir_len;
837 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
838 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
839 wszPath[dir_len + path_len] = '\\';
840 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
841 *lpBufferSize = nRequired;
842 return TRUE;
844 *lpBufferSize = nRequired;
845 return FALSE;
848 /***********************************************************************
849 * URLCache_LocalFileNameToPathA (Internal)
851 * Copies the full path to the specified buffer given the local file
852 * name and the index of the directory it is in. Always sets value in
853 * lpBufferSize to the required buffer size.
855 * RETURNS
856 * TRUE if the buffer was big enough
857 * FALSE if the buffer was too small
860 static BOOL URLCache_LocalFileNameToPathA(
861 const URLCACHECONTAINER * pContainer,
862 LPCURLCACHE_HEADER pHeader,
863 LPCSTR szLocalFileName,
864 BYTE Directory,
865 LPSTR szPath,
866 LPLONG lpBufferSize)
868 LONG nRequired;
869 int path_len, file_name_len, dir_len;
871 if (Directory >= pHeader->DirectoryCount)
873 *lpBufferSize = 0;
874 return FALSE;
877 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL);
878 file_name_len = strlen(szLocalFileName);
879 dir_len = DIR_LENGTH;
881 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(WCHAR);
882 if (nRequired < *lpBufferSize)
884 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, -1, NULL, NULL);
885 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
886 szPath[path_len + dir_len] = '\\';
887 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
888 *lpBufferSize = nRequired;
889 return TRUE;
891 *lpBufferSize = nRequired;
892 return FALSE;
895 /***********************************************************************
896 * URLCache_CopyEntry (Internal)
898 * Copies an entry from the cache index file to the Win32 structure
900 * RETURNS
901 * TRUE if the buffer was big enough
902 * FALSE if the buffer was too small
905 static BOOL URLCache_CopyEntry(
906 URLCACHECONTAINER * pContainer,
907 LPCURLCACHE_HEADER pHeader,
908 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
909 LPDWORD lpdwBufferSize,
910 URL_CACHEFILE_ENTRY * pUrlEntry,
911 BOOL bUnicode)
913 int lenUrl;
914 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
916 if (*lpdwBufferSize >= dwRequiredSize)
918 lpCacheEntryInfo->lpHeaderInfo = NULL;
919 lpCacheEntryInfo->lpszFileExtension = NULL;
920 lpCacheEntryInfo->lpszLocalFileName = NULL;
921 lpCacheEntryInfo->lpszSourceUrlName = NULL;
922 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
923 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
924 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
925 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
926 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
927 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
928 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
929 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
930 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
931 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
932 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
933 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
934 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
935 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
938 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
939 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
940 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
941 if (bUnicode)
942 lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0);
943 else
944 lenUrl = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
945 dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
947 /* FIXME: is source url optional? */
948 if (*lpdwBufferSize >= dwRequiredSize)
950 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrl - 1;
951 if (bUnicode)
952 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
953 else
954 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, (lenUrl + 1) * sizeof(CHAR));
957 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
958 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
959 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
961 if (pUrlEntry->dwOffsetLocalName)
963 LONG nLocalFilePathSize;
964 LPSTR lpszLocalFileName;
965 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
966 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
967 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
968 URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize))
970 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
972 dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ;
974 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
975 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
976 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
978 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
980 if (*lpdwBufferSize >= dwRequiredSize)
982 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
983 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
984 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
986 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
987 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
988 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
990 if (dwRequiredSize > *lpdwBufferSize)
992 *lpdwBufferSize = dwRequiredSize;
993 SetLastError(ERROR_INSUFFICIENT_BUFFER);
994 return FALSE;
996 *lpdwBufferSize = dwRequiredSize;
997 return TRUE;
1001 /***********************************************************************
1002 * URLCache_SetEntryInfo (Internal)
1004 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1005 * according to the flags set by dwFieldControl.
1007 * RETURNS
1008 * TRUE if the buffer was big enough
1009 * FALSE if the buffer was too small
1012 static BOOL URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1014 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1015 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1016 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1017 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1018 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1019 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1020 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1021 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1022 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1023 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1024 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1025 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1026 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1027 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1028 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1029 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1031 return TRUE;
1034 /***********************************************************************
1035 * URLCache_HashKey (Internal)
1037 * Returns the hash key for a given string
1039 * RETURNS
1040 * hash key for the string
1043 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1045 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1046 * but the algorithm and result are not the same!
1048 static const unsigned char lookupTable[256] =
1050 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1051 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1052 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1053 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1054 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1055 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1056 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1057 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1058 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1059 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1060 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1061 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1062 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1063 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1064 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1065 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1066 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1067 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1068 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1069 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1070 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1071 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1072 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1073 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1074 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1075 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1076 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1077 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1078 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1079 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1080 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1081 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1083 BYTE key[4];
1084 DWORD i;
1085 int subscript[sizeof(key) / sizeof(key[0])];
1087 subscript[0] = *lpszKey;
1088 subscript[1] = (char)(*lpszKey + 1);
1089 subscript[2] = (char)(*lpszKey + 2);
1090 subscript[3] = (char)(*lpszKey + 3);
1092 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1093 key[i] = lookupTable[i];
1095 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
1097 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1098 key[i] = lookupTable[*lpszKey ^ key[i]];
1101 return *(DWORD *)key;
1104 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
1106 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
1109 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1111 /* structure of hash table:
1112 * 448 entries divided into 64 blocks
1113 * each block therefore contains a chain of 7 key/offset pairs
1114 * how position in table is calculated:
1115 * 1. the url is hashed in helper function
1116 * 2. the key % 64 * 8 is the offset
1117 * 3. the key in the hash table is the hash key aligned to 64
1119 * note:
1120 * there can be multiple hash tables in the file and the offset to
1121 * the next one is stored in the header of the hash table
1123 DWORD key = URLCache_HashKey(lpszUrl);
1124 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1125 HASH_CACHEFILE_ENTRY * pHashEntry;
1126 DWORD dwHashTableNumber = 0;
1128 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1130 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1131 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1132 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1134 int i;
1135 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1137 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1138 continue;
1140 /* make sure that it is in fact a hash entry */
1141 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1143 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1144 continue;
1147 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1149 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1150 if (key == (DWORD)(pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
1152 /* FIXME: we should make sure that this is the right element
1153 * before returning and claiming that it is. We can do this
1154 * by doing a simple compare between the URL we were given
1155 * and the URL stored in the entry. However, this assumes
1156 * we know the format of all the entries stored in the
1157 * hash table */
1158 *ppHashEntry = pHashElement;
1159 return TRUE;
1163 return FALSE;
1166 static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1168 LPSTR urlA;
1169 int url_len;
1170 BOOL ret;
1172 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1173 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1174 if (!urlA)
1176 SetLastError(ERROR_OUTOFMEMORY);
1177 return FALSE;
1179 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, urlA, url_len, NULL, NULL);
1180 ret = URLCache_FindHash(pHeader, urlA, ppHashEntry);
1181 HeapFree(GetProcessHeap(), 0, urlA);
1182 return ret;
1185 /***********************************************************************
1186 * URLCache_HashEntrySetUse (Internal)
1188 * Searches all the hash tables in the index for the given URL and
1189 * sets the use count (stored or'ed with key)
1191 * RETURNS
1192 * TRUE if the entry was found
1193 * FALSE if the entry could not be found
1196 static BOOL URLCache_HashEntrySetUse(struct _HASH_ENTRY * pHashEntry, DWORD dwUseCount)
1198 pHashEntry->dwHashKey = dwUseCount | (DWORD)(pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1199 return TRUE;
1202 /***********************************************************************
1203 * URLCache_DeleteEntryFromHash (Internal)
1205 * Searches all the hash tables in the index for the given URL and
1206 * then if found deletes the entry.
1208 * RETURNS
1209 * TRUE if the entry was found
1210 * FALSE if the entry could not be found
1213 static BOOL URLCache_DeleteEntryFromHash(struct _HASH_ENTRY * pHashEntry)
1215 pHashEntry->dwHashKey = HASHTABLE_FREE;
1216 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1217 return TRUE;
1220 /***********************************************************************
1221 * URLCache_AddEntryToHash (Internal)
1223 * Searches all the hash tables for a free slot based on the offset
1224 * generated from the hash key. If a free slot is found, the offset and
1225 * key are entered into the hash table.
1227 * RETURNS
1228 * TRUE if the entry was added
1229 * FALSE if the entry could not be added
1232 static BOOL URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1234 /* see URLCache_FindEntryInHash for structure of hash tables */
1236 DWORD key = URLCache_HashKey(lpszUrl);
1237 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1238 HASH_CACHEFILE_ENTRY * pHashEntry;
1239 DWORD dwHashTableNumber = 0;
1241 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1243 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1244 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1245 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1247 int i;
1248 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1250 ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1251 break;
1253 /* make sure that it is in fact a hash entry */
1254 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1256 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1257 break;
1260 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1262 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1263 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1265 pHashElement->dwHashKey = key;
1266 pHashElement->dwOffsetEntry = dwOffsetEntry;
1267 return TRUE;
1271 pHashEntry = URLCache_CreateHashTable(pHeader, pHashEntry);
1272 if (!pHashEntry)
1273 return FALSE;
1275 pHashEntry->HashTable[offset].dwHashKey = key;
1276 pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry;
1277 return TRUE;
1280 static HASH_CACHEFILE_ENTRY *URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash)
1282 HASH_CACHEFILE_ENTRY *pHash;
1283 DWORD dwOffset;
1284 int i;
1286 if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)&pHash))
1288 FIXME("no free space for hash table\n");
1289 SetLastError(ERROR_DISK_FULL);
1290 return NULL;
1293 dwOffset = (BYTE *)pHash - (BYTE *)pHeader;
1295 if (pPrevHash)
1296 pPrevHash->dwAddressNext = dwOffset;
1297 else
1298 pHeader->dwOffsetFirstHashTable = dwOffset;
1299 pHash->CacheFileEntry.dwSignature = HASH_SIGNATURE;
1300 pHash->CacheFileEntry.dwBlocksUsed = 0x20;
1301 pHash->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0;
1302 for (i = 0; i < HASHTABLE_SIZE; i++)
1304 pHash->HashTable[i].dwOffsetEntry = 0;
1305 pHash->HashTable[i].dwHashKey = HASHTABLE_FREE;
1307 return pHash;
1310 /***********************************************************************
1311 * GetUrlCacheEntryInfoExA (WININET.@)
1314 BOOL WINAPI GetUrlCacheEntryInfoExA(
1315 LPCSTR lpszUrl,
1316 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1317 LPDWORD lpdwCacheEntryInfoBufSize,
1318 LPSTR lpszReserved,
1319 LPDWORD lpdwReserved,
1320 LPVOID lpReserved,
1321 DWORD dwFlags)
1323 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1324 debugstr_a(lpszUrl),
1325 lpCacheEntryInfo,
1326 lpdwCacheEntryInfoBufSize,
1327 lpszReserved,
1328 lpdwReserved,
1329 lpReserved,
1330 dwFlags);
1332 if ((lpszReserved != NULL) ||
1333 (lpdwReserved != NULL) ||
1334 (lpReserved != NULL))
1336 ERR("Reserved value was not 0\n");
1337 SetLastError(ERROR_INVALID_PARAMETER);
1338 return FALSE;
1340 if (dwFlags != 0)
1341 FIXME("Undocumented flag(s): %x\n", dwFlags);
1342 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1345 /***********************************************************************
1346 * GetUrlCacheEntryInfoA (WININET.@)
1349 BOOL WINAPI GetUrlCacheEntryInfoA(
1350 IN LPCSTR lpszUrlName,
1351 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1352 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1355 LPURLCACHE_HEADER pHeader;
1356 struct _HASH_ENTRY * pHashEntry;
1357 CACHEFILE_ENTRY * pEntry;
1358 URL_CACHEFILE_ENTRY * pUrlEntry;
1359 URLCACHECONTAINER * pContainer;
1361 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1363 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1364 return FALSE;
1366 if (!URLCacheContainer_OpenIndex(pContainer))
1367 return FALSE;
1369 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1370 return FALSE;
1372 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1374 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1375 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1376 SetLastError(ERROR_FILE_NOT_FOUND);
1377 return FALSE;
1380 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1381 if (pEntry->dwSignature != URL_SIGNATURE)
1383 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1384 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1385 SetLastError(ERROR_FILE_NOT_FOUND);
1386 return FALSE;
1389 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1390 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1391 if (pUrlEntry->dwOffsetHeaderInfo)
1392 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1394 if (!URLCache_CopyEntry(
1395 pContainer,
1396 pHeader,
1397 lpCacheEntryInfo,
1398 lpdwCacheEntryInfoBufferSize,
1399 pUrlEntry,
1400 FALSE /* ANSI */))
1402 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1403 return FALSE;
1405 TRACE("Local File Name: %s\n", debugstr_a(lpCacheEntryInfo->lpszLocalFileName));
1407 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1409 return TRUE;
1412 /***********************************************************************
1413 * GetUrlCacheEntryInfoW (WININET.@)
1416 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1417 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1418 LPDWORD lpdwCacheEntryInfoBufferSize)
1420 LPURLCACHE_HEADER pHeader;
1421 struct _HASH_ENTRY * pHashEntry;
1422 CACHEFILE_ENTRY * pEntry;
1423 URL_CACHEFILE_ENTRY * pUrlEntry;
1424 URLCACHECONTAINER * pContainer;
1426 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1428 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1429 return FALSE;
1431 if (!URLCacheContainer_OpenIndex(pContainer))
1432 return FALSE;
1434 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1435 return FALSE;
1437 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1439 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1440 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1441 SetLastError(ERROR_FILE_NOT_FOUND);
1442 return FALSE;
1445 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1446 if (pEntry->dwSignature != URL_SIGNATURE)
1448 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1449 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1450 SetLastError(ERROR_FILE_NOT_FOUND);
1451 return FALSE;
1454 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1455 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1456 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1458 if (!URLCache_CopyEntry(
1459 pContainer,
1460 pHeader,
1461 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1462 lpdwCacheEntryInfoBufferSize,
1463 pUrlEntry,
1464 TRUE /* UNICODE */))
1466 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1467 return FALSE;
1469 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1471 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1473 return TRUE;
1476 /***********************************************************************
1477 * GetUrlCacheEntryInfoExW (WININET.@)
1480 BOOL WINAPI GetUrlCacheEntryInfoExW(
1481 LPCWSTR lpszUrl,
1482 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1483 LPDWORD lpdwCacheEntryInfoBufSize,
1484 LPWSTR lpszReserved,
1485 LPDWORD lpdwReserved,
1486 LPVOID lpReserved,
1487 DWORD dwFlags)
1489 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1490 debugstr_w(lpszUrl),
1491 lpCacheEntryInfo,
1492 lpdwCacheEntryInfoBufSize,
1493 lpszReserved,
1494 lpdwReserved,
1495 lpReserved,
1496 dwFlags);
1498 if ((lpszReserved != NULL) ||
1499 (lpdwReserved != NULL) ||
1500 (lpReserved != NULL))
1502 ERR("Reserved value was not 0\n");
1503 SetLastError(ERROR_INVALID_PARAMETER);
1504 return FALSE;
1506 if (dwFlags != 0)
1507 FIXME("Undocumented flag(s): %x\n", dwFlags);
1508 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1511 /***********************************************************************
1512 * SetUrlCacheEntryInfoA (WININET.@)
1514 BOOL WINAPI SetUrlCacheEntryInfoA(
1515 LPCSTR lpszUrlName,
1516 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1517 DWORD dwFieldControl)
1519 LPURLCACHE_HEADER pHeader;
1520 struct _HASH_ENTRY * pHashEntry;
1521 CACHEFILE_ENTRY * pEntry;
1522 URLCACHECONTAINER * pContainer;
1524 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1526 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1527 return FALSE;
1529 if (!URLCacheContainer_OpenIndex(pContainer))
1530 return FALSE;
1532 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1533 return FALSE;
1535 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1537 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1538 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1539 SetLastError(ERROR_FILE_NOT_FOUND);
1540 return FALSE;
1543 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1544 if (pEntry->dwSignature != URL_SIGNATURE)
1546 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1547 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1548 SetLastError(ERROR_FILE_NOT_FOUND);
1549 return FALSE;
1552 URLCache_SetEntryInfo(
1553 (URL_CACHEFILE_ENTRY *)pEntry,
1554 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1555 dwFieldControl);
1557 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1559 return TRUE;
1562 /***********************************************************************
1563 * SetUrlCacheEntryInfoW (WININET.@)
1565 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1567 LPURLCACHE_HEADER pHeader;
1568 struct _HASH_ENTRY * pHashEntry;
1569 CACHEFILE_ENTRY * pEntry;
1570 URLCACHECONTAINER * pContainer;
1572 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1574 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1575 return FALSE;
1577 if (!URLCacheContainer_OpenIndex(pContainer))
1578 return FALSE;
1580 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1581 return FALSE;
1583 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1585 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1586 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1587 SetLastError(ERROR_FILE_NOT_FOUND);
1588 return FALSE;
1591 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1592 if (pEntry->dwSignature != URL_SIGNATURE)
1594 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1595 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1596 SetLastError(ERROR_FILE_NOT_FOUND);
1597 return FALSE;
1600 URLCache_SetEntryInfo(
1601 (URL_CACHEFILE_ENTRY *)pEntry,
1602 lpCacheEntryInfo,
1603 dwFieldControl);
1605 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1607 return TRUE;
1610 /***********************************************************************
1611 * RetrieveUrlCacheEntryFileA (WININET.@)
1614 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1615 IN LPCSTR lpszUrlName,
1616 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1617 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1618 IN DWORD dwReserved
1621 LPURLCACHE_HEADER pHeader;
1622 struct _HASH_ENTRY * pHashEntry;
1623 CACHEFILE_ENTRY * pEntry;
1624 URL_CACHEFILE_ENTRY * pUrlEntry;
1625 URLCACHECONTAINER * pContainer;
1627 TRACE("(%s, %p, %p, 0x%08x)\n",
1628 debugstr_a(lpszUrlName),
1629 lpCacheEntryInfo,
1630 lpdwCacheEntryInfoBufferSize,
1631 dwReserved);
1633 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1634 return FALSE;
1636 if (!URLCacheContainer_OpenIndex(pContainer))
1637 return FALSE;
1639 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1640 return FALSE;
1642 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1644 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1645 TRACE("entry %s not found!\n", lpszUrlName);
1646 SetLastError(ERROR_FILE_NOT_FOUND);
1647 return FALSE;
1650 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1651 if (pEntry->dwSignature != URL_SIGNATURE)
1653 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1654 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1655 SetLastError(ERROR_FILE_NOT_FOUND);
1656 return FALSE;
1659 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1660 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1661 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1663 pUrlEntry->dwHitRate++;
1664 pUrlEntry->dwUseCount++;
1665 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1667 if (!URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize, pUrlEntry, FALSE))
1669 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1670 return FALSE;
1672 TRACE("Local File Name: %s\n", lpCacheEntryInfo->lpszLocalFileName);
1674 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1676 return TRUE;
1679 /***********************************************************************
1680 * RetrieveUrlCacheEntryFileW (WININET.@)
1683 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1684 IN LPCWSTR lpszUrlName,
1685 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1686 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1687 IN DWORD dwReserved
1690 LPURLCACHE_HEADER pHeader;
1691 struct _HASH_ENTRY * pHashEntry;
1692 CACHEFILE_ENTRY * pEntry;
1693 URL_CACHEFILE_ENTRY * pUrlEntry;
1694 URLCACHECONTAINER * pContainer;
1696 TRACE("(%s, %p, %p, 0x%08x)\n",
1697 debugstr_w(lpszUrlName),
1698 lpCacheEntryInfo,
1699 lpdwCacheEntryInfoBufferSize,
1700 dwReserved);
1702 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
1703 return FALSE;
1705 if (!URLCacheContainer_OpenIndex(pContainer))
1706 return FALSE;
1708 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1709 return FALSE;
1711 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1713 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1714 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1715 SetLastError(ERROR_FILE_NOT_FOUND);
1716 return FALSE;
1719 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1720 if (pEntry->dwSignature != URL_SIGNATURE)
1722 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1723 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1724 SetLastError(ERROR_FILE_NOT_FOUND);
1725 return FALSE;
1728 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1729 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1730 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1732 pUrlEntry->dwHitRate++;
1733 pUrlEntry->dwUseCount++;
1734 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1736 if (!URLCache_CopyEntry(
1737 pContainer,
1738 pHeader,
1739 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1740 lpdwCacheEntryInfoBufferSize,
1741 pUrlEntry,
1742 TRUE /* UNICODE */))
1744 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1745 return FALSE;
1747 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1749 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1751 return TRUE;
1754 /***********************************************************************
1755 * UnlockUrlCacheEntryFileA (WININET.@)
1758 BOOL WINAPI UnlockUrlCacheEntryFileA(
1759 IN LPCSTR lpszUrlName,
1760 IN DWORD dwReserved
1763 LPURLCACHE_HEADER pHeader;
1764 struct _HASH_ENTRY * pHashEntry;
1765 CACHEFILE_ENTRY * pEntry;
1766 URL_CACHEFILE_ENTRY * pUrlEntry;
1767 URLCACHECONTAINER * pContainer;
1769 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
1771 if (dwReserved)
1773 ERR("dwReserved != 0\n");
1774 SetLastError(ERROR_INVALID_PARAMETER);
1775 return FALSE;
1778 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1779 return FALSE;
1781 if (!URLCacheContainer_OpenIndex(pContainer))
1782 return FALSE;
1784 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1785 return FALSE;
1787 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1789 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1790 TRACE("entry %s not found!\n", lpszUrlName);
1791 SetLastError(ERROR_FILE_NOT_FOUND);
1792 return FALSE;
1795 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1796 if (pEntry->dwSignature != URL_SIGNATURE)
1798 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1799 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1800 SetLastError(ERROR_FILE_NOT_FOUND);
1801 return FALSE;
1804 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1806 if (pUrlEntry->dwUseCount == 0)
1808 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1809 return FALSE;
1811 pUrlEntry->dwUseCount--;
1812 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1814 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1816 return TRUE;
1819 /***********************************************************************
1820 * UnlockUrlCacheEntryFileW (WININET.@)
1823 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
1825 LPURLCACHE_HEADER pHeader;
1826 struct _HASH_ENTRY * pHashEntry;
1827 CACHEFILE_ENTRY * pEntry;
1828 URL_CACHEFILE_ENTRY * pUrlEntry;
1829 URLCACHECONTAINER * pContainer;
1831 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
1833 if (dwReserved)
1835 ERR("dwReserved != 0\n");
1836 SetLastError(ERROR_INVALID_PARAMETER);
1837 return FALSE;
1840 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
1841 return FALSE;
1843 if (!URLCacheContainer_OpenIndex(pContainer))
1844 return FALSE;
1846 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1847 return FALSE;
1849 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1851 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1852 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1853 SetLastError(ERROR_FILE_NOT_FOUND);
1854 return FALSE;
1857 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1858 if (pEntry->dwSignature != URL_SIGNATURE)
1860 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1861 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1862 SetLastError(ERROR_FILE_NOT_FOUND);
1863 return FALSE;
1866 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1868 if (pUrlEntry->dwUseCount == 0)
1870 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1871 return FALSE;
1873 pUrlEntry->dwUseCount--;
1874 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1876 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1878 return TRUE;
1881 /***********************************************************************
1882 * CreateUrlCacheEntryA (WININET.@)
1885 BOOL WINAPI CreateUrlCacheEntryA(
1886 IN LPCSTR lpszUrlName,
1887 IN DWORD dwExpectedFileSize,
1888 IN LPCSTR lpszFileExtension,
1889 OUT LPSTR lpszFileName,
1890 IN DWORD dwReserved
1893 DWORD len;
1894 WCHAR *url_name;
1895 WCHAR *file_extension;
1896 WCHAR file_name[MAX_PATH];
1897 BOOL bSuccess = FALSE;
1898 DWORD dwError = 0;
1900 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
1901 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
1903 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
1904 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 &&
1905 (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
1907 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
1908 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
1910 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
1912 bSuccess = TRUE;
1914 else
1916 dwError = GetLastError();
1919 else
1921 dwError = GetLastError();
1923 HeapFree(GetProcessHeap(), 0, file_extension);
1925 else
1927 dwError = GetLastError();
1929 HeapFree(GetProcessHeap(), 0, url_name);
1930 if (!bSuccess)
1931 SetLastError(dwError);
1933 return bSuccess;
1935 /***********************************************************************
1936 * CreateUrlCacheEntryW (WININET.@)
1939 BOOL WINAPI CreateUrlCacheEntryW(
1940 IN LPCWSTR lpszUrlName,
1941 IN DWORD dwExpectedFileSize,
1942 IN LPCWSTR lpszFileExtension,
1943 OUT LPWSTR lpszFileName,
1944 IN DWORD dwReserved
1947 URLCACHECONTAINER * pContainer;
1948 LPURLCACHE_HEADER pHeader;
1949 CHAR szFile[MAX_PATH];
1950 WCHAR szExtension[MAX_PATH];
1951 LPCWSTR lpszUrlPart;
1952 LPCWSTR lpszUrlEnd;
1953 LPCWSTR lpszFileNameExtension;
1954 LPWSTR lpszFileNameNoPath;
1955 int i;
1956 int countnoextension;
1957 BYTE CacheDir;
1958 LONG lBufferSize;
1959 BOOL bFound = FALSE;
1960 int count;
1961 static const WCHAR szWWW[] = {'w','w','w',0};
1963 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
1964 debugstr_w(lpszUrlName),
1965 dwExpectedFileSize,
1966 debugstr_w(lpszFileExtension),
1967 lpszFileName,
1968 dwReserved);
1970 if (dwReserved)
1972 ERR("dwReserved != 0\n");
1973 SetLastError(ERROR_INVALID_PARAMETER);
1974 return FALSE;
1977 for (lpszUrlEnd = lpszUrlName; *lpszUrlEnd; lpszUrlEnd++)
1980 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
1981 lpszUrlEnd--;
1983 for (lpszUrlPart = lpszUrlEnd;
1984 (lpszUrlPart >= lpszUrlName);
1985 lpszUrlPart--)
1987 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
1989 bFound = TRUE;
1990 lpszUrlPart++;
1991 break;
1994 if (!lstrcmpW(lpszUrlPart, szWWW))
1996 lpszUrlPart += lstrlenW(szWWW);
1999 count = lpszUrlEnd - lpszUrlPart;
2001 if (bFound && (count < MAX_PATH))
2003 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2004 if (!len)
2005 return FALSE;
2006 szFile[len] = '\0';
2007 /* FIXME: get rid of illegal characters like \, / and : */
2009 else
2011 FIXME("need to generate a random filename\n");
2014 TRACE("File name: %s\n", debugstr_a(szFile));
2016 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
2017 return FALSE;
2019 if (!URLCacheContainer_OpenIndex(pContainer))
2020 return FALSE;
2022 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2023 return FALSE;
2025 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2027 lBufferSize = MAX_PATH * sizeof(WCHAR);
2028 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
2030 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2032 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2033 lpszFileNameNoPath >= lpszFileName;
2034 --lpszFileNameNoPath)
2036 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2037 break;
2040 countnoextension = lstrlenW(lpszFileNameNoPath);
2041 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2042 if (lpszFileNameExtension)
2043 countnoextension -= lstrlenW(lpszFileNameExtension);
2044 *szExtension = '\0';
2046 if (lpszFileExtension)
2048 szExtension[0] = '.';
2049 lstrcpyW(szExtension+1, lpszFileExtension);
2052 for (i = 0; i < 255; i++)
2054 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2055 HANDLE hFile;
2056 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2057 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2058 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2059 if (hFile != INVALID_HANDLE_VALUE)
2061 CloseHandle(hFile);
2062 return TRUE;
2066 return FALSE;
2070 /***********************************************************************
2071 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2073 * The bug we are compensating for is that some drongo at Microsoft
2074 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2075 * As a consequence, CommitUrlCacheEntryA has been effectively
2076 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2077 * is still defined as LPCWSTR. The result (other than madness) is
2078 * that we always need to store lpHeaderInfo in CP_ACP rather than
2079 * in UTF16, and we need to avoid converting lpHeaderInfo in
2080 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2081 * result will lose data for arbitrary binary data.
2084 static BOOL WINAPI CommitUrlCacheEntryInternal(
2085 IN LPCWSTR lpszUrlName,
2086 IN LPCWSTR lpszLocalFileName,
2087 IN FILETIME ExpireTime,
2088 IN FILETIME LastModifiedTime,
2089 IN DWORD CacheEntryType,
2090 IN LPBYTE lpHeaderInfo,
2091 IN DWORD dwHeaderSize,
2092 IN LPCWSTR lpszFileExtension,
2093 IN LPCWSTR lpszOriginalUrl
2096 URLCACHECONTAINER * pContainer;
2097 LPURLCACHE_HEADER pHeader;
2098 struct _HASH_ENTRY * pHashEntry;
2099 CACHEFILE_ENTRY * pEntry;
2100 URL_CACHEFILE_ENTRY * pUrlEntry;
2101 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2102 DWORD dwOffsetLocalFileName = 0;
2103 DWORD dwOffsetHeader = 0;
2104 DWORD dwFileSizeLow = 0;
2105 DWORD dwFileSizeHigh = 0;
2106 BYTE cDirectory = 0;
2107 char achFile[MAX_PATH];
2108 char achUrl[MAX_PATH];
2109 char *pchLocalFileName = 0;
2111 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2112 debugstr_w(lpszUrlName),
2113 debugstr_w(lpszLocalFileName),
2114 CacheEntryType,
2115 lpHeaderInfo,
2116 dwHeaderSize,
2117 debugstr_w(lpszFileExtension),
2118 debugstr_w(lpszOriginalUrl));
2120 if (lpszOriginalUrl)
2121 WARN(": lpszOriginalUrl ignored\n");
2123 if (lpszLocalFileName)
2125 HANDLE hFile;
2127 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2128 if (hFile == INVALID_HANDLE_VALUE)
2130 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2131 return FALSE;
2134 /* Get file size */
2135 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2136 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2138 ERR("couldn't get file size (error is %d)\n", GetLastError());
2139 CloseHandle(hFile);
2140 return FALSE;
2143 CloseHandle(hFile);
2146 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
2147 return FALSE;
2149 if (!URLCacheContainer_OpenIndex(pContainer))
2150 return FALSE;
2152 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2153 return FALSE;
2155 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, achUrl, -1, NULL, NULL);
2157 if (URLCache_FindHash(pHeader, achUrl, &pHashEntry))
2159 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2160 FIXME("entry already in cache - don't know what to do!\n");
2162 * SetLastError(ERROR_FILE_NOT_FOUND);
2163 * return FALSE;
2165 return TRUE;
2168 if (lpszLocalFileName)
2170 BOOL bFound = FALSE;
2172 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2174 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2175 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2176 SetLastError(ERROR_INVALID_PARAMETER);
2177 return FALSE;
2180 /* skip container path prefix */
2181 lpszLocalFileName += lstrlenW(pContainer->path);
2183 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, -1, NULL, NULL);
2184 pchLocalFileName = achFile;
2186 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2188 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2190 bFound = TRUE;
2191 break;
2195 if (!bFound)
2197 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2198 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2199 SetLastError(ERROR_INVALID_PARAMETER);
2200 return FALSE;
2203 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2206 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(achUrl) + 1);
2207 if (lpszLocalFileName)
2209 dwOffsetLocalFileName = dwBytesNeeded;
2210 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2212 if (lpHeaderInfo)
2214 dwOffsetHeader = dwBytesNeeded;
2215 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2218 /* round up to next block */
2219 if (dwBytesNeeded % BLOCKSIZE)
2221 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2222 dwBytesNeeded += BLOCKSIZE;
2225 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2227 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2228 ERR("no free entries\n");
2229 SetLastError(ERROR_DISK_FULL);
2230 return FALSE;
2233 /* FindFirstFreeEntry fills in blocks used */
2234 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2235 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2236 pUrlEntry->CacheDir = cDirectory;
2237 pUrlEntry->CacheEntryType = CacheEntryType;
2238 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2239 pUrlEntry->dwExemptDelta = 0;
2240 pUrlEntry->dwHitRate = 0;
2241 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2242 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2243 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2244 pUrlEntry->dwSizeHigh = 0;
2245 pUrlEntry->dwSizeLow = dwFileSizeLow;
2246 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2247 pUrlEntry->dwUseCount = 0;
2248 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2249 pUrlEntry->LastModifiedTime = LastModifiedTime;
2250 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2251 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2252 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2253 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2255 /*** Unknowns ***/
2256 pUrlEntry->dwUnknown1 = 0;
2257 pUrlEntry->dwUnknown2 = 0;
2258 pUrlEntry->dwUnknown3 = 0x60;
2259 pUrlEntry->Unknown4 = 0;
2260 pUrlEntry->wUnknown5 = 0x1010;
2261 pUrlEntry->dwUnknown6 = 0;
2262 pUrlEntry->dwUnknown7 = 0;
2263 pUrlEntry->dwUnknown8 = 0;
2266 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, achUrl);
2267 if (dwOffsetLocalFileName)
2268 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2269 if (dwOffsetHeader)
2270 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2272 if (!URLCache_AddEntryToHash(pHeader, achUrl, (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader)))
2274 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2275 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2276 return FALSE;
2279 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2281 return TRUE;
2284 /***********************************************************************
2285 * CommitUrlCacheEntryA (WININET.@)
2288 BOOL WINAPI CommitUrlCacheEntryA(
2289 IN LPCSTR lpszUrlName,
2290 IN LPCSTR lpszLocalFileName,
2291 IN FILETIME ExpireTime,
2292 IN FILETIME LastModifiedTime,
2293 IN DWORD CacheEntryType,
2294 IN LPBYTE lpHeaderInfo,
2295 IN DWORD dwHeaderSize,
2296 IN LPCSTR lpszFileExtension,
2297 IN LPCSTR lpszOriginalUrl
2300 DWORD len;
2301 WCHAR *url_name;
2302 WCHAR *local_file_name;
2303 WCHAR *original_url = NULL;
2304 BOOL bSuccess = FALSE;
2305 DWORD dwError = 0;
2307 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2308 debugstr_a(lpszUrlName),
2309 debugstr_a(lpszLocalFileName),
2310 CacheEntryType,
2311 lpHeaderInfo,
2312 dwHeaderSize,
2313 debugstr_a(lpszFileExtension),
2314 debugstr_a(lpszOriginalUrl));
2316 if (lpszFileExtension != 0)
2318 SetLastError(ERROR_INVALID_PARAMETER);
2319 return FALSE;
2321 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
2322 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2324 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2325 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0)) != 0 &&
2326 (local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2328 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2329 if (!lpszOriginalUrl ||
2330 ((len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0)) != 0 &&
2331 (original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0))
2333 if (original_url)
2334 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2335 if (CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2336 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2337 NULL, original_url))
2339 bSuccess = TRUE;
2341 else
2343 dwError = GetLastError();
2345 HeapFree(GetProcessHeap(), 0, original_url);
2347 else
2349 dwError = GetLastError();
2351 HeapFree(GetProcessHeap(), 0, local_file_name);
2353 else
2355 dwError = GetLastError();
2357 HeapFree(GetProcessHeap(), 0, url_name);
2358 if (!bSuccess)
2359 SetLastError(dwError);
2361 return bSuccess;
2364 /***********************************************************************
2365 * CommitUrlCacheEntryW (WININET.@)
2368 BOOL WINAPI CommitUrlCacheEntryW(
2369 IN LPCWSTR lpszUrlName,
2370 IN LPCWSTR lpszLocalFileName,
2371 IN FILETIME ExpireTime,
2372 IN FILETIME LastModifiedTime,
2373 IN DWORD CacheEntryType,
2374 IN LPWSTR lpHeaderInfo,
2375 IN DWORD dwHeaderSize,
2376 IN LPCWSTR lpszFileExtension,
2377 IN LPCWSTR lpszOriginalUrl
2380 DWORD dwError = 0;
2381 BOOL bSuccess = FALSE;
2382 DWORD len = 0;
2383 CHAR *header_info = NULL;
2385 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2386 debugstr_w(lpszUrlName),
2387 debugstr_w(lpszLocalFileName),
2388 CacheEntryType,
2389 lpHeaderInfo,
2390 dwHeaderSize,
2391 debugstr_w(lpszFileExtension),
2392 debugstr_w(lpszOriginalUrl));
2394 if (!lpHeaderInfo ||
2395 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2396 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2398 if (header_info)
2399 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2400 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2401 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2403 bSuccess = TRUE;
2405 else
2407 dwError = GetLastError();
2409 if (header_info)
2411 HeapFree(GetProcessHeap(), 0, header_info);
2412 if (!bSuccess)
2413 SetLastError(dwError);
2416 return bSuccess;
2419 /***********************************************************************
2420 * ReadUrlCacheEntryStream (WININET.@)
2423 BOOL WINAPI ReadUrlCacheEntryStream(
2424 IN HANDLE hUrlCacheStream,
2425 IN DWORD dwLocation,
2426 IN OUT LPVOID lpBuffer,
2427 IN OUT LPDWORD lpdwLen,
2428 IN DWORD dwReserved
2431 /* Get handle to file from 'stream' */
2432 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2434 if (dwReserved != 0)
2436 ERR("dwReserved != 0\n");
2437 SetLastError(ERROR_INVALID_PARAMETER);
2438 return FALSE;
2441 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2443 SetLastError(ERROR_INVALID_HANDLE);
2444 return FALSE;
2447 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2448 return FALSE;
2449 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2452 /***********************************************************************
2453 * RetrieveUrlCacheEntryStreamA (WININET.@)
2456 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2457 IN LPCSTR lpszUrlName,
2458 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2459 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2460 IN BOOL fRandomRead,
2461 IN DWORD dwReserved
2464 /* NOTE: this is not the same as the way that the native
2465 * version allocates 'stream' handles. I did it this way
2466 * as it is much easier and no applications should depend
2467 * on this behaviour. (Native version appears to allocate
2468 * indices into a table)
2470 STREAM_HANDLE * pStream;
2471 HANDLE hFile;
2473 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2474 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2476 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2477 lpCacheEntryInfo,
2478 lpdwCacheEntryInfoBufferSize,
2479 dwReserved))
2481 return NULL;
2484 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2485 GENERIC_READ,
2486 FILE_SHARE_READ,
2487 NULL,
2488 OPEN_EXISTING,
2489 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2490 NULL);
2491 if (hFile == INVALID_HANDLE_VALUE)
2492 return FALSE;
2494 /* allocate handle storage space */
2495 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2496 if (!pStream)
2498 CloseHandle(hFile);
2499 SetLastError(ERROR_OUTOFMEMORY);
2500 return FALSE;
2503 pStream->hFile = hFile;
2504 strcpy(pStream->lpszUrl, lpszUrlName);
2505 return (HANDLE)pStream;
2508 /***********************************************************************
2509 * RetrieveUrlCacheEntryStreamW (WININET.@)
2512 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2513 IN LPCWSTR lpszUrlName,
2514 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2515 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2516 IN BOOL fRandomRead,
2517 IN DWORD dwReserved
2520 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2521 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2522 return NULL;
2525 /***********************************************************************
2526 * UnlockUrlCacheEntryStream (WININET.@)
2529 BOOL WINAPI UnlockUrlCacheEntryStream(
2530 IN HANDLE hUrlCacheStream,
2531 IN DWORD dwReserved
2534 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2536 if (dwReserved != 0)
2538 ERR("dwReserved != 0\n");
2539 SetLastError(ERROR_INVALID_PARAMETER);
2540 return FALSE;
2543 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2545 SetLastError(ERROR_INVALID_HANDLE);
2546 return FALSE;
2549 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2550 return FALSE;
2552 /* close file handle */
2553 CloseHandle(pStream->hFile);
2555 /* free allocated space */
2556 HeapFree(GetProcessHeap(), 0, pStream);
2558 return TRUE;
2562 /***********************************************************************
2563 * DeleteUrlCacheEntryA (WININET.@)
2566 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2568 URLCACHECONTAINER * pContainer;
2569 LPURLCACHE_HEADER pHeader;
2570 struct _HASH_ENTRY * pHashEntry;
2571 CACHEFILE_ENTRY * pEntry;
2573 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2575 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
2576 return FALSE;
2578 if (!URLCacheContainer_OpenIndex(pContainer))
2579 return FALSE;
2581 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2582 return FALSE;
2584 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2586 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2587 TRACE("entry %s not found!\n", lpszUrlName);
2588 SetLastError(ERROR_FILE_NOT_FOUND);
2589 return FALSE;
2592 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2593 URLCache_DeleteEntry(pHeader, pEntry);
2595 URLCache_DeleteEntryFromHash(pHashEntry);
2597 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2599 return TRUE;
2602 /***********************************************************************
2603 * DeleteUrlCacheEntryW (WININET.@)
2606 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2608 URLCACHECONTAINER * pContainer;
2609 LPURLCACHE_HEADER pHeader;
2610 struct _HASH_ENTRY * pHashEntry;
2611 CACHEFILE_ENTRY * pEntry;
2612 LPSTR urlA;
2613 int url_len;
2615 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2617 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2618 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
2619 if (!urlA)
2621 SetLastError(ERROR_OUTOFMEMORY);
2622 return FALSE;
2624 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, urlA, url_len, NULL, NULL);
2626 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
2628 HeapFree(GetProcessHeap(), 0, urlA);
2629 return FALSE;
2631 if (!URLCacheContainer_OpenIndex(pContainer))
2633 HeapFree(GetProcessHeap(), 0, urlA);
2634 return FALSE;
2636 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2638 HeapFree(GetProcessHeap(), 0, urlA);
2639 return FALSE;
2642 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
2644 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2645 TRACE("entry %s not found!\n", debugstr_a(urlA));
2646 HeapFree(GetProcessHeap(), 0, urlA);
2647 SetLastError(ERROR_FILE_NOT_FOUND);
2648 return FALSE;
2651 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2652 URLCache_DeleteEntry(pHeader, pEntry);
2654 URLCache_DeleteEntryFromHash(pHashEntry);
2656 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2658 HeapFree(GetProcessHeap(), 0, urlA);
2659 return TRUE;
2662 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2664 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2665 return TRUE;
2668 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2670 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2671 return TRUE;
2674 /***********************************************************************
2675 * CreateCacheContainerA (WININET.@)
2677 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2678 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2680 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2681 d1, d2, d3, d4, d5, d6, d7, d8);
2682 return TRUE;
2685 /***********************************************************************
2686 * CreateCacheContainerW (WININET.@)
2688 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2689 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2691 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2692 d1, d2, d3, d4, d5, d6, d7, d8);
2693 return TRUE;
2696 /***********************************************************************
2697 * FindCloseUrlCache (WININET.@)
2699 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
2701 FIXME("(%p) stub\n", hEnumHandle);
2702 return TRUE;
2705 /***********************************************************************
2706 * FindFirstUrlCacheContainerA (WININET.@)
2708 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2710 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
2711 return NULL;
2714 /***********************************************************************
2715 * FindFirstUrlCacheContainerW (WININET.@)
2717 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2719 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
2720 return NULL;
2723 /***********************************************************************
2724 * FindNextUrlCacheContainerA (WININET.@)
2726 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
2728 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2729 return FALSE;
2732 /***********************************************************************
2733 * FindNextUrlCacheContainerW (WININET.@)
2735 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
2737 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2738 return FALSE;
2741 HANDLE WINAPI FindFirstUrlCacheEntryExA(
2742 LPCSTR lpszUrlSearchPattern,
2743 DWORD dwFlags,
2744 DWORD dwFilter,
2745 GROUPID GroupId,
2746 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2747 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2748 LPVOID lpReserved,
2749 LPDWORD pcbReserved2,
2750 LPVOID lpReserved3
2753 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
2754 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2755 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2756 SetLastError(ERROR_FILE_NOT_FOUND);
2757 return NULL;
2760 HANDLE WINAPI FindFirstUrlCacheEntryExW(
2761 LPCWSTR lpszUrlSearchPattern,
2762 DWORD dwFlags,
2763 DWORD dwFilter,
2764 GROUPID GroupId,
2765 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2766 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2767 LPVOID lpReserved,
2768 LPDWORD pcbReserved2,
2769 LPVOID lpReserved3
2772 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
2773 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2774 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2775 SetLastError(ERROR_FILE_NOT_FOUND);
2776 return NULL;
2779 /***********************************************************************
2780 * FindFirstUrlCacheEntryA (WININET.@)
2783 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
2784 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2786 FIXME("(%s, %p, %p): stub\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2787 SetLastError(ERROR_FILE_NOT_FOUND);
2788 return 0;
2791 /***********************************************************************
2792 * FindFirstUrlCacheEntryW (WININET.@)
2795 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
2796 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2798 FIXME("(%s, %p, %p): stub\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2799 SetLastError(ERROR_FILE_NOT_FOUND);
2800 return 0;
2803 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
2804 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
2806 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
2807 dwSearchCondition, lpGroupId, lpReserved);
2808 return NULL;
2811 BOOL WINAPI FindNextUrlCacheEntryA(
2812 HANDLE hEnumHandle,
2813 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
2814 LPDWORD lpdwNextCacheEntryInfoBufferSize
2817 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2818 return FALSE;
2821 BOOL WINAPI FindNextUrlCacheEntryW(
2822 HANDLE hEnumHandle,
2823 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
2824 LPDWORD lpdwNextCacheEntryInfoBufferSize
2827 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2828 return FALSE;
2831 BOOL WINAPI FindNextUrlCacheEntryExA(
2832 HANDLE hEnumHandle,
2833 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2834 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2835 LPVOID lpReserved,
2836 LPDWORD pcbReserved2,
2837 LPVOID lpReserved3
2840 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2841 lpReserved, pcbReserved2, lpReserved3);
2842 return FALSE;
2845 BOOL WINAPI FindNextUrlCacheEntryExW(
2846 HANDLE hEnumHandle,
2847 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2848 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2849 LPVOID lpReserved,
2850 LPDWORD pcbReserved2,
2851 LPVOID lpReserved3
2854 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2855 lpReserved, pcbReserved2, lpReserved3);
2856 return FALSE;
2859 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
2861 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
2862 return FALSE;
2865 /***********************************************************************
2866 * CreateUrlCacheGroup (WININET.@)
2869 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
2871 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
2872 return FALSE;
2875 /***********************************************************************
2876 * DeleteUrlCacheGroup (WININET.@)
2879 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
2881 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
2882 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
2883 return FALSE;
2886 /***********************************************************************
2887 * SetUrlCacheEntryGroupA (WININET.@)
2890 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
2891 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2892 LPVOID lpReserved)
2894 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
2895 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2896 pbGroupAttributes, cbGroupAttributes, lpReserved);
2897 SetLastError(ERROR_FILE_NOT_FOUND);
2898 return FALSE;
2901 /***********************************************************************
2902 * SetUrlCacheEntryGroupW (WININET.@)
2905 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
2906 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2907 LPVOID lpReserved)
2909 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
2910 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2911 pbGroupAttributes, cbGroupAttributes, lpReserved);
2912 SetLastError(ERROR_FILE_NOT_FOUND);
2913 return FALSE;
2916 /***********************************************************************
2917 * GetUrlCacheConfigInfoW (WININET.@)
2919 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
2921 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
2922 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2923 return FALSE;
2926 /***********************************************************************
2927 * GetUrlCacheConfigInfoA (WININET.@)
2929 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
2931 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
2933 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
2934 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2935 return FALSE;
2938 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2939 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
2940 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2942 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
2943 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2944 lpdwGroupInfo, lpReserved);
2945 return FALSE;
2948 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2949 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
2950 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2952 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
2953 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2954 lpdwGroupInfo, lpReserved);
2955 return FALSE;
2958 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2959 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
2961 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
2962 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2963 return TRUE;
2966 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2967 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
2969 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
2970 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2971 return TRUE;
2974 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
2976 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
2977 return TRUE;
2980 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
2982 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
2983 return TRUE;
2986 /***********************************************************************
2987 * DeleteIE3Cache (WININET.@)
2989 * Deletes the files used by the IE3 URL caching system.
2991 * PARAMS
2992 * hWnd [I] A dummy window.
2993 * hInst [I] Instance of process calling the function.
2994 * lpszCmdLine [I] Options used by function.
2995 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
2997 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
2999 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3000 return 0;
3003 /***********************************************************************
3004 * IsUrlCacheEntryExpiredA (WININET.@)
3006 * PARAMS
3007 * url [I] Url
3008 * dwFlags [I] Unknown
3009 * pftLastModified [O] Last modified time
3011 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3013 LPURLCACHE_HEADER pHeader;
3014 struct _HASH_ENTRY * pHashEntry;
3015 CACHEFILE_ENTRY * pEntry;
3016 URL_CACHEFILE_ENTRY * pUrlEntry;
3017 URLCACHECONTAINER * pContainer;
3019 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3021 if (!URLCacheContainers_FindContainerA(url, &pContainer))
3022 return FALSE;
3024 if (!URLCacheContainer_OpenIndex(pContainer))
3025 return FALSE;
3027 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3028 return FALSE;
3030 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3032 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3033 TRACE("entry %s not found!\n", url);
3034 SetLastError(ERROR_FILE_NOT_FOUND);
3035 return FALSE;
3038 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3039 if (pEntry->dwSignature != URL_SIGNATURE)
3041 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3042 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3043 SetLastError(ERROR_FILE_NOT_FOUND);
3044 return FALSE;
3047 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3049 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3051 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3053 return TRUE;
3056 /***********************************************************************
3057 * IsUrlCacheEntryExpiredW (WININET.@)
3059 * PARAMS
3060 * url [I] Url
3061 * dwFlags [I] Unknown
3062 * pftLastModified [O] Last modified time
3064 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3066 LPURLCACHE_HEADER pHeader;
3067 struct _HASH_ENTRY * pHashEntry;
3068 CACHEFILE_ENTRY * pEntry;
3069 URL_CACHEFILE_ENTRY * pUrlEntry;
3070 URLCACHECONTAINER * pContainer;
3072 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3074 if (!URLCacheContainers_FindContainerW(url, &pContainer))
3075 return FALSE;
3077 if (!URLCacheContainer_OpenIndex(pContainer))
3078 return FALSE;
3080 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3081 return FALSE;
3083 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3085 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3086 TRACE("entry %s not found!\n", debugstr_w(url));
3087 SetLastError(ERROR_FILE_NOT_FOUND);
3088 return FALSE;
3091 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3092 if (pEntry->dwSignature != URL_SIGNATURE)
3094 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3095 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3096 SetLastError(ERROR_FILE_NOT_FOUND);
3097 return FALSE;
3100 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3102 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3104 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3106 return TRUE;