2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003-2008 Robert Shearman
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
26 #include "wine/port.h"
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
31 #if defined(__MINGW32__) || defined (_MSC_VER)
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
56 #include "wine/unicode.h"
57 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
61 #define ENTRY_START_OFFSET 0x4000
64 #define HASHTABLE_SIZE 448
65 #define HASHTABLE_BLOCKSIZE 7
66 #define HASHTABLE_FREE 3
67 #define ALLOCATION_TABLE_OFFSET 0x250
68 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
69 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
70 #define NEWFILE_NUM_BLOCKS 0xd80
71 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
73 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
74 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
75 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
76 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
77 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
79 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
81 typedef struct _CACHEFILE_ENTRY
85 DWORD dwSignature; /* e.g. "URL " */
86 /* CHAR szSignature[4];
88 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
91 typedef struct _URL_CACHEFILE_ENTRY
93 CACHEFILE_ENTRY CacheFileEntry;
94 FILETIME LastModifiedTime;
95 FILETIME LastAccessTime;
96 WORD wExpiredDate; /* expire date in dos format */
97 WORD wExpiredTime; /* expire time in dos format */
98 DWORD dwUnknown1; /* usually zero */
99 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
100 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
101 DWORD dwUnknown2; /* usually zero */
102 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
103 DWORD dwUnknown3; /* usually 0x60 */
104 DWORD dwOffsetUrl; /* offset of start of url from start of entry */
105 BYTE CacheDir; /* index of cache directory this url is stored in */
106 BYTE Unknown4; /* usually zero */
107 WORD wUnknown5; /* usually 0x1010 */
108 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
109 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
110 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
111 DWORD dwHeaderInfoSize;
112 DWORD dwOffsetFileExtension; /* offset of start of file extension from start of entry */
113 WORD wLastSyncDate; /* last sync date in dos format */
114 WORD wLastSyncTime; /* last sync time in dos format */
115 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
116 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
117 WORD wUnknownDate; /* usually same as wLastSyncDate */
118 WORD wUnknownTime; /* usually same as wLastSyncTime */
119 DWORD dwUnknown7; /* usually zero */
120 DWORD dwUnknown8; /* usually zero */
121 /* packing to dword align start of next field */
122 /* CHAR szSourceUrlName[]; (url) */
123 /* packing to dword align start of next field */
124 /* CHAR szLocalFileName[]; (local file name excluding path) */
125 /* packing to dword align start of next field */
126 /* CHAR szHeaderInfo[]; (header info) */
127 } URL_CACHEFILE_ENTRY;
135 typedef struct _HASH_CACHEFILE_ENTRY
137 CACHEFILE_ENTRY CacheFileEntry;
139 DWORD dwHashTableNumber;
140 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
141 } HASH_CACHEFILE_ENTRY;
143 typedef struct _DIRECTORY_DATA
146 char filename[DIR_LENGTH];
149 typedef struct _URLCACHE_HEADER
151 char szSignature[28];
153 DWORD dwOffsetFirstHashTable;
154 DWORD dwIndexCapacityInBlocks;
157 DWORD dwCacheLimitLow; /* disk space limit for cache */
158 DWORD dwCacheLimitHigh; /* disk space limit for cache */
159 DWORD dwUnknown4; /* current disk space usage for cache */
160 DWORD dwUnknown5; /* current disk space usage for cache */
161 DWORD dwUnknown6; /* possibly a flag? */
163 BYTE DirectoryCount; /* number of directory_data's */
164 BYTE Unknown8[3]; /* just padding? */
165 DIRECTORY_DATA directory_data[1]; /* first directory entry */
166 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
167 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
169 typedef struct _STREAM_HANDLE
175 typedef struct _URLCACHECONTAINER
177 struct list entry; /* part of a list */
178 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
179 LPWSTR path; /* path to url container directory */
180 HANDLE hMapping; /* handle of file mapping */
181 DWORD file_size; /* size of file when mapping was opened */
182 HANDLE hMutex; /* handle of mutex */
186 /* List of all containers available */
187 static struct list UrlContainers = LIST_INIT(UrlContainers);
189 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash);
191 /***********************************************************************
192 * URLCache_PathToObjectName (Internal)
194 * Converts a path to a name suitable for use as a Win32 object name.
195 * Replaces '\\' characters in-place with the specified character
196 * (usually '_' or '!')
202 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
204 for (; *lpszPath; lpszPath++)
206 if (*lpszPath == '\\')
211 /***********************************************************************
212 * URLCacheContainer_OpenIndex (Internal)
214 * Opens the index file and saves mapping handle in hCacheIndexMapping
217 * ERROR_SUCCESS if succeeded
218 * Any other Win32 error code if failed
221 static DWORD URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
224 WCHAR wszFilePath[MAX_PATH];
227 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
228 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
230 if (pContainer->hMapping)
231 return ERROR_SUCCESS;
233 strcpyW(wszFilePath, pContainer->path);
234 strcatW(wszFilePath, wszIndex);
236 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
237 if (hFile == INVALID_HANDLE_VALUE)
239 /* Maybe the directory wasn't there? Try to create it */
240 if (CreateDirectoryW(pContainer->path, 0))
241 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
243 if (hFile == INVALID_HANDLE_VALUE)
245 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath));
246 return GetLastError();
249 /* At this stage we need the mutex because we may be about to create the
252 WaitForSingleObject(pContainer->hMutex, INFINITE);
254 dwFileSize = GetFileSize(hFile, NULL);
255 if (dwFileSize == INVALID_FILE_SIZE)
257 ReleaseMutex(pContainer->hMutex);
258 return GetLastError();
263 static const CHAR szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content";
265 char achZeroes[0x1000];
267 DWORD dwError = ERROR_SUCCESS;
269 /* Write zeroes to the entire file so we can safely map it without
270 * fear of getting a SEGV because the disk is full.
272 memset(achZeroes, 0, sizeof(achZeroes));
273 for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes))
275 DWORD dwWrite = sizeof(achZeroes);
278 if (NEWFILE_SIZE - dwOffset < dwWrite)
279 dwWrite = NEWFILE_SIZE - dwOffset;
280 if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) ||
281 dwWritten != dwWrite)
283 /* If we fail to write, we need to return the error that
284 * cause the problem and also make sure the file is no
285 * longer there, if possible.
287 dwError = GetLastError();
293 if (dwError == ERROR_SUCCESS)
295 HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL);
299 URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE);
304 WCHAR wszDirPath[MAX_PATH];
307 HASH_CACHEFILE_ENTRY *pHashEntry;
309 dwFileSize = NEWFILE_SIZE;
311 /* First set some constants and defaults in the header */
312 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
313 pHeader->dwFileSize = dwFileSize;
314 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
315 /* 127MB - taken from default for Windows 2000 */
316 pHeader->dwCacheLimitHigh = 0;
317 pHeader->dwCacheLimitLow = 0x07ff5400;
318 /* Copied from a Windows 2000 cache index */
319 pHeader->DirectoryCount = 4;
321 /* If the registry has a cache size set, use the registry value */
322 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
325 DWORD len = sizeof(dw);
328 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
329 (BYTE *) &dw, &len) == ERROR_SUCCESS &&
330 keytype == REG_DWORD)
332 pHeader->dwCacheLimitHigh = (dw >> 22);
333 pHeader->dwCacheLimitLow = dw << 10;
338 URLCache_CreateHashTable(pHeader, NULL, &pHashEntry);
340 /* Last step - create the directories */
342 strcpyW(wszDirPath, pContainer->path);
343 pwchDir = wszDirPath + strlenW(wszDirPath);
346 GetSystemTimeAsFileTime(&ft);
348 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
350 /* The following values were copied from a Windows index.
351 * I don't know what the values are supposed to mean but
352 * have made them the same in the hope that this will
353 * be better for compatibility
355 pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
359 ULONGLONG n = ft.dwHighDateTime;
361 /* Generate a file name to attempt to create.
362 * This algorithm will create what will appear
363 * to be random and unrelated directory names
364 * of up to 9 characters in length.
367 n += ft.dwLowDateTime;
368 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
370 for (k = 0; k < 8; ++k)
374 /* Dividing by a prime greater than 36 helps
375 * with the appearance of randomness
380 pwchDir[k] = '0' + r;
382 pwchDir[k] = 'A' + (r - 10);
385 if (CreateDirectoryW(wszDirPath, 0))
387 /* The following is OK because we generated an
388 * 8 character directory name made from characters
389 * [A-Z0-9], which are equivalent for all code
390 * pages and for UTF-16
392 for (k = 0; k < 8; ++k)
393 pHeader->directory_data[i].filename[k] = pwchDir[k];
398 /* Give up. The most likely cause of this
399 * is a full disk, but whatever the cause
400 * is, it should be more than apparent that
403 dwError = GetLastError();
409 UnmapViewOfFile(pHeader);
413 dwError = GetLastError();
415 CloseHandle(hMapping);
419 dwError = GetLastError();
426 DeleteFileW(wszFilePath);
427 ReleaseMutex(pContainer->hMutex);
433 ReleaseMutex(pContainer->hMutex);
435 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
436 URLCache_PathToObjectName(wszFilePath, '_');
437 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
438 if (!pContainer->hMapping)
439 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
441 if (!pContainer->hMapping)
443 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
444 return GetLastError();
447 return ERROR_SUCCESS;
450 /***********************************************************************
451 * URLCacheContainer_CloseIndex (Internal)
459 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
461 CloseHandle(pContainer->hMapping);
462 pContainer->hMapping = NULL;
465 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
467 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
468 int cache_prefix_len = strlenW(cache_prefix);
475 pContainer->hMapping = NULL;
476 pContainer->file_size = 0;
478 pContainer->path = heap_strdupW(path);
479 if (!pContainer->path)
481 HeapFree(GetProcessHeap(), 0, pContainer);
485 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
486 if (!pContainer->cache_prefix)
488 HeapFree(GetProcessHeap(), 0, pContainer->path);
489 HeapFree(GetProcessHeap(), 0, pContainer);
493 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
495 CharLowerW(mutex_name);
496 URLCache_PathToObjectName(mutex_name, '!');
498 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
500 ERR("couldn't create mutex (error is %d)\n", GetLastError());
501 HeapFree(GetProcessHeap(), 0, pContainer->path);
502 HeapFree(GetProcessHeap(), 0, pContainer);
506 list_add_head(&UrlContainers, &pContainer->entry);
511 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
513 list_remove(&pContainer->entry);
515 URLCacheContainer_CloseIndex(pContainer);
516 CloseHandle(pContainer->hMutex);
517 HeapFree(GetProcessHeap(), 0, pContainer->path);
518 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
519 HeapFree(GetProcessHeap(), 0, pContainer);
522 void URLCacheContainers_CreateDefaults(void)
524 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
525 static const WCHAR UrlPrefix[] = {0};
526 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
527 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
528 static const WCHAR CookieSuffix[] = {0};
529 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
532 int nFolder; /* CSIDL_* constant */
533 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
534 const WCHAR * cache_prefix; /* prefix used to reference the container */
535 } DefaultContainerData[] =
537 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
538 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
539 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
543 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
545 WCHAR wszCachePath[MAX_PATH];
546 WCHAR wszMutexName[MAX_PATH];
547 int path_len, suffix_len;
549 if (!SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE))
551 ERR("Couldn't get path for default container %u\n", i);
554 path_len = strlenW(wszCachePath);
555 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
557 if (path_len + suffix_len + 2 > MAX_PATH)
559 ERR("Path too long\n");
563 wszCachePath[path_len] = '\\';
564 wszCachePath[path_len+1] = 0;
566 strcpyW(wszMutexName, wszCachePath);
570 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
571 wszCachePath[path_len + suffix_len + 1] = '\\';
572 wszCachePath[path_len + suffix_len + 2] = '\0';
575 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
579 void URLCacheContainers_DeleteAll(void)
581 while(!list_empty(&UrlContainers))
582 URLCacheContainer_DeleteContainer(
583 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
587 static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
589 URLCACHECONTAINER * pContainer;
591 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
594 return ERROR_INVALID_PARAMETER;
596 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
598 int prefix_len = strlenW(pContainer->cache_prefix);
599 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
601 TRACE("found container with prefix %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
602 *ppContainer = pContainer;
603 return ERROR_SUCCESS;
606 ERR("no container found\n");
607 return ERROR_FILE_NOT_FOUND;
610 static DWORD URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
615 if (lpszUrl && !(url = heap_strdupAtoW(lpszUrl)))
616 return ERROR_OUTOFMEMORY;
618 ret = URLCacheContainers_FindContainerW(url, ppContainer);
619 HeapFree(GetProcessHeap(), 0, url);
623 static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, URLCACHECONTAINER ** ppContainer)
626 URLCACHECONTAINER * pContainer;
628 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern));
630 /* non-NULL search pattern only returns one container ever */
631 if (lpwszSearchPattern && dwIndex > 0)
634 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
636 if (lpwszSearchPattern)
638 if (!strcmpW(pContainer->cache_prefix, lpwszSearchPattern))
640 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
641 *ppContainer = pContainer;
649 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
650 *ppContainer = pContainer;
659 /***********************************************************************
660 * URLCacheContainer_LockIndex (Internal)
662 * Locks the index for system-wide exclusive access.
665 * Cache file header if successful
666 * NULL if failed and calls SetLastError.
668 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
672 URLCACHE_HEADER * pHeader;
676 WaitForSingleObject(pContainer->hMutex, INFINITE);
678 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
682 ReleaseMutex(pContainer->hMutex);
683 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
686 pHeader = (URLCACHE_HEADER *)pIndexData;
688 /* file has grown - we need to remap to prevent us getting
689 * access violations when we try and access beyond the end
690 * of the memory mapped file */
691 if (pHeader->dwFileSize != pContainer->file_size)
693 UnmapViewOfFile( pHeader );
694 URLCacheContainer_CloseIndex(pContainer);
695 error = URLCacheContainer_OpenIndex(pContainer);
696 if (error != ERROR_SUCCESS)
698 ReleaseMutex(pContainer->hMutex);
702 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
706 ReleaseMutex(pContainer->hMutex);
707 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
710 pHeader = (URLCACHE_HEADER *)pIndexData;
713 TRACE("Signature: %s, file size: %d bytes\n", pHeader->szSignature, pHeader->dwFileSize);
715 for (index = 0; index < pHeader->DirectoryCount; index++)
717 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
723 /***********************************************************************
724 * URLCacheContainer_UnlockIndex (Internal)
727 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
730 ReleaseMutex(pContainer->hMutex);
731 return UnmapViewOfFile(pHeader);
736 #define CHAR_BIT (8 * sizeof(CHAR))
739 /***********************************************************************
740 * URLCache_Allocation_BlockIsFree (Internal)
742 * Is the specified block number free?
749 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
751 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
752 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
755 /***********************************************************************
756 * URLCache_Allocation_BlockFree (Internal)
758 * Marks the specified block as free
764 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
766 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
767 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
770 /***********************************************************************
771 * URLCache_Allocation_BlockAllocate (Internal)
773 * Marks the specified block as allocated
779 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
781 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
782 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
785 /***********************************************************************
786 * URLCache_FindFirstFreeEntry (Internal)
788 * Finds and allocates the first block of free space big enough and
789 * sets ppEntry to point to it.
792 * TRUE if it had enough space
793 * FALSE if it couldn't find enough space
796 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
798 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
801 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
803 for (dwFreeCounter = 0;
804 dwFreeCounter < dwBlocksNeeded &&
805 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
806 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
808 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
810 if (dwFreeCounter == dwBlocksNeeded)
813 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
814 for (index = 0; index < dwBlocksNeeded; index++)
815 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
816 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
817 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
821 FIXME("Grow file\n");
825 /***********************************************************************
826 * URLCache_DeleteEntry (Internal)
828 * Deletes the specified entry and frees the space allocated to it
831 * TRUE if it succeeded
835 static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, CACHEFILE_ENTRY * pEntry)
839 BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
841 /* update allocation table */
842 dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE;
843 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
844 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
846 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
850 /***********************************************************************
851 * URLCache_LocalFileNameToPathW (Internal)
853 * Copies the full path to the specified buffer given the local file
854 * name and the index of the directory it is in. Always sets value in
855 * lpBufferSize to the required buffer size (in bytes).
858 * TRUE if the buffer was big enough
859 * FALSE if the buffer was too small
862 static BOOL URLCache_LocalFileNameToPathW(
863 const URLCACHECONTAINER * pContainer,
864 LPCURLCACHE_HEADER pHeader,
865 LPCSTR szLocalFileName,
871 int path_len = strlenW(pContainer->path);
872 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
873 if (Directory >= pHeader->DirectoryCount)
879 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
880 if (nRequired < *lpBufferSize)
884 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
885 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
886 wszPath[dir_len + path_len] = '\\';
887 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
888 *lpBufferSize = nRequired;
891 *lpBufferSize = nRequired;
895 /***********************************************************************
896 * URLCache_LocalFileNameToPathA (Internal)
898 * Copies the full path to the specified buffer given the local file
899 * name and the index of the directory it is in. Always sets value in
900 * lpBufferSize to the required buffer size.
903 * TRUE if the buffer was big enough
904 * FALSE if the buffer was too small
907 static BOOL URLCache_LocalFileNameToPathA(
908 const URLCACHECONTAINER * pContainer,
909 LPCURLCACHE_HEADER pHeader,
910 LPCSTR szLocalFileName,
916 int path_len, file_name_len, dir_len;
918 if (Directory >= pHeader->DirectoryCount)
924 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL) - 1;
925 file_name_len = strlen(szLocalFileName) + 1 /* for nul-terminator */;
926 dir_len = DIR_LENGTH;
928 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(char);
929 if (nRequired < *lpBufferSize)
931 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, path_len, NULL, NULL);
932 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
933 szPath[path_len + dir_len] = '\\';
934 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
935 *lpBufferSize = nRequired;
938 *lpBufferSize = nRequired;
942 /***********************************************************************
943 * URLCache_CopyEntry (Internal)
945 * Copies an entry from the cache index file to the Win32 structure
948 * ERROR_SUCCESS if the buffer was big enough
949 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
952 static DWORD URLCache_CopyEntry(
953 URLCACHECONTAINER * pContainer,
954 LPCURLCACHE_HEADER pHeader,
955 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
956 LPDWORD lpdwBufferSize,
957 const URL_CACHEFILE_ENTRY * pUrlEntry,
961 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
963 if (*lpdwBufferSize >= dwRequiredSize)
965 lpCacheEntryInfo->lpHeaderInfo = NULL;
966 lpCacheEntryInfo->lpszFileExtension = NULL;
967 lpCacheEntryInfo->lpszLocalFileName = NULL;
968 lpCacheEntryInfo->lpszSourceUrlName = NULL;
969 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
970 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
971 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
972 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
973 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
974 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
975 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
976 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
977 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
978 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
979 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
980 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
981 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
982 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
985 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
986 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
987 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
989 lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0);
991 lenUrl = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
992 dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
994 /* FIXME: is source url optional? */
995 if (*lpdwBufferSize >= dwRequiredSize)
997 DWORD lenUrlBytes = (lenUrl+1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
999 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrlBytes;
1001 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
1003 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lenUrlBytes);
1006 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1007 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1008 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1010 if (pUrlEntry->dwOffsetLocalName)
1012 LONG nLocalFilePathSize;
1013 LPSTR lpszLocalFileName;
1014 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
1015 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
1016 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
1017 (!bUnicode && URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize)))
1019 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
1021 dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ;
1023 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1024 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1025 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1027 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
1029 if (*lpdwBufferSize >= dwRequiredSize)
1031 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
1032 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
1033 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
1035 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1036 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1037 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1039 if (pUrlEntry->dwOffsetFileExtension)
1044 lenExtension = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, NULL, 0);
1046 lenExtension = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension) + 1;
1047 dwRequiredSize += lenExtension * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
1049 if (*lpdwBufferSize >= dwRequiredSize)
1051 lpCacheEntryInfo->lpszFileExtension = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenExtension;
1053 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenExtension);
1055 memcpy(lpCacheEntryInfo->lpszFileExtension, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, lenExtension * sizeof(CHAR));
1058 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1059 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1060 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1063 if (dwRequiredSize > *lpdwBufferSize)
1065 *lpdwBufferSize = dwRequiredSize;
1066 return ERROR_INSUFFICIENT_BUFFER;
1068 *lpdwBufferSize = dwRequiredSize;
1069 return ERROR_SUCCESS;
1073 /***********************************************************************
1074 * URLCache_SetEntryInfo (Internal)
1076 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1077 * according to the flags set by dwFieldControl.
1080 * ERROR_SUCCESS if the buffer was big enough
1081 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1084 static DWORD URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1086 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1087 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1088 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1089 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1090 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1091 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1092 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1093 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1094 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1095 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1096 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1097 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1098 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1099 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1100 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1101 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1103 return ERROR_SUCCESS;
1106 /***********************************************************************
1107 * URLCache_HashKey (Internal)
1109 * Returns the hash key for a given string
1112 * hash key for the string
1115 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1117 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1118 * but the algorithm and result are not the same!
1120 static const unsigned char lookupTable[256] =
1122 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1123 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1124 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1125 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1126 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1127 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1128 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1129 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1130 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1131 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1132 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1133 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1134 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1135 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1136 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1137 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1138 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1139 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1140 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1141 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1142 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1143 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1144 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1145 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1146 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1147 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1148 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1149 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1150 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1151 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1152 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1153 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1158 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1159 key[i] = lookupTable[i];
1161 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
1163 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1164 key[i] = lookupTable[*lpszKey ^ key[i]];
1167 return *(DWORD *)key;
1170 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
1172 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
1175 static inline BOOL URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY *pHashEntry)
1177 /* check pHashEntry located within acceptable bounds in the URL cache mapping */
1178 return ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) &&
1179 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1182 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1184 /* structure of hash table:
1185 * 448 entries divided into 64 blocks
1186 * each block therefore contains a chain of 7 key/offset pairs
1187 * how position in table is calculated:
1188 * 1. the url is hashed in helper function
1189 * 2. the key % 64 * 8 is the offset
1190 * 3. the key in the hash table is the hash key aligned to 64
1193 * there can be multiple hash tables in the file and the offset to
1194 * the next one is stored in the header of the hash table
1196 DWORD key = URLCache_HashKey(lpszUrl);
1197 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1198 HASH_CACHEFILE_ENTRY * pHashEntry;
1199 DWORD dwHashTableNumber = 0;
1201 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1203 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1204 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1205 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1208 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1210 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1213 /* make sure that it is in fact a hash entry */
1214 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1216 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1220 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1222 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1223 if (key == (pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
1225 /* FIXME: we should make sure that this is the right element
1226 * before returning and claiming that it is. We can do this
1227 * by doing a simple compare between the URL we were given
1228 * and the URL stored in the entry. However, this assumes
1229 * we know the format of all the entries stored in the
1231 *ppHashEntry = pHashElement;
1239 static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1244 urlA = heap_strdupWtoA(lpszUrl);
1247 SetLastError(ERROR_OUTOFMEMORY);
1251 ret = URLCache_FindHash(pHeader, urlA, ppHashEntry);
1252 HeapFree(GetProcessHeap(), 0, urlA);
1256 /***********************************************************************
1257 * URLCache_HashEntrySetUse (Internal)
1259 * Searches all the hash tables in the index for the given URL and
1260 * sets the use count (stored or'ed with key)
1263 * TRUE if the entry was found
1264 * FALSE if the entry could not be found
1267 static BOOL URLCache_HashEntrySetUse(struct _HASH_ENTRY * pHashEntry, DWORD dwUseCount)
1269 pHashEntry->dwHashKey = dwUseCount | (pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1273 /***********************************************************************
1274 * URLCache_DeleteEntryFromHash (Internal)
1276 * Searches all the hash tables in the index for the given URL and
1277 * then if found deletes the entry.
1280 * TRUE if the entry was found
1281 * FALSE if the entry could not be found
1284 static BOOL URLCache_DeleteEntryFromHash(struct _HASH_ENTRY * pHashEntry)
1286 pHashEntry->dwHashKey = HASHTABLE_FREE;
1287 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1291 /***********************************************************************
1292 * URLCache_AddEntryToHash (Internal)
1294 * Searches all the hash tables for a free slot based on the offset
1295 * generated from the hash key. If a free slot is found, the offset and
1296 * key are entered into the hash table.
1299 * ERROR_SUCCESS if the entry was added
1300 * Any other Win32 error code if the entry could not be added
1303 static DWORD URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1305 /* see URLCache_FindEntryInHash for structure of hash tables */
1307 DWORD key = URLCache_HashKey(lpszUrl);
1308 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1309 HASH_CACHEFILE_ENTRY * pHashEntry;
1310 DWORD dwHashTableNumber = 0;
1313 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1315 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1316 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1317 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1320 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1322 ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1325 /* make sure that it is in fact a hash entry */
1326 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1328 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1332 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1334 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1335 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1337 pHashElement->dwHashKey = key;
1338 pHashElement->dwOffsetEntry = dwOffsetEntry;
1339 return ERROR_SUCCESS;
1343 error = URLCache_CreateHashTable(pHeader, pHashEntry, &pHashEntry);
1344 if (error != ERROR_SUCCESS)
1347 pHashEntry->HashTable[offset].dwHashKey = key;
1348 pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry;
1349 return ERROR_SUCCESS;
1352 /***********************************************************************
1353 * URLCache_CreateHashTable (Internal)
1355 * Creates a new hash table in free space and adds it to the chain of existing
1359 * ERROR_SUCCESS if the hash table was created
1360 * ERROR_DISK_FULL if the hash table could not be created
1363 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash)
1368 if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)ppHash))
1370 FIXME("no free space for hash table\n");
1371 return ERROR_DISK_FULL;
1374 dwOffset = (BYTE *)*ppHash - (BYTE *)pHeader;
1377 pPrevHash->dwAddressNext = dwOffset;
1379 pHeader->dwOffsetFirstHashTable = dwOffset;
1380 (*ppHash)->CacheFileEntry.dwSignature = HASH_SIGNATURE;
1381 (*ppHash)->CacheFileEntry.dwBlocksUsed = 0x20;
1382 (*ppHash)->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0;
1383 for (i = 0; i < HASHTABLE_SIZE; i++)
1385 (*ppHash)->HashTable[i].dwOffsetEntry = 0;
1386 (*ppHash)->HashTable[i].dwHashKey = HASHTABLE_FREE;
1388 return ERROR_SUCCESS;
1391 /***********************************************************************
1392 * URLCache_EnumHashTables (Internal)
1394 * Enumerates the hash tables in a container.
1397 * TRUE if an entry was found
1398 * FALSE if there are no more tables to enumerate.
1401 static BOOL URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader, DWORD *pdwHashTableNumber, HASH_CACHEFILE_ENTRY ** ppHashEntry)
1403 for (*ppHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1404 URLCache_IsHashEntryValid(pHeader, *ppHashEntry);
1405 *ppHashEntry = URLCache_HashEntryFromOffset(pHeader, (*ppHashEntry)->dwAddressNext))
1407 TRACE("looking at hash table number %d\n", (*ppHashEntry)->dwHashTableNumber);
1408 if ((*ppHashEntry)->dwHashTableNumber != *pdwHashTableNumber)
1410 /* make sure that it is in fact a hash entry */
1411 if ((*ppHashEntry)->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1413 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&(*ppHashEntry)->CacheFileEntry.dwSignature);
1414 (*pdwHashTableNumber)++;
1418 TRACE("hash table number %d found\n", *pdwHashTableNumber);
1424 /***********************************************************************
1425 * URLCache_EnumHashTableEntries (Internal)
1427 * Enumerates entries in a hash table and returns the next non-free entry.
1430 * TRUE if an entry was found
1431 * FALSE if the hash table is empty or there are no more entries to
1435 static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY * pHashEntry,
1436 DWORD * index, const struct _HASH_ENTRY ** ppHashEntry)
1438 for (; *index < HASHTABLE_SIZE ; (*index)++)
1440 if (pHashEntry->HashTable[*index].dwHashKey == HASHTABLE_FREE)
1443 *ppHashEntry = &pHashEntry->HashTable[*index];
1444 TRACE("entry found %d\n", *index);
1447 TRACE("no more entries (%d)\n", *index);
1451 /***********************************************************************
1452 * FreeUrlCacheSpaceA (WININET.@)
1455 BOOL WINAPI FreeUrlCacheSpaceA(LPCSTR lpszCachePath, DWORD dwSize, DWORD dwFilter)
1458 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1462 /***********************************************************************
1463 * FreeUrlCacheSpaceW (WININET.@)
1466 BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR lpszCachePath, DWORD dwSize, DWORD dwFilter)
1469 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1473 /***********************************************************************
1474 * GetUrlCacheEntryInfoExA (WININET.@)
1477 BOOL WINAPI GetUrlCacheEntryInfoExA(
1479 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1480 LPDWORD lpdwCacheEntryInfoBufSize,
1482 LPDWORD lpdwReserved,
1486 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1487 debugstr_a(lpszUrl),
1489 lpdwCacheEntryInfoBufSize,
1495 if ((lpszReserved != NULL) ||
1496 (lpdwReserved != NULL) ||
1497 (lpReserved != NULL))
1499 ERR("Reserved value was not 0\n");
1500 SetLastError(ERROR_INVALID_PARAMETER);
1505 FIXME("Undocumented flag(s): %x\n", dwFlags);
1506 SetLastError(ERROR_FILE_NOT_FOUND);
1509 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1512 /***********************************************************************
1513 * GetUrlCacheEntryInfoA (WININET.@)
1516 BOOL WINAPI GetUrlCacheEntryInfoA(
1517 IN LPCSTR lpszUrlName,
1518 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1519 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1522 LPURLCACHE_HEADER pHeader;
1523 struct _HASH_ENTRY * pHashEntry;
1524 const CACHEFILE_ENTRY * pEntry;
1525 const URL_CACHEFILE_ENTRY * pUrlEntry;
1526 URLCACHECONTAINER * pContainer;
1529 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1531 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1532 if (error != ERROR_SUCCESS)
1534 SetLastError(error);
1538 error = URLCacheContainer_OpenIndex(pContainer);
1539 if (error != ERROR_SUCCESS)
1541 SetLastError(error);
1545 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1548 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1550 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1551 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1552 SetLastError(ERROR_FILE_NOT_FOUND);
1556 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1557 if (pEntry->dwSignature != URL_SIGNATURE)
1559 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1560 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1561 SetLastError(ERROR_FILE_NOT_FOUND);
1565 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1566 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1567 if (pUrlEntry->dwOffsetHeaderInfo)
1568 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1570 if (lpdwCacheEntryInfoBufferSize)
1572 if (!lpCacheEntryInfo)
1573 *lpdwCacheEntryInfoBufferSize = 0;
1575 error = URLCache_CopyEntry(
1579 lpdwCacheEntryInfoBufferSize,
1582 if (error != ERROR_SUCCESS)
1584 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1585 SetLastError(error);
1588 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1591 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1596 /***********************************************************************
1597 * GetUrlCacheEntryInfoW (WININET.@)
1600 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1601 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1602 LPDWORD lpdwCacheEntryInfoBufferSize)
1604 LPURLCACHE_HEADER pHeader;
1605 struct _HASH_ENTRY * pHashEntry;
1606 const CACHEFILE_ENTRY * pEntry;
1607 const URL_CACHEFILE_ENTRY * pUrlEntry;
1608 URLCACHECONTAINER * pContainer;
1611 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1613 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1614 if (error != ERROR_SUCCESS)
1616 SetLastError(error);
1620 error = URLCacheContainer_OpenIndex(pContainer);
1621 if (error != ERROR_SUCCESS)
1623 SetLastError(error);
1627 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1630 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1632 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1633 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1634 SetLastError(ERROR_FILE_NOT_FOUND);
1638 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1639 if (pEntry->dwSignature != URL_SIGNATURE)
1641 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1642 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1643 SetLastError(ERROR_FILE_NOT_FOUND);
1647 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1648 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1649 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1651 if (lpdwCacheEntryInfoBufferSize)
1653 if (!lpCacheEntryInfo)
1654 *lpdwCacheEntryInfoBufferSize = 0;
1656 error = URLCache_CopyEntry(
1659 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1660 lpdwCacheEntryInfoBufferSize,
1662 TRUE /* UNICODE */);
1663 if (error != ERROR_SUCCESS)
1665 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1666 SetLastError(error);
1669 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1672 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1677 /***********************************************************************
1678 * GetUrlCacheEntryInfoExW (WININET.@)
1681 BOOL WINAPI GetUrlCacheEntryInfoExW(
1683 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1684 LPDWORD lpdwCacheEntryInfoBufSize,
1685 LPWSTR lpszReserved,
1686 LPDWORD lpdwReserved,
1690 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1691 debugstr_w(lpszUrl),
1693 lpdwCacheEntryInfoBufSize,
1699 if ((lpszReserved != NULL) ||
1700 (lpdwReserved != NULL) ||
1701 (lpReserved != NULL))
1703 ERR("Reserved value was not 0\n");
1704 SetLastError(ERROR_INVALID_PARAMETER);
1709 FIXME("Undocumented flag(s): %x\n", dwFlags);
1710 SetLastError(ERROR_FILE_NOT_FOUND);
1713 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1716 /***********************************************************************
1717 * SetUrlCacheEntryInfoA (WININET.@)
1719 BOOL WINAPI SetUrlCacheEntryInfoA(
1721 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1722 DWORD dwFieldControl)
1724 LPURLCACHE_HEADER pHeader;
1725 struct _HASH_ENTRY * pHashEntry;
1726 CACHEFILE_ENTRY * pEntry;
1727 URLCACHECONTAINER * pContainer;
1730 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1732 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1733 if (error != ERROR_SUCCESS)
1735 SetLastError(error);
1739 error = URLCacheContainer_OpenIndex(pContainer);
1740 if (error != ERROR_SUCCESS)
1742 SetLastError(error);
1746 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1749 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1751 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1752 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1753 SetLastError(ERROR_FILE_NOT_FOUND);
1757 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1758 if (pEntry->dwSignature != URL_SIGNATURE)
1760 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1761 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1762 SetLastError(ERROR_FILE_NOT_FOUND);
1766 URLCache_SetEntryInfo(
1767 (URL_CACHEFILE_ENTRY *)pEntry,
1768 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1771 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1776 /***********************************************************************
1777 * SetUrlCacheEntryInfoW (WININET.@)
1779 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1781 LPURLCACHE_HEADER pHeader;
1782 struct _HASH_ENTRY * pHashEntry;
1783 CACHEFILE_ENTRY * pEntry;
1784 URLCACHECONTAINER * pContainer;
1787 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1789 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1790 if (error != ERROR_SUCCESS)
1792 SetLastError(error);
1796 error = URLCacheContainer_OpenIndex(pContainer);
1797 if (error != ERROR_SUCCESS)
1799 SetLastError(error);
1803 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1806 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1808 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1809 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1810 SetLastError(ERROR_FILE_NOT_FOUND);
1814 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1815 if (pEntry->dwSignature != URL_SIGNATURE)
1817 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1818 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1819 SetLastError(ERROR_FILE_NOT_FOUND);
1823 URLCache_SetEntryInfo(
1824 (URL_CACHEFILE_ENTRY *)pEntry,
1828 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1833 /***********************************************************************
1834 * RetrieveUrlCacheEntryFileA (WININET.@)
1837 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1838 IN LPCSTR lpszUrlName,
1839 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1840 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1844 LPURLCACHE_HEADER pHeader;
1845 struct _HASH_ENTRY * pHashEntry;
1846 CACHEFILE_ENTRY * pEntry;
1847 URL_CACHEFILE_ENTRY * pUrlEntry;
1848 URLCACHECONTAINER * pContainer;
1851 TRACE("(%s, %p, %p, 0x%08x)\n",
1852 debugstr_a(lpszUrlName),
1854 lpdwCacheEntryInfoBufferSize,
1857 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1858 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1860 SetLastError(ERROR_INVALID_PARAMETER);
1864 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1865 if (error != ERROR_SUCCESS)
1867 SetLastError(error);
1871 error = URLCacheContainer_OpenIndex(pContainer);
1872 if (error != ERROR_SUCCESS)
1874 SetLastError(error);
1878 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1881 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1883 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1884 TRACE("entry %s not found!\n", lpszUrlName);
1885 SetLastError(ERROR_FILE_NOT_FOUND);
1889 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1890 if (pEntry->dwSignature != URL_SIGNATURE)
1892 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1893 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1894 SetLastError(ERROR_FILE_NOT_FOUND);
1898 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1899 if (!pUrlEntry->dwOffsetLocalName)
1901 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1902 SetLastError(ERROR_INVALID_DATA);
1906 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1907 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1909 pUrlEntry->dwHitRate++;
1910 pUrlEntry->dwUseCount++;
1911 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1913 error = URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo,
1914 lpdwCacheEntryInfoBufferSize, pUrlEntry,
1916 if (error != ERROR_SUCCESS)
1918 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1919 SetLastError(error);
1922 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1924 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1929 /***********************************************************************
1930 * RetrieveUrlCacheEntryFileW (WININET.@)
1933 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1934 IN LPCWSTR lpszUrlName,
1935 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1936 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1940 LPURLCACHE_HEADER pHeader;
1941 struct _HASH_ENTRY * pHashEntry;
1942 CACHEFILE_ENTRY * pEntry;
1943 URL_CACHEFILE_ENTRY * pUrlEntry;
1944 URLCACHECONTAINER * pContainer;
1947 TRACE("(%s, %p, %p, 0x%08x)\n",
1948 debugstr_w(lpszUrlName),
1950 lpdwCacheEntryInfoBufferSize,
1953 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1954 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1956 SetLastError(ERROR_INVALID_PARAMETER);
1960 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
1961 if (error != ERROR_SUCCESS)
1963 SetLastError(error);
1967 error = URLCacheContainer_OpenIndex(pContainer);
1968 if (error != ERROR_SUCCESS)
1970 SetLastError(error);
1974 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1977 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1979 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1980 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1981 SetLastError(ERROR_FILE_NOT_FOUND);
1985 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1986 if (pEntry->dwSignature != URL_SIGNATURE)
1988 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1989 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1990 SetLastError(ERROR_FILE_NOT_FOUND);
1994 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1995 if (!pUrlEntry->dwOffsetLocalName)
1997 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1998 SetLastError(ERROR_INVALID_DATA);
2002 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
2003 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
2005 pUrlEntry->dwHitRate++;
2006 pUrlEntry->dwUseCount++;
2007 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2009 error = URLCache_CopyEntry(
2012 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
2013 lpdwCacheEntryInfoBufferSize,
2015 TRUE /* UNICODE */);
2016 if (error != ERROR_SUCCESS)
2018 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2019 SetLastError(error);
2022 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
2024 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2029 /***********************************************************************
2030 * UnlockUrlCacheEntryFileA (WININET.@)
2033 BOOL WINAPI UnlockUrlCacheEntryFileA(
2034 IN LPCSTR lpszUrlName,
2038 LPURLCACHE_HEADER pHeader;
2039 struct _HASH_ENTRY * pHashEntry;
2040 CACHEFILE_ENTRY * pEntry;
2041 URL_CACHEFILE_ENTRY * pUrlEntry;
2042 URLCACHECONTAINER * pContainer;
2045 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
2049 ERR("dwReserved != 0\n");
2050 SetLastError(ERROR_INVALID_PARAMETER);
2054 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2055 if (error != ERROR_SUCCESS)
2057 SetLastError(error);
2061 error = URLCacheContainer_OpenIndex(pContainer);
2062 if (error != ERROR_SUCCESS)
2064 SetLastError(error);
2068 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2071 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2073 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2074 TRACE("entry %s not found!\n", lpszUrlName);
2075 SetLastError(ERROR_FILE_NOT_FOUND);
2079 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2080 if (pEntry->dwSignature != URL_SIGNATURE)
2082 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2083 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2084 SetLastError(ERROR_FILE_NOT_FOUND);
2088 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2090 if (pUrlEntry->dwUseCount == 0)
2092 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2095 pUrlEntry->dwUseCount--;
2096 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2098 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2103 /***********************************************************************
2104 * UnlockUrlCacheEntryFileW (WININET.@)
2107 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
2109 LPURLCACHE_HEADER pHeader;
2110 struct _HASH_ENTRY * pHashEntry;
2111 CACHEFILE_ENTRY * pEntry;
2112 URL_CACHEFILE_ENTRY * pUrlEntry;
2113 URLCACHECONTAINER * pContainer;
2116 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
2120 ERR("dwReserved != 0\n");
2121 SetLastError(ERROR_INVALID_PARAMETER);
2125 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2126 if (error != ERROR_SUCCESS)
2128 SetLastError(error);
2132 error = URLCacheContainer_OpenIndex(pContainer);
2133 if (error != ERROR_SUCCESS)
2135 SetLastError(error);
2139 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2142 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
2144 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2145 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
2146 SetLastError(ERROR_FILE_NOT_FOUND);
2150 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2151 if (pEntry->dwSignature != URL_SIGNATURE)
2153 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2154 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2155 SetLastError(ERROR_FILE_NOT_FOUND);
2159 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2161 if (pUrlEntry->dwUseCount == 0)
2163 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2166 pUrlEntry->dwUseCount--;
2167 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2169 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2174 /***********************************************************************
2175 * CreateUrlCacheEntryA (WININET.@)
2178 BOOL WINAPI CreateUrlCacheEntryA(
2179 IN LPCSTR lpszUrlName,
2180 IN DWORD dwExpectedFileSize,
2181 IN LPCSTR lpszFileExtension,
2182 OUT LPSTR lpszFileName,
2187 WCHAR *file_extension;
2188 WCHAR file_name[MAX_PATH];
2189 BOOL bSuccess = FALSE;
2192 if (lpszUrlName && (url_name = heap_strdupAtoW(lpszUrlName)))
2194 if (lpszFileExtension && (file_extension = heap_strdupAtoW(lpszFileExtension)))
2196 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
2198 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
2204 dwError = GetLastError();
2209 dwError = GetLastError();
2211 HeapFree(GetProcessHeap(), 0, file_extension);
2215 dwError = GetLastError();
2217 HeapFree(GetProcessHeap(), 0, url_name);
2219 SetLastError(dwError);
2223 /***********************************************************************
2224 * CreateUrlCacheEntryW (WININET.@)
2227 BOOL WINAPI CreateUrlCacheEntryW(
2228 IN LPCWSTR lpszUrlName,
2229 IN DWORD dwExpectedFileSize,
2230 IN LPCWSTR lpszFileExtension,
2231 OUT LPWSTR lpszFileName,
2235 URLCACHECONTAINER * pContainer;
2236 LPURLCACHE_HEADER pHeader;
2237 CHAR szFile[MAX_PATH];
2238 WCHAR szExtension[MAX_PATH];
2239 LPCWSTR lpszUrlPart;
2241 LPCWSTR lpszFileNameExtension;
2242 LPWSTR lpszFileNameNoPath;
2244 int countnoextension;
2247 BOOL bFound = FALSE;
2253 static const WCHAR szWWW[] = {'w','w','w',0};
2254 static const WCHAR fmt[] = {'%','0','8','X','%','s',0};
2256 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2257 debugstr_w(lpszUrlName),
2259 debugstr_w(lpszFileExtension),
2264 FIXME("dwReserved 0x%08x\n", dwReserved);
2266 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2268 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2271 for (lpszUrlPart = lpszUrlEnd;
2272 (lpszUrlPart >= lpszUrlName);
2275 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2281 else if(*lpszUrlPart == '?' || *lpszUrlPart == '#')
2283 lpszUrlEnd = lpszUrlPart;
2286 if (!lstrcmpW(lpszUrlPart, szWWW))
2288 lpszUrlPart += lstrlenW(szWWW);
2291 count = lpszUrlEnd - lpszUrlPart;
2293 if (bFound && (count < MAX_PATH))
2295 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2299 while(len && szFile[--len] == '/') szFile[len] = '\0';
2301 /* FIXME: get rid of illegal characters like \, / and : */
2305 FIXME("need to generate a random filename\n");
2308 TRACE("File name: %s\n", debugstr_a(szFile));
2310 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2311 if (error != ERROR_SUCCESS)
2313 SetLastError(error);
2317 error = URLCacheContainer_OpenIndex(pContainer);
2318 if (error != ERROR_SUCCESS)
2320 SetLastError(error);
2324 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2327 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2329 lBufferSize = MAX_PATH * sizeof(WCHAR);
2330 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
2332 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2334 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2335 lpszFileNameNoPath >= lpszFileName;
2336 --lpszFileNameNoPath)
2338 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2342 countnoextension = lstrlenW(lpszFileNameNoPath);
2343 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2344 if (lpszFileNameExtension)
2345 countnoextension -= lstrlenW(lpszFileNameExtension);
2346 *szExtension = '\0';
2348 if (lpszFileExtension)
2350 szExtension[0] = '.';
2351 lstrcpyW(szExtension+1, lpszFileExtension);
2354 for (i = 0; i < 255; i++)
2356 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2359 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2360 for (p = lpszFileNameNoPath + 1; *p; p++)
2366 case '/': case '\\':
2373 if (p[-1] == ' ' || p[-1] == '.') p[-1] = '_';
2375 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2376 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2377 if (hFile != INVALID_HANDLE_VALUE)
2384 GetSystemTimeAsFileTime(&ft);
2385 wsprintfW(lpszFileNameNoPath + countnoextension, fmt, ft.dwLowDateTime, szExtension);
2387 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2388 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2389 if (hFile != INVALID_HANDLE_VALUE)
2395 WARN("Could not find a unique filename\n");
2400 /***********************************************************************
2401 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2403 * The bug we are compensating for is that some drongo at Microsoft
2404 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2405 * As a consequence, CommitUrlCacheEntryA has been effectively
2406 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2407 * is still defined as LPCWSTR. The result (other than madness) is
2408 * that we always need to store lpHeaderInfo in CP_ACP rather than
2409 * in UTF16, and we need to avoid converting lpHeaderInfo in
2410 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2411 * result will lose data for arbitrary binary data.
2414 static BOOL CommitUrlCacheEntryInternal(
2415 IN LPCWSTR lpszUrlName,
2416 IN LPCWSTR lpszLocalFileName,
2417 IN FILETIME ExpireTime,
2418 IN FILETIME LastModifiedTime,
2419 IN DWORD CacheEntryType,
2420 IN LPBYTE lpHeaderInfo,
2421 IN DWORD dwHeaderSize,
2422 IN LPCWSTR lpszFileExtension,
2423 IN LPCWSTR lpszOriginalUrl
2426 URLCACHECONTAINER * pContainer;
2427 LPURLCACHE_HEADER pHeader;
2428 struct _HASH_ENTRY * pHashEntry;
2429 CACHEFILE_ENTRY * pEntry;
2430 URL_CACHEFILE_ENTRY * pUrlEntry;
2431 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2432 DWORD dwOffsetLocalFileName = 0;
2433 DWORD dwOffsetHeader = 0;
2434 DWORD dwOffsetFileExtension = 0;
2435 DWORD dwFileSizeLow = 0;
2436 DWORD dwFileSizeHigh = 0;
2437 BYTE cDirectory = 0;
2439 char achFile[MAX_PATH];
2440 LPSTR lpszUrlNameA = NULL;
2441 LPSTR lpszFileExtensionA = NULL;
2442 char *pchLocalFileName = 0;
2445 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2446 debugstr_w(lpszUrlName),
2447 debugstr_w(lpszLocalFileName),
2451 debugstr_w(lpszFileExtension),
2452 debugstr_w(lpszOriginalUrl));
2454 if (lpszOriginalUrl)
2455 WARN(": lpszOriginalUrl ignored\n");
2457 if (lpszLocalFileName)
2461 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2462 if (hFile == INVALID_HANDLE_VALUE)
2464 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2469 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2470 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2472 ERR("couldn't get file size (error is %d)\n", GetLastError());
2480 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2481 if (error != ERROR_SUCCESS)
2483 SetLastError(error);
2487 error = URLCacheContainer_OpenIndex(pContainer);
2488 if (error != ERROR_SUCCESS)
2490 SetLastError(error);
2494 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2497 lpszUrlNameA = heap_strdupWtoA(lpszUrlName);
2500 error = GetLastError();
2504 if (lpszFileExtension && !(lpszFileExtensionA = heap_strdupWtoA(lpszFileExtension)))
2506 error = GetLastError();
2510 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2512 FIXME("entry already in cache - don't know what to do!\n");
2514 * SetLastError(ERROR_FILE_NOT_FOUND);
2520 if (lpszLocalFileName)
2522 BOOL bFound = FALSE;
2524 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2526 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2527 error = ERROR_INVALID_PARAMETER;
2531 /* skip container path prefix */
2532 lpszLocalFileName += lstrlenW(pContainer->path);
2534 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL);
2535 pchLocalFileName = achFile;
2537 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2539 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2548 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2549 error = ERROR_INVALID_PARAMETER;
2553 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2556 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2557 if (lpszLocalFileName)
2559 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2560 dwOffsetLocalFileName = dwBytesNeeded;
2561 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2565 dwOffsetHeader = dwBytesNeeded;
2566 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2568 if (lpszFileExtensionA)
2570 dwOffsetFileExtension = dwBytesNeeded;
2571 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2574 /* round up to next block */
2575 if (dwBytesNeeded % BLOCKSIZE)
2577 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2578 dwBytesNeeded += BLOCKSIZE;
2581 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2583 ERR("no free entries\n");
2584 error = ERROR_DISK_FULL;
2588 /* FindFirstFreeEntry fills in blocks used */
2589 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2590 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2591 pUrlEntry->CacheDir = cDirectory;
2592 pUrlEntry->CacheEntryType = CacheEntryType;
2593 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2594 pUrlEntry->dwExemptDelta = 0;
2595 pUrlEntry->dwHitRate = 0;
2596 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2597 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2598 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2599 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2600 pUrlEntry->dwSizeHigh = 0;
2601 pUrlEntry->dwSizeLow = dwFileSizeLow;
2602 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2603 pUrlEntry->dwUseCount = 0;
2604 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2605 pUrlEntry->LastModifiedTime = LastModifiedTime;
2606 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2607 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2608 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2609 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2612 pUrlEntry->dwUnknown1 = 0;
2613 pUrlEntry->dwUnknown2 = 0;
2614 pUrlEntry->dwUnknown3 = 0x60;
2615 pUrlEntry->Unknown4 = 0;
2616 pUrlEntry->wUnknown5 = 0x1010;
2617 pUrlEntry->dwUnknown7 = 0;
2618 pUrlEntry->dwUnknown8 = 0;
2621 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2622 if (dwOffsetLocalFileName)
2623 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2625 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2626 if (dwOffsetFileExtension)
2627 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2629 error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA,
2630 (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader));
2631 if (error != ERROR_SUCCESS)
2632 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2635 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2636 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2637 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2639 if (error == ERROR_SUCCESS)
2643 SetLastError(error);
2648 /***********************************************************************
2649 * CommitUrlCacheEntryA (WININET.@)
2652 BOOL WINAPI CommitUrlCacheEntryA(
2653 IN LPCSTR lpszUrlName,
2654 IN LPCSTR lpszLocalFileName,
2655 IN FILETIME ExpireTime,
2656 IN FILETIME LastModifiedTime,
2657 IN DWORD CacheEntryType,
2658 IN LPBYTE lpHeaderInfo,
2659 IN DWORD dwHeaderSize,
2660 IN LPCSTR lpszFileExtension,
2661 IN LPCSTR lpszOriginalUrl
2664 WCHAR *url_name = NULL;
2665 WCHAR *local_file_name = NULL;
2666 WCHAR *original_url = NULL;
2667 WCHAR *file_extension = NULL;
2668 BOOL bSuccess = FALSE;
2670 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2671 debugstr_a(lpszUrlName),
2672 debugstr_a(lpszLocalFileName),
2676 debugstr_a(lpszFileExtension),
2677 debugstr_a(lpszOriginalUrl));
2679 url_name = heap_strdupAtoW(lpszUrlName);
2683 if (lpszLocalFileName)
2685 local_file_name = heap_strdupAtoW(lpszLocalFileName);
2686 if (!local_file_name)
2689 if (lpszFileExtension)
2691 file_extension = heap_strdupAtoW(lpszFileExtension);
2692 if (!file_extension)
2695 if (lpszOriginalUrl)
2697 original_url = heap_strdupAtoW(lpszOriginalUrl);
2702 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2703 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2704 file_extension, original_url);
2707 HeapFree(GetProcessHeap(), 0, original_url);
2708 HeapFree(GetProcessHeap(), 0, file_extension);
2709 HeapFree(GetProcessHeap(), 0, local_file_name);
2710 HeapFree(GetProcessHeap(), 0, url_name);
2715 /***********************************************************************
2716 * CommitUrlCacheEntryW (WININET.@)
2719 BOOL WINAPI CommitUrlCacheEntryW(
2720 IN LPCWSTR lpszUrlName,
2721 IN LPCWSTR lpszLocalFileName,
2722 IN FILETIME ExpireTime,
2723 IN FILETIME LastModifiedTime,
2724 IN DWORD CacheEntryType,
2725 IN LPWSTR lpHeaderInfo,
2726 IN DWORD dwHeaderSize,
2727 IN LPCWSTR lpszFileExtension,
2728 IN LPCWSTR lpszOriginalUrl
2732 BOOL bSuccess = FALSE;
2734 CHAR *header_info = NULL;
2736 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2737 debugstr_w(lpszUrlName),
2738 debugstr_w(lpszLocalFileName),
2742 debugstr_w(lpszFileExtension),
2743 debugstr_w(lpszOriginalUrl));
2745 if (!lpHeaderInfo || (header_info = heap_strdupWtoA(lpHeaderInfo)))
2747 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2748 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2754 dwError = GetLastError();
2758 HeapFree(GetProcessHeap(), 0, header_info);
2760 SetLastError(dwError);
2766 /***********************************************************************
2767 * ReadUrlCacheEntryStream (WININET.@)
2770 BOOL WINAPI ReadUrlCacheEntryStream(
2771 IN HANDLE hUrlCacheStream,
2772 IN DWORD dwLocation,
2773 IN OUT LPVOID lpBuffer,
2774 IN OUT LPDWORD lpdwLen,
2778 /* Get handle to file from 'stream' */
2779 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2781 if (dwReserved != 0)
2783 ERR("dwReserved != 0\n");
2784 SetLastError(ERROR_INVALID_PARAMETER);
2788 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2790 SetLastError(ERROR_INVALID_HANDLE);
2794 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2796 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2799 /***********************************************************************
2800 * RetrieveUrlCacheEntryStreamA (WININET.@)
2803 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2804 IN LPCSTR lpszUrlName,
2805 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2806 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2807 IN BOOL fRandomRead,
2811 /* NOTE: this is not the same as the way that the native
2812 * version allocates 'stream' handles. I did it this way
2813 * as it is much easier and no applications should depend
2814 * on this behaviour. (Native version appears to allocate
2815 * indices into a table)
2817 STREAM_HANDLE * pStream;
2820 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2821 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2823 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2825 lpdwCacheEntryInfoBufferSize,
2831 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2836 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2838 if (hFile == INVALID_HANDLE_VALUE)
2841 /* allocate handle storage space */
2842 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2846 SetLastError(ERROR_OUTOFMEMORY);
2850 pStream->hFile = hFile;
2851 strcpy(pStream->lpszUrl, lpszUrlName);
2855 /***********************************************************************
2856 * RetrieveUrlCacheEntryStreamW (WININET.@)
2859 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2860 IN LPCWSTR lpszUrlName,
2861 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2862 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2863 IN BOOL fRandomRead,
2867 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2868 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2872 /***********************************************************************
2873 * UnlockUrlCacheEntryStream (WININET.@)
2876 BOOL WINAPI UnlockUrlCacheEntryStream(
2877 IN HANDLE hUrlCacheStream,
2881 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2883 if (dwReserved != 0)
2885 ERR("dwReserved != 0\n");
2886 SetLastError(ERROR_INVALID_PARAMETER);
2890 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2892 SetLastError(ERROR_INVALID_HANDLE);
2896 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2899 /* close file handle */
2900 CloseHandle(pStream->hFile);
2902 /* free allocated space */
2903 HeapFree(GetProcessHeap(), 0, pStream);
2909 /***********************************************************************
2910 * DeleteUrlCacheEntryA (WININET.@)
2913 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2915 URLCACHECONTAINER * pContainer;
2916 LPURLCACHE_HEADER pHeader;
2917 struct _HASH_ENTRY * pHashEntry;
2918 CACHEFILE_ENTRY * pEntry;
2921 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2923 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2924 if (error != ERROR_SUCCESS)
2926 SetLastError(error);
2930 error = URLCacheContainer_OpenIndex(pContainer);
2931 if (error != ERROR_SUCCESS)
2933 SetLastError(error);
2937 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2940 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2942 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2943 TRACE("entry %s not found!\n", lpszUrlName);
2944 SetLastError(ERROR_FILE_NOT_FOUND);
2948 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2949 URLCache_DeleteEntry(pHeader, pEntry);
2951 URLCache_DeleteEntryFromHash(pHashEntry);
2953 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2958 /***********************************************************************
2959 * DeleteUrlCacheEntryW (WININET.@)
2962 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2964 URLCACHECONTAINER * pContainer;
2965 LPURLCACHE_HEADER pHeader;
2966 struct _HASH_ENTRY * pHashEntry;
2967 CACHEFILE_ENTRY * pEntry;
2971 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2973 urlA = heap_strdupWtoA(lpszUrlName);
2976 SetLastError(ERROR_OUTOFMEMORY);
2980 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2981 if (error != ERROR_SUCCESS)
2983 HeapFree(GetProcessHeap(), 0, urlA);
2984 SetLastError(error);
2988 error = URLCacheContainer_OpenIndex(pContainer);
2989 if (error != ERROR_SUCCESS)
2991 HeapFree(GetProcessHeap(), 0, urlA);
2992 SetLastError(error);
2996 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2998 HeapFree(GetProcessHeap(), 0, urlA);
3002 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
3004 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3005 TRACE("entry %s not found!\n", debugstr_a(urlA));
3006 HeapFree(GetProcessHeap(), 0, urlA);
3007 SetLastError(ERROR_FILE_NOT_FOUND);
3011 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3012 URLCache_DeleteEntry(pHeader, pEntry);
3014 URLCache_DeleteEntryFromHash(pHashEntry);
3016 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3018 HeapFree(GetProcessHeap(), 0, urlA);
3022 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
3024 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3028 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
3030 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3034 /***********************************************************************
3035 * CreateCacheContainerA (WININET.@)
3037 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3038 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3040 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3041 d1, d2, d3, d4, d5, d6, d7, d8);
3045 /***********************************************************************
3046 * CreateCacheContainerW (WININET.@)
3048 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3049 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3051 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3052 d1, d2, d3, d4, d5, d6, d7, d8);
3056 /***********************************************************************
3057 * FindFirstUrlCacheContainerA (WININET.@)
3059 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3061 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3065 /***********************************************************************
3066 * FindFirstUrlCacheContainerW (WININET.@)
3068 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3070 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3074 /***********************************************************************
3075 * FindNextUrlCacheContainerA (WININET.@)
3077 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
3079 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3083 /***********************************************************************
3084 * FindNextUrlCacheContainerW (WININET.@)
3086 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
3088 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3092 HANDLE WINAPI FindFirstUrlCacheEntryExA(
3093 LPCSTR lpszUrlSearchPattern,
3097 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3098 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3100 LPDWORD pcbReserved2,
3104 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
3105 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3106 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3107 SetLastError(ERROR_FILE_NOT_FOUND);
3111 HANDLE WINAPI FindFirstUrlCacheEntryExW(
3112 LPCWSTR lpszUrlSearchPattern,
3116 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3117 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3119 LPDWORD pcbReserved2,
3123 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
3124 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3125 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3126 SetLastError(ERROR_FILE_NOT_FOUND);
3130 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3132 typedef struct URLCacheFindEntryHandle
3135 LPWSTR lpszUrlSearchPattern;
3136 DWORD dwContainerIndex;
3137 DWORD dwHashTableIndex;
3138 DWORD dwHashEntryIndex;
3139 } URLCacheFindEntryHandle;
3141 /***********************************************************************
3142 * FindFirstUrlCacheEntryA (WININET.@)
3145 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
3146 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3148 URLCacheFindEntryHandle *pEntryHandle;
3150 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3152 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3156 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3157 if (lpszUrlSearchPattern)
3159 pEntryHandle->lpszUrlSearchPattern = heap_strdupAtoW(lpszUrlSearchPattern);
3160 if (!pEntryHandle->lpszUrlSearchPattern)
3162 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3167 pEntryHandle->lpszUrlSearchPattern = NULL;
3168 pEntryHandle->dwContainerIndex = 0;
3169 pEntryHandle->dwHashTableIndex = 0;
3170 pEntryHandle->dwHashEntryIndex = 0;
3172 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3174 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3177 return pEntryHandle;
3180 /***********************************************************************
3181 * FindFirstUrlCacheEntryW (WININET.@)
3184 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3185 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3187 URLCacheFindEntryHandle *pEntryHandle;
3189 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3191 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3195 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3196 if (lpszUrlSearchPattern)
3198 pEntryHandle->lpszUrlSearchPattern = heap_strdupW(lpszUrlSearchPattern);
3199 if (!pEntryHandle->lpszUrlSearchPattern)
3201 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3206 pEntryHandle->lpszUrlSearchPattern = NULL;
3207 pEntryHandle->dwContainerIndex = 0;
3208 pEntryHandle->dwHashTableIndex = 0;
3209 pEntryHandle->dwHashEntryIndex = 0;
3211 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3213 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3216 return pEntryHandle;
3219 /***********************************************************************
3220 * FindNextUrlCacheEntryA (WININET.@)
3222 BOOL WINAPI FindNextUrlCacheEntryA(
3224 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3225 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3227 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3228 URLCACHECONTAINER * pContainer;
3230 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3232 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3234 SetLastError(ERROR_INVALID_HANDLE);
3238 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3239 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3241 LPURLCACHE_HEADER pHeader;
3242 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3245 error = URLCacheContainer_OpenIndex(pContainer);
3246 if (error != ERROR_SUCCESS)
3248 SetLastError(error);
3252 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3255 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3256 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3258 const struct _HASH_ENTRY *pHashEntry = NULL;
3259 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3260 pEntryHandle->dwHashEntryIndex++)
3262 const URL_CACHEFILE_ENTRY *pUrlEntry;
3263 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3265 if (pEntry->dwSignature != URL_SIGNATURE)
3268 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3269 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3270 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3272 error = URLCache_CopyEntry(
3275 lpNextCacheEntryInfo,
3276 lpdwNextCacheEntryInfoBufferSize,
3278 FALSE /* not UNICODE */);
3279 if (error != ERROR_SUCCESS)
3281 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3282 SetLastError(error);
3285 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
3287 /* increment the current index so that next time the function
3288 * is called the next entry is returned */
3289 pEntryHandle->dwHashEntryIndex++;
3290 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3295 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3298 SetLastError(ERROR_NO_MORE_ITEMS);
3302 /***********************************************************************
3303 * FindNextUrlCacheEntryW (WININET.@)
3305 BOOL WINAPI FindNextUrlCacheEntryW(
3307 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3308 LPDWORD lpdwNextCacheEntryInfoBufferSize
3311 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3312 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3316 /***********************************************************************
3317 * FindCloseUrlCache (WININET.@)
3319 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3321 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3323 TRACE("(%p)\n", hEnumHandle);
3325 if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3327 SetLastError(ERROR_INVALID_HANDLE);
3331 pEntryHandle->dwMagic = 0;
3332 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3333 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3338 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3339 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3341 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3342 dwSearchCondition, lpGroupId, lpReserved);
3346 BOOL WINAPI FindNextUrlCacheEntryExA(
3348 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3349 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3351 LPDWORD pcbReserved2,
3355 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3356 lpReserved, pcbReserved2, lpReserved3);
3360 BOOL WINAPI FindNextUrlCacheEntryExW(
3362 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3363 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3365 LPDWORD pcbReserved2,
3369 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3370 lpReserved, pcbReserved2, lpReserved3);
3374 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3376 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3380 /***********************************************************************
3381 * CreateUrlCacheGroup (WININET.@)
3384 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3386 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3390 /***********************************************************************
3391 * DeleteUrlCacheGroup (WININET.@)
3394 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3396 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3397 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3401 /***********************************************************************
3402 * SetUrlCacheEntryGroupA (WININET.@)
3405 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3406 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3409 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3410 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3411 pbGroupAttributes, cbGroupAttributes, lpReserved);
3412 SetLastError(ERROR_FILE_NOT_FOUND);
3416 /***********************************************************************
3417 * SetUrlCacheEntryGroupW (WININET.@)
3420 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3421 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3424 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3425 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3426 pbGroupAttributes, cbGroupAttributes, lpReserved);
3427 SetLastError(ERROR_FILE_NOT_FOUND);
3431 /***********************************************************************
3432 * GetUrlCacheConfigInfoW (WININET.@)
3434 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3436 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3437 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3441 /***********************************************************************
3442 * GetUrlCacheConfigInfoA (WININET.@)
3444 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3446 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3448 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3449 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3453 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3454 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3455 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3457 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3458 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3459 lpdwGroupInfo, lpReserved);
3463 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3464 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3465 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3467 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3468 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3469 lpdwGroupInfo, lpReserved);
3473 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3474 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3476 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3477 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3481 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3482 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3484 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3485 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3489 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3491 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3495 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3497 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3501 /***********************************************************************
3502 * DeleteIE3Cache (WININET.@)
3504 * Deletes the files used by the IE3 URL caching system.
3507 * hWnd [I] A dummy window.
3508 * hInst [I] Instance of process calling the function.
3509 * lpszCmdLine [I] Options used by function.
3510 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3512 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3514 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3518 /***********************************************************************
3519 * IsUrlCacheEntryExpiredA (WININET.@)
3523 * dwFlags [I] Unknown
3524 * pftLastModified [O] Last modified time
3526 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3528 LPURLCACHE_HEADER pHeader;
3529 struct _HASH_ENTRY * pHashEntry;
3530 const CACHEFILE_ENTRY * pEntry;
3531 const URL_CACHEFILE_ENTRY * pUrlEntry;
3532 URLCACHECONTAINER * pContainer;
3535 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3537 error = URLCacheContainers_FindContainerA(url, &pContainer);
3538 if (error != ERROR_SUCCESS)
3540 SetLastError(error);
3544 error = URLCacheContainer_OpenIndex(pContainer);
3545 if (error != ERROR_SUCCESS)
3547 SetLastError(error);
3551 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3554 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3556 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3557 TRACE("entry %s not found!\n", url);
3558 SetLastError(ERROR_FILE_NOT_FOUND);
3562 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3563 if (pEntry->dwSignature != URL_SIGNATURE)
3565 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3566 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3567 SetLastError(ERROR_FILE_NOT_FOUND);
3571 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3573 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3575 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3580 /***********************************************************************
3581 * IsUrlCacheEntryExpiredW (WININET.@)
3585 * dwFlags [I] Unknown
3586 * pftLastModified [O] Last modified time
3588 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3590 LPURLCACHE_HEADER pHeader;
3591 struct _HASH_ENTRY * pHashEntry;
3592 const CACHEFILE_ENTRY * pEntry;
3593 const URL_CACHEFILE_ENTRY * pUrlEntry;
3594 URLCACHECONTAINER * pContainer;
3597 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3599 error = URLCacheContainers_FindContainerW(url, &pContainer);
3600 if (error != ERROR_SUCCESS)
3602 SetLastError(error);
3606 error = URLCacheContainer_OpenIndex(pContainer);
3607 if (error != ERROR_SUCCESS)
3609 SetLastError(error);
3613 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3616 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3618 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3619 TRACE("entry %s not found!\n", debugstr_w(url));
3620 SetLastError(ERROR_FILE_NOT_FOUND);
3624 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3625 if (pEntry->dwSignature != URL_SIGNATURE)
3627 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3628 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3629 SetLastError(ERROR_FILE_NOT_FOUND);
3633 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3635 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3637 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3642 /***********************************************************************
3643 * GetDiskInfoA (WININET.@)
3645 BOOL WINAPI GetDiskInfoA(PCSTR path, PDWORD cluster_size, PDWORDLONG free, PDWORDLONG total)
3648 ULARGE_INTEGER bytes_free, bytes_total;
3650 TRACE("(%s, %p, %p, %p)\n", debugstr_a(path), cluster_size, free, total);
3654 SetLastError(ERROR_INVALID_PARAMETER);
3658 if ((ret = GetDiskFreeSpaceExA(path, NULL, &bytes_total, &bytes_free)))
3660 if (cluster_size) *cluster_size = 1;
3661 if (free) *free = bytes_free.QuadPart;
3662 if (total) *total = bytes_total.QuadPart;
3667 /***********************************************************************
3668 * RegisterUrlCacheNotification (WININET.@)
3670 DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
3672 FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f);
3676 /***********************************************************************
3677 * IncrementUrlCacheHeaderData (WININET.@)
3679 BOOL WINAPI IncrementUrlCacheHeaderData(DWORD index, LPDWORD data)
3681 FIXME("(%u, %p)\n", index, data);