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 * GetUrlCacheEntryInfoExA (WININET.@)
1455 BOOL WINAPI GetUrlCacheEntryInfoExA(
1457 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1458 LPDWORD lpdwCacheEntryInfoBufSize,
1460 LPDWORD lpdwReserved,
1464 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1465 debugstr_a(lpszUrl),
1467 lpdwCacheEntryInfoBufSize,
1473 if ((lpszReserved != NULL) ||
1474 (lpdwReserved != NULL) ||
1475 (lpReserved != NULL))
1477 ERR("Reserved value was not 0\n");
1478 SetLastError(ERROR_INVALID_PARAMETER);
1482 FIXME("Undocumented flag(s): %x\n", dwFlags);
1483 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1486 /***********************************************************************
1487 * GetUrlCacheEntryInfoA (WININET.@)
1490 BOOL WINAPI GetUrlCacheEntryInfoA(
1491 IN LPCSTR lpszUrlName,
1492 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1493 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1496 LPURLCACHE_HEADER pHeader;
1497 struct _HASH_ENTRY * pHashEntry;
1498 const CACHEFILE_ENTRY * pEntry;
1499 const URL_CACHEFILE_ENTRY * pUrlEntry;
1500 URLCACHECONTAINER * pContainer;
1503 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1505 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1506 if (error != ERROR_SUCCESS)
1508 SetLastError(error);
1512 error = URLCacheContainer_OpenIndex(pContainer);
1513 if (error != ERROR_SUCCESS)
1515 SetLastError(error);
1519 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1522 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1524 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1525 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1526 SetLastError(ERROR_FILE_NOT_FOUND);
1530 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1531 if (pEntry->dwSignature != URL_SIGNATURE)
1533 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1534 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1535 SetLastError(ERROR_FILE_NOT_FOUND);
1539 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1540 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1541 if (pUrlEntry->dwOffsetHeaderInfo)
1542 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1544 if (lpdwCacheEntryInfoBufferSize)
1546 if (!lpCacheEntryInfo)
1547 *lpdwCacheEntryInfoBufferSize = 0;
1549 error = URLCache_CopyEntry(
1553 lpdwCacheEntryInfoBufferSize,
1556 if (error != ERROR_SUCCESS)
1558 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1559 SetLastError(error);
1562 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1565 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1570 /***********************************************************************
1571 * GetUrlCacheEntryInfoW (WININET.@)
1574 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1575 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1576 LPDWORD lpdwCacheEntryInfoBufferSize)
1578 LPURLCACHE_HEADER pHeader;
1579 struct _HASH_ENTRY * pHashEntry;
1580 const CACHEFILE_ENTRY * pEntry;
1581 const URL_CACHEFILE_ENTRY * pUrlEntry;
1582 URLCACHECONTAINER * pContainer;
1585 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1587 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1588 if (error != ERROR_SUCCESS)
1590 SetLastError(error);
1594 error = URLCacheContainer_OpenIndex(pContainer);
1595 if (error != ERROR_SUCCESS)
1597 SetLastError(error);
1601 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1604 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1606 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1607 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1608 SetLastError(ERROR_FILE_NOT_FOUND);
1612 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1613 if (pEntry->dwSignature != URL_SIGNATURE)
1615 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1616 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1617 SetLastError(ERROR_FILE_NOT_FOUND);
1621 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1622 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1623 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1625 if (lpdwCacheEntryInfoBufferSize)
1627 if (!lpCacheEntryInfo)
1628 *lpdwCacheEntryInfoBufferSize = 0;
1630 error = URLCache_CopyEntry(
1633 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1634 lpdwCacheEntryInfoBufferSize,
1636 TRUE /* UNICODE */);
1637 if (error != ERROR_SUCCESS)
1639 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1640 SetLastError(error);
1643 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1646 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1651 /***********************************************************************
1652 * GetUrlCacheEntryInfoExW (WININET.@)
1655 BOOL WINAPI GetUrlCacheEntryInfoExW(
1657 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1658 LPDWORD lpdwCacheEntryInfoBufSize,
1659 LPWSTR lpszReserved,
1660 LPDWORD lpdwReserved,
1664 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1665 debugstr_w(lpszUrl),
1667 lpdwCacheEntryInfoBufSize,
1673 if ((lpszReserved != NULL) ||
1674 (lpdwReserved != NULL) ||
1675 (lpReserved != NULL))
1677 ERR("Reserved value was not 0\n");
1678 SetLastError(ERROR_INVALID_PARAMETER);
1682 FIXME("Undocumented flag(s): %x\n", dwFlags);
1683 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1686 /***********************************************************************
1687 * SetUrlCacheEntryInfoA (WININET.@)
1689 BOOL WINAPI SetUrlCacheEntryInfoA(
1691 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1692 DWORD dwFieldControl)
1694 LPURLCACHE_HEADER pHeader;
1695 struct _HASH_ENTRY * pHashEntry;
1696 CACHEFILE_ENTRY * pEntry;
1697 URLCACHECONTAINER * pContainer;
1700 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1702 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1703 if (error != ERROR_SUCCESS)
1705 SetLastError(error);
1709 error = URLCacheContainer_OpenIndex(pContainer);
1710 if (error != ERROR_SUCCESS)
1712 SetLastError(error);
1716 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1719 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1721 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1722 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1723 SetLastError(ERROR_FILE_NOT_FOUND);
1727 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1728 if (pEntry->dwSignature != URL_SIGNATURE)
1730 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1731 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1732 SetLastError(ERROR_FILE_NOT_FOUND);
1736 URLCache_SetEntryInfo(
1737 (URL_CACHEFILE_ENTRY *)pEntry,
1738 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1741 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1746 /***********************************************************************
1747 * SetUrlCacheEntryInfoW (WININET.@)
1749 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1751 LPURLCACHE_HEADER pHeader;
1752 struct _HASH_ENTRY * pHashEntry;
1753 CACHEFILE_ENTRY * pEntry;
1754 URLCACHECONTAINER * pContainer;
1757 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1759 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1760 if (error != ERROR_SUCCESS)
1762 SetLastError(error);
1766 error = URLCacheContainer_OpenIndex(pContainer);
1767 if (error != ERROR_SUCCESS)
1769 SetLastError(error);
1773 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1776 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1778 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1779 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1780 SetLastError(ERROR_FILE_NOT_FOUND);
1784 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1785 if (pEntry->dwSignature != URL_SIGNATURE)
1787 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1788 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1789 SetLastError(ERROR_FILE_NOT_FOUND);
1793 URLCache_SetEntryInfo(
1794 (URL_CACHEFILE_ENTRY *)pEntry,
1798 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1803 /***********************************************************************
1804 * RetrieveUrlCacheEntryFileA (WININET.@)
1807 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1808 IN LPCSTR lpszUrlName,
1809 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1810 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1814 LPURLCACHE_HEADER pHeader;
1815 struct _HASH_ENTRY * pHashEntry;
1816 CACHEFILE_ENTRY * pEntry;
1817 URL_CACHEFILE_ENTRY * pUrlEntry;
1818 URLCACHECONTAINER * pContainer;
1821 TRACE("(%s, %p, %p, 0x%08x)\n",
1822 debugstr_a(lpszUrlName),
1824 lpdwCacheEntryInfoBufferSize,
1827 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1828 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1830 SetLastError(ERROR_INVALID_PARAMETER);
1834 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1835 if (error != ERROR_SUCCESS)
1837 SetLastError(error);
1841 error = URLCacheContainer_OpenIndex(pContainer);
1842 if (error != ERROR_SUCCESS)
1844 SetLastError(error);
1848 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1851 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1853 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1854 TRACE("entry %s not found!\n", lpszUrlName);
1855 SetLastError(ERROR_FILE_NOT_FOUND);
1859 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1860 if (pEntry->dwSignature != URL_SIGNATURE)
1862 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1863 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1864 SetLastError(ERROR_FILE_NOT_FOUND);
1868 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1869 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1870 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1872 pUrlEntry->dwHitRate++;
1873 pUrlEntry->dwUseCount++;
1874 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1876 error = URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo,
1877 lpdwCacheEntryInfoBufferSize, pUrlEntry,
1879 if (error != ERROR_SUCCESS)
1881 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1882 SetLastError(error);
1885 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1887 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1892 /***********************************************************************
1893 * RetrieveUrlCacheEntryFileW (WININET.@)
1896 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1897 IN LPCWSTR lpszUrlName,
1898 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1899 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1903 LPURLCACHE_HEADER pHeader;
1904 struct _HASH_ENTRY * pHashEntry;
1905 CACHEFILE_ENTRY * pEntry;
1906 URL_CACHEFILE_ENTRY * pUrlEntry;
1907 URLCACHECONTAINER * pContainer;
1910 TRACE("(%s, %p, %p, 0x%08x)\n",
1911 debugstr_w(lpszUrlName),
1913 lpdwCacheEntryInfoBufferSize,
1916 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1917 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1919 SetLastError(ERROR_INVALID_PARAMETER);
1923 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
1924 if (error != ERROR_SUCCESS)
1926 SetLastError(error);
1930 error = URLCacheContainer_OpenIndex(pContainer);
1931 if (error != ERROR_SUCCESS)
1933 SetLastError(error);
1937 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1940 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1942 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1943 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1944 SetLastError(ERROR_FILE_NOT_FOUND);
1948 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1949 if (pEntry->dwSignature != URL_SIGNATURE)
1951 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1952 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1953 SetLastError(ERROR_FILE_NOT_FOUND);
1957 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1958 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1959 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1961 pUrlEntry->dwHitRate++;
1962 pUrlEntry->dwUseCount++;
1963 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1965 error = URLCache_CopyEntry(
1968 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1969 lpdwCacheEntryInfoBufferSize,
1971 TRUE /* UNICODE */);
1972 if (error != ERROR_SUCCESS)
1974 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1975 SetLastError(error);
1978 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1980 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1985 /***********************************************************************
1986 * UnlockUrlCacheEntryFileA (WININET.@)
1989 BOOL WINAPI UnlockUrlCacheEntryFileA(
1990 IN LPCSTR lpszUrlName,
1994 LPURLCACHE_HEADER pHeader;
1995 struct _HASH_ENTRY * pHashEntry;
1996 CACHEFILE_ENTRY * pEntry;
1997 URL_CACHEFILE_ENTRY * pUrlEntry;
1998 URLCACHECONTAINER * pContainer;
2001 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
2005 ERR("dwReserved != 0\n");
2006 SetLastError(ERROR_INVALID_PARAMETER);
2010 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2011 if (error != ERROR_SUCCESS)
2013 SetLastError(error);
2017 error = URLCacheContainer_OpenIndex(pContainer);
2018 if (error != ERROR_SUCCESS)
2020 SetLastError(error);
2024 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2027 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2029 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2030 TRACE("entry %s not found!\n", lpszUrlName);
2031 SetLastError(ERROR_FILE_NOT_FOUND);
2035 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2036 if (pEntry->dwSignature != URL_SIGNATURE)
2038 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2039 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2040 SetLastError(ERROR_FILE_NOT_FOUND);
2044 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2046 if (pUrlEntry->dwUseCount == 0)
2048 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2051 pUrlEntry->dwUseCount--;
2052 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2054 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2059 /***********************************************************************
2060 * UnlockUrlCacheEntryFileW (WININET.@)
2063 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
2065 LPURLCACHE_HEADER pHeader;
2066 struct _HASH_ENTRY * pHashEntry;
2067 CACHEFILE_ENTRY * pEntry;
2068 URL_CACHEFILE_ENTRY * pUrlEntry;
2069 URLCACHECONTAINER * pContainer;
2072 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
2076 ERR("dwReserved != 0\n");
2077 SetLastError(ERROR_INVALID_PARAMETER);
2081 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2082 if (error != ERROR_SUCCESS)
2084 SetLastError(error);
2088 error = URLCacheContainer_OpenIndex(pContainer);
2089 if (error != ERROR_SUCCESS)
2091 SetLastError(error);
2095 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2098 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
2100 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2101 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
2102 SetLastError(ERROR_FILE_NOT_FOUND);
2106 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2107 if (pEntry->dwSignature != URL_SIGNATURE)
2109 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2110 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2111 SetLastError(ERROR_FILE_NOT_FOUND);
2115 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2117 if (pUrlEntry->dwUseCount == 0)
2119 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2122 pUrlEntry->dwUseCount--;
2123 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2125 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2130 /***********************************************************************
2131 * CreateUrlCacheEntryA (WININET.@)
2134 BOOL WINAPI CreateUrlCacheEntryA(
2135 IN LPCSTR lpszUrlName,
2136 IN DWORD dwExpectedFileSize,
2137 IN LPCSTR lpszFileExtension,
2138 OUT LPSTR lpszFileName,
2143 WCHAR *file_extension;
2144 WCHAR file_name[MAX_PATH];
2145 BOOL bSuccess = FALSE;
2148 if (lpszUrlName && (url_name = heap_strdupAtoW(lpszUrlName)))
2150 if (lpszFileExtension && (file_extension = heap_strdupAtoW(lpszFileExtension)))
2152 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
2154 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
2160 dwError = GetLastError();
2165 dwError = GetLastError();
2167 HeapFree(GetProcessHeap(), 0, file_extension);
2171 dwError = GetLastError();
2173 HeapFree(GetProcessHeap(), 0, url_name);
2175 SetLastError(dwError);
2179 /***********************************************************************
2180 * CreateUrlCacheEntryW (WININET.@)
2183 BOOL WINAPI CreateUrlCacheEntryW(
2184 IN LPCWSTR lpszUrlName,
2185 IN DWORD dwExpectedFileSize,
2186 IN LPCWSTR lpszFileExtension,
2187 OUT LPWSTR lpszFileName,
2191 URLCACHECONTAINER * pContainer;
2192 LPURLCACHE_HEADER pHeader;
2193 CHAR szFile[MAX_PATH];
2194 WCHAR szExtension[MAX_PATH];
2195 LPCWSTR lpszUrlPart;
2197 LPCWSTR lpszFileNameExtension;
2198 LPWSTR lpszFileNameNoPath;
2200 int countnoextension;
2203 BOOL bFound = FALSE;
2209 static const WCHAR szWWW[] = {'w','w','w',0};
2210 static const WCHAR fmt[] = {'%','0','8','X','%','s',0};
2212 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2213 debugstr_w(lpszUrlName),
2215 debugstr_w(lpszFileExtension),
2220 FIXME("dwReserved 0x%08x\n", dwReserved);
2222 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2224 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2227 for (lpszUrlPart = lpszUrlEnd;
2228 (lpszUrlPart >= lpszUrlName);
2231 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2237 else if(*lpszUrlPart == '?' || *lpszUrlPart == '#')
2239 lpszUrlEnd = lpszUrlPart;
2242 if (!lstrcmpW(lpszUrlPart, szWWW))
2244 lpszUrlPart += lstrlenW(szWWW);
2247 count = lpszUrlEnd - lpszUrlPart;
2249 if (bFound && (count < MAX_PATH))
2251 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2255 while(len && szFile[--len] == '/') szFile[len] = '\0';
2257 /* FIXME: get rid of illegal characters like \, / and : */
2261 FIXME("need to generate a random filename\n");
2264 TRACE("File name: %s\n", debugstr_a(szFile));
2266 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2267 if (error != ERROR_SUCCESS)
2269 SetLastError(error);
2273 error = URLCacheContainer_OpenIndex(pContainer);
2274 if (error != ERROR_SUCCESS)
2276 SetLastError(error);
2280 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2283 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2285 lBufferSize = MAX_PATH * sizeof(WCHAR);
2286 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
2288 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2290 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2291 lpszFileNameNoPath >= lpszFileName;
2292 --lpszFileNameNoPath)
2294 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2298 countnoextension = lstrlenW(lpszFileNameNoPath);
2299 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2300 if (lpszFileNameExtension)
2301 countnoextension -= lstrlenW(lpszFileNameExtension);
2302 *szExtension = '\0';
2304 if (lpszFileExtension)
2306 szExtension[0] = '.';
2307 lstrcpyW(szExtension+1, lpszFileExtension);
2310 for (i = 0; i < 255; i++)
2312 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2315 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2316 for (p = lpszFileNameNoPath + 1; *p; p++)
2322 case '/': case '\\':
2329 if (p[-1] == ' ' || p[-1] == '.') p[-1] = '_';
2331 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2332 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2333 if (hFile != INVALID_HANDLE_VALUE)
2340 GetSystemTimeAsFileTime(&ft);
2341 wsprintfW(lpszFileNameNoPath + countnoextension, fmt, ft.dwLowDateTime, szExtension);
2343 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2344 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2345 if (hFile != INVALID_HANDLE_VALUE)
2351 WARN("Could not find a unique filename\n");
2356 /***********************************************************************
2357 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2359 * The bug we are compensating for is that some drongo at Microsoft
2360 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2361 * As a consequence, CommitUrlCacheEntryA has been effectively
2362 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2363 * is still defined as LPCWSTR. The result (other than madness) is
2364 * that we always need to store lpHeaderInfo in CP_ACP rather than
2365 * in UTF16, and we need to avoid converting lpHeaderInfo in
2366 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2367 * result will lose data for arbitrary binary data.
2370 static BOOL CommitUrlCacheEntryInternal(
2371 IN LPCWSTR lpszUrlName,
2372 IN LPCWSTR lpszLocalFileName,
2373 IN FILETIME ExpireTime,
2374 IN FILETIME LastModifiedTime,
2375 IN DWORD CacheEntryType,
2376 IN LPBYTE lpHeaderInfo,
2377 IN DWORD dwHeaderSize,
2378 IN LPCWSTR lpszFileExtension,
2379 IN LPCWSTR lpszOriginalUrl
2382 URLCACHECONTAINER * pContainer;
2383 LPURLCACHE_HEADER pHeader;
2384 struct _HASH_ENTRY * pHashEntry;
2385 CACHEFILE_ENTRY * pEntry;
2386 URL_CACHEFILE_ENTRY * pUrlEntry;
2387 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2388 DWORD dwOffsetLocalFileName = 0;
2389 DWORD dwOffsetHeader = 0;
2390 DWORD dwOffsetFileExtension = 0;
2391 DWORD dwFileSizeLow = 0;
2392 DWORD dwFileSizeHigh = 0;
2393 BYTE cDirectory = 0;
2395 char achFile[MAX_PATH];
2396 LPSTR lpszUrlNameA = NULL;
2397 LPSTR lpszFileExtensionA = NULL;
2398 char *pchLocalFileName = 0;
2401 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2402 debugstr_w(lpszUrlName),
2403 debugstr_w(lpszLocalFileName),
2407 debugstr_w(lpszFileExtension),
2408 debugstr_w(lpszOriginalUrl));
2410 if (lpszOriginalUrl)
2411 WARN(": lpszOriginalUrl ignored\n");
2413 if (lpszLocalFileName)
2417 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2418 if (hFile == INVALID_HANDLE_VALUE)
2420 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2425 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2426 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2428 ERR("couldn't get file size (error is %d)\n", GetLastError());
2436 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2437 if (error != ERROR_SUCCESS)
2439 SetLastError(error);
2443 error = URLCacheContainer_OpenIndex(pContainer);
2444 if (error != ERROR_SUCCESS)
2446 SetLastError(error);
2450 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2453 lpszUrlNameA = heap_strdupWtoA(lpszUrlName);
2456 error = GetLastError();
2460 if (lpszFileExtension && !(lpszFileExtensionA = heap_strdupWtoA(lpszFileExtension)))
2462 error = GetLastError();
2466 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2468 FIXME("entry already in cache - don't know what to do!\n");
2470 * SetLastError(ERROR_FILE_NOT_FOUND);
2476 if (lpszLocalFileName)
2478 BOOL bFound = FALSE;
2480 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2482 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2483 error = ERROR_INVALID_PARAMETER;
2487 /* skip container path prefix */
2488 lpszLocalFileName += lstrlenW(pContainer->path);
2490 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL);
2491 pchLocalFileName = achFile;
2493 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2495 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2504 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2505 error = ERROR_INVALID_PARAMETER;
2509 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2512 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2513 if (lpszLocalFileName)
2515 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2516 dwOffsetLocalFileName = dwBytesNeeded;
2517 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2521 dwOffsetHeader = dwBytesNeeded;
2522 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2524 if (lpszFileExtensionA)
2526 dwOffsetFileExtension = dwBytesNeeded;
2527 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2530 /* round up to next block */
2531 if (dwBytesNeeded % BLOCKSIZE)
2533 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2534 dwBytesNeeded += BLOCKSIZE;
2537 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2539 ERR("no free entries\n");
2540 error = ERROR_DISK_FULL;
2544 /* FindFirstFreeEntry fills in blocks used */
2545 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2546 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2547 pUrlEntry->CacheDir = cDirectory;
2548 pUrlEntry->CacheEntryType = CacheEntryType;
2549 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2550 pUrlEntry->dwExemptDelta = 0;
2551 pUrlEntry->dwHitRate = 0;
2552 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2553 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2554 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2555 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2556 pUrlEntry->dwSizeHigh = 0;
2557 pUrlEntry->dwSizeLow = dwFileSizeLow;
2558 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2559 pUrlEntry->dwUseCount = 0;
2560 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2561 pUrlEntry->LastModifiedTime = LastModifiedTime;
2562 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2563 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2564 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2565 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2568 pUrlEntry->dwUnknown1 = 0;
2569 pUrlEntry->dwUnknown2 = 0;
2570 pUrlEntry->dwUnknown3 = 0x60;
2571 pUrlEntry->Unknown4 = 0;
2572 pUrlEntry->wUnknown5 = 0x1010;
2573 pUrlEntry->dwUnknown7 = 0;
2574 pUrlEntry->dwUnknown8 = 0;
2577 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2578 if (dwOffsetLocalFileName)
2579 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2581 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2582 if (dwOffsetFileExtension)
2583 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2585 error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA,
2586 (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader));
2587 if (error != ERROR_SUCCESS)
2588 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2591 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2592 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2593 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2595 if (error == ERROR_SUCCESS)
2599 SetLastError(error);
2604 /***********************************************************************
2605 * CommitUrlCacheEntryA (WININET.@)
2608 BOOL WINAPI CommitUrlCacheEntryA(
2609 IN LPCSTR lpszUrlName,
2610 IN LPCSTR lpszLocalFileName,
2611 IN FILETIME ExpireTime,
2612 IN FILETIME LastModifiedTime,
2613 IN DWORD CacheEntryType,
2614 IN LPBYTE lpHeaderInfo,
2615 IN DWORD dwHeaderSize,
2616 IN LPCSTR lpszFileExtension,
2617 IN LPCSTR lpszOriginalUrl
2620 WCHAR *url_name = NULL;
2621 WCHAR *local_file_name = NULL;
2622 WCHAR *original_url = NULL;
2623 WCHAR *file_extension = NULL;
2624 BOOL bSuccess = FALSE;
2626 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2627 debugstr_a(lpszUrlName),
2628 debugstr_a(lpszLocalFileName),
2632 debugstr_a(lpszFileExtension),
2633 debugstr_a(lpszOriginalUrl));
2635 url_name = heap_strdupAtoW(lpszUrlName);
2639 if (lpszLocalFileName)
2641 local_file_name = heap_strdupAtoW(lpszLocalFileName);
2642 if (!local_file_name)
2645 if (lpszFileExtension)
2647 file_extension = heap_strdupAtoW(lpszFileExtension);
2648 if (!file_extension)
2651 if (lpszOriginalUrl)
2653 original_url = heap_strdupAtoW(lpszOriginalUrl);
2658 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2659 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2660 file_extension, original_url);
2663 HeapFree(GetProcessHeap(), 0, original_url);
2664 HeapFree(GetProcessHeap(), 0, file_extension);
2665 HeapFree(GetProcessHeap(), 0, local_file_name);
2666 HeapFree(GetProcessHeap(), 0, url_name);
2671 /***********************************************************************
2672 * CommitUrlCacheEntryW (WININET.@)
2675 BOOL WINAPI CommitUrlCacheEntryW(
2676 IN LPCWSTR lpszUrlName,
2677 IN LPCWSTR lpszLocalFileName,
2678 IN FILETIME ExpireTime,
2679 IN FILETIME LastModifiedTime,
2680 IN DWORD CacheEntryType,
2681 IN LPWSTR lpHeaderInfo,
2682 IN DWORD dwHeaderSize,
2683 IN LPCWSTR lpszFileExtension,
2684 IN LPCWSTR lpszOriginalUrl
2688 BOOL bSuccess = FALSE;
2690 CHAR *header_info = NULL;
2692 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2693 debugstr_w(lpszUrlName),
2694 debugstr_w(lpszLocalFileName),
2698 debugstr_w(lpszFileExtension),
2699 debugstr_w(lpszOriginalUrl));
2701 if (!lpHeaderInfo || (header_info = heap_strdupWtoA(lpHeaderInfo)))
2703 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2704 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2710 dwError = GetLastError();
2714 HeapFree(GetProcessHeap(), 0, header_info);
2716 SetLastError(dwError);
2722 /***********************************************************************
2723 * ReadUrlCacheEntryStream (WININET.@)
2726 BOOL WINAPI ReadUrlCacheEntryStream(
2727 IN HANDLE hUrlCacheStream,
2728 IN DWORD dwLocation,
2729 IN OUT LPVOID lpBuffer,
2730 IN OUT LPDWORD lpdwLen,
2734 /* Get handle to file from 'stream' */
2735 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2737 if (dwReserved != 0)
2739 ERR("dwReserved != 0\n");
2740 SetLastError(ERROR_INVALID_PARAMETER);
2744 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2746 SetLastError(ERROR_INVALID_HANDLE);
2750 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2752 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2755 /***********************************************************************
2756 * RetrieveUrlCacheEntryStreamA (WININET.@)
2759 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2760 IN LPCSTR lpszUrlName,
2761 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2762 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2763 IN BOOL fRandomRead,
2767 /* NOTE: this is not the same as the way that the native
2768 * version allocates 'stream' handles. I did it this way
2769 * as it is much easier and no applications should depend
2770 * on this behaviour. (Native version appears to allocate
2771 * indices into a table)
2773 STREAM_HANDLE * pStream;
2776 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2777 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2779 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2781 lpdwCacheEntryInfoBufferSize,
2787 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2792 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2794 if (hFile == INVALID_HANDLE_VALUE)
2797 /* allocate handle storage space */
2798 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2802 SetLastError(ERROR_OUTOFMEMORY);
2806 pStream->hFile = hFile;
2807 strcpy(pStream->lpszUrl, lpszUrlName);
2811 /***********************************************************************
2812 * RetrieveUrlCacheEntryStreamW (WININET.@)
2815 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2816 IN LPCWSTR lpszUrlName,
2817 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2818 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2819 IN BOOL fRandomRead,
2823 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2824 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2828 /***********************************************************************
2829 * UnlockUrlCacheEntryStream (WININET.@)
2832 BOOL WINAPI UnlockUrlCacheEntryStream(
2833 IN HANDLE hUrlCacheStream,
2837 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2839 if (dwReserved != 0)
2841 ERR("dwReserved != 0\n");
2842 SetLastError(ERROR_INVALID_PARAMETER);
2846 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2848 SetLastError(ERROR_INVALID_HANDLE);
2852 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2855 /* close file handle */
2856 CloseHandle(pStream->hFile);
2858 /* free allocated space */
2859 HeapFree(GetProcessHeap(), 0, pStream);
2865 /***********************************************************************
2866 * DeleteUrlCacheEntryA (WININET.@)
2869 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2871 URLCACHECONTAINER * pContainer;
2872 LPURLCACHE_HEADER pHeader;
2873 struct _HASH_ENTRY * pHashEntry;
2874 CACHEFILE_ENTRY * pEntry;
2877 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2879 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2880 if (error != ERROR_SUCCESS)
2882 SetLastError(error);
2886 error = URLCacheContainer_OpenIndex(pContainer);
2887 if (error != ERROR_SUCCESS)
2889 SetLastError(error);
2893 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2896 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2898 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2899 TRACE("entry %s not found!\n", lpszUrlName);
2900 SetLastError(ERROR_FILE_NOT_FOUND);
2904 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2905 URLCache_DeleteEntry(pHeader, pEntry);
2907 URLCache_DeleteEntryFromHash(pHashEntry);
2909 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2914 /***********************************************************************
2915 * DeleteUrlCacheEntryW (WININET.@)
2918 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2920 URLCACHECONTAINER * pContainer;
2921 LPURLCACHE_HEADER pHeader;
2922 struct _HASH_ENTRY * pHashEntry;
2923 CACHEFILE_ENTRY * pEntry;
2927 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2929 urlA = heap_strdupWtoA(lpszUrlName);
2932 SetLastError(ERROR_OUTOFMEMORY);
2936 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2937 if (error != ERROR_SUCCESS)
2939 HeapFree(GetProcessHeap(), 0, urlA);
2940 SetLastError(error);
2944 error = URLCacheContainer_OpenIndex(pContainer);
2945 if (error != ERROR_SUCCESS)
2947 HeapFree(GetProcessHeap(), 0, urlA);
2948 SetLastError(error);
2952 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2954 HeapFree(GetProcessHeap(), 0, urlA);
2958 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
2960 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2961 TRACE("entry %s not found!\n", debugstr_a(urlA));
2962 HeapFree(GetProcessHeap(), 0, urlA);
2963 SetLastError(ERROR_FILE_NOT_FOUND);
2967 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2968 URLCache_DeleteEntry(pHeader, pEntry);
2970 URLCache_DeleteEntryFromHash(pHashEntry);
2972 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2974 HeapFree(GetProcessHeap(), 0, urlA);
2978 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2980 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2984 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2986 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2990 /***********************************************************************
2991 * CreateCacheContainerA (WININET.@)
2993 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2994 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2996 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2997 d1, d2, d3, d4, d5, d6, d7, d8);
3001 /***********************************************************************
3002 * CreateCacheContainerW (WININET.@)
3004 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3005 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3007 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3008 d1, d2, d3, d4, d5, d6, d7, d8);
3012 /***********************************************************************
3013 * FindFirstUrlCacheContainerA (WININET.@)
3015 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3017 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3021 /***********************************************************************
3022 * FindFirstUrlCacheContainerW (WININET.@)
3024 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3026 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3030 /***********************************************************************
3031 * FindNextUrlCacheContainerA (WININET.@)
3033 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
3035 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3039 /***********************************************************************
3040 * FindNextUrlCacheContainerW (WININET.@)
3042 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
3044 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3048 HANDLE WINAPI FindFirstUrlCacheEntryExA(
3049 LPCSTR lpszUrlSearchPattern,
3053 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3054 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3056 LPDWORD pcbReserved2,
3060 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
3061 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3062 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3063 SetLastError(ERROR_FILE_NOT_FOUND);
3067 HANDLE WINAPI FindFirstUrlCacheEntryExW(
3068 LPCWSTR lpszUrlSearchPattern,
3072 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3073 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3075 LPDWORD pcbReserved2,
3079 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
3080 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3081 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3082 SetLastError(ERROR_FILE_NOT_FOUND);
3086 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3088 typedef struct URLCacheFindEntryHandle
3091 LPWSTR lpszUrlSearchPattern;
3092 DWORD dwContainerIndex;
3093 DWORD dwHashTableIndex;
3094 DWORD dwHashEntryIndex;
3095 } URLCacheFindEntryHandle;
3097 /***********************************************************************
3098 * FindFirstUrlCacheEntryA (WININET.@)
3101 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
3102 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3104 URLCacheFindEntryHandle *pEntryHandle;
3106 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3108 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3112 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3113 if (lpszUrlSearchPattern)
3115 pEntryHandle->lpszUrlSearchPattern = heap_strdupAtoW(lpszUrlSearchPattern);
3116 if (!pEntryHandle->lpszUrlSearchPattern)
3118 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3123 pEntryHandle->lpszUrlSearchPattern = NULL;
3124 pEntryHandle->dwContainerIndex = 0;
3125 pEntryHandle->dwHashTableIndex = 0;
3126 pEntryHandle->dwHashEntryIndex = 0;
3128 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3130 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3133 return pEntryHandle;
3136 /***********************************************************************
3137 * FindFirstUrlCacheEntryW (WININET.@)
3140 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3141 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3143 URLCacheFindEntryHandle *pEntryHandle;
3145 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3147 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3151 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3152 if (lpszUrlSearchPattern)
3154 pEntryHandle->lpszUrlSearchPattern = heap_strdupW(lpszUrlSearchPattern);
3155 if (!pEntryHandle->lpszUrlSearchPattern)
3157 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3162 pEntryHandle->lpszUrlSearchPattern = NULL;
3163 pEntryHandle->dwContainerIndex = 0;
3164 pEntryHandle->dwHashTableIndex = 0;
3165 pEntryHandle->dwHashEntryIndex = 0;
3167 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3169 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3172 return pEntryHandle;
3175 /***********************************************************************
3176 * FindNextUrlCacheEntryA (WININET.@)
3178 BOOL WINAPI FindNextUrlCacheEntryA(
3180 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3181 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3183 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3184 URLCACHECONTAINER * pContainer;
3186 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3188 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3190 SetLastError(ERROR_INVALID_HANDLE);
3194 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3195 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3197 LPURLCACHE_HEADER pHeader;
3198 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3201 error = URLCacheContainer_OpenIndex(pContainer);
3202 if (error != ERROR_SUCCESS)
3204 SetLastError(error);
3208 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3211 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3212 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3214 const struct _HASH_ENTRY *pHashEntry = NULL;
3215 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3216 pEntryHandle->dwHashEntryIndex++)
3218 const URL_CACHEFILE_ENTRY *pUrlEntry;
3219 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3221 if (pEntry->dwSignature != URL_SIGNATURE)
3224 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3225 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3226 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3228 error = URLCache_CopyEntry(
3231 lpNextCacheEntryInfo,
3232 lpdwNextCacheEntryInfoBufferSize,
3234 FALSE /* not UNICODE */);
3235 if (error != ERROR_SUCCESS)
3237 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3238 SetLastError(error);
3241 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
3243 /* increment the current index so that next time the function
3244 * is called the next entry is returned */
3245 pEntryHandle->dwHashEntryIndex++;
3246 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3251 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3254 SetLastError(ERROR_NO_MORE_ITEMS);
3258 /***********************************************************************
3259 * FindNextUrlCacheEntryW (WININET.@)
3261 BOOL WINAPI FindNextUrlCacheEntryW(
3263 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3264 LPDWORD lpdwNextCacheEntryInfoBufferSize
3267 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3268 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3272 /***********************************************************************
3273 * FindCloseUrlCache (WININET.@)
3275 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3277 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3279 TRACE("(%p)\n", hEnumHandle);
3281 if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3283 SetLastError(ERROR_INVALID_HANDLE);
3287 pEntryHandle->dwMagic = 0;
3288 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3289 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3294 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3295 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3297 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3298 dwSearchCondition, lpGroupId, lpReserved);
3302 BOOL WINAPI FindNextUrlCacheEntryExA(
3304 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3305 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3307 LPDWORD pcbReserved2,
3311 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3312 lpReserved, pcbReserved2, lpReserved3);
3316 BOOL WINAPI FindNextUrlCacheEntryExW(
3318 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3319 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3321 LPDWORD pcbReserved2,
3325 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3326 lpReserved, pcbReserved2, lpReserved3);
3330 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3332 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3336 /***********************************************************************
3337 * CreateUrlCacheGroup (WININET.@)
3340 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3342 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3346 /***********************************************************************
3347 * DeleteUrlCacheGroup (WININET.@)
3350 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3352 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3353 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3357 /***********************************************************************
3358 * SetUrlCacheEntryGroupA (WININET.@)
3361 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3362 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3365 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3366 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3367 pbGroupAttributes, cbGroupAttributes, lpReserved);
3368 SetLastError(ERROR_FILE_NOT_FOUND);
3372 /***********************************************************************
3373 * SetUrlCacheEntryGroupW (WININET.@)
3376 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3377 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3380 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3381 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3382 pbGroupAttributes, cbGroupAttributes, lpReserved);
3383 SetLastError(ERROR_FILE_NOT_FOUND);
3387 /***********************************************************************
3388 * GetUrlCacheConfigInfoW (WININET.@)
3390 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3392 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3393 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3397 /***********************************************************************
3398 * GetUrlCacheConfigInfoA (WININET.@)
3400 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3402 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3404 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3405 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3409 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3410 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3411 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3413 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3414 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3415 lpdwGroupInfo, lpReserved);
3419 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3420 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3421 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3423 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3424 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3425 lpdwGroupInfo, lpReserved);
3429 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3430 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3432 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3433 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3437 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3438 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3440 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3441 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3445 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3447 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3451 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3453 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3457 /***********************************************************************
3458 * DeleteIE3Cache (WININET.@)
3460 * Deletes the files used by the IE3 URL caching system.
3463 * hWnd [I] A dummy window.
3464 * hInst [I] Instance of process calling the function.
3465 * lpszCmdLine [I] Options used by function.
3466 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3468 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3470 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3474 /***********************************************************************
3475 * IsUrlCacheEntryExpiredA (WININET.@)
3479 * dwFlags [I] Unknown
3480 * pftLastModified [O] Last modified time
3482 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3484 LPURLCACHE_HEADER pHeader;
3485 struct _HASH_ENTRY * pHashEntry;
3486 const CACHEFILE_ENTRY * pEntry;
3487 const URL_CACHEFILE_ENTRY * pUrlEntry;
3488 URLCACHECONTAINER * pContainer;
3491 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3493 error = URLCacheContainers_FindContainerA(url, &pContainer);
3494 if (error != ERROR_SUCCESS)
3496 SetLastError(error);
3500 error = URLCacheContainer_OpenIndex(pContainer);
3501 if (error != ERROR_SUCCESS)
3503 SetLastError(error);
3507 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3510 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3512 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3513 TRACE("entry %s not found!\n", url);
3514 SetLastError(ERROR_FILE_NOT_FOUND);
3518 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3519 if (pEntry->dwSignature != URL_SIGNATURE)
3521 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3522 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3523 SetLastError(ERROR_FILE_NOT_FOUND);
3527 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3529 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3531 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3536 /***********************************************************************
3537 * IsUrlCacheEntryExpiredW (WININET.@)
3541 * dwFlags [I] Unknown
3542 * pftLastModified [O] Last modified time
3544 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3546 LPURLCACHE_HEADER pHeader;
3547 struct _HASH_ENTRY * pHashEntry;
3548 const CACHEFILE_ENTRY * pEntry;
3549 const URL_CACHEFILE_ENTRY * pUrlEntry;
3550 URLCACHECONTAINER * pContainer;
3553 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3555 error = URLCacheContainers_FindContainerW(url, &pContainer);
3556 if (error != ERROR_SUCCESS)
3558 SetLastError(error);
3562 error = URLCacheContainer_OpenIndex(pContainer);
3563 if (error != ERROR_SUCCESS)
3565 SetLastError(error);
3569 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3572 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3574 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3575 TRACE("entry %s not found!\n", debugstr_w(url));
3576 SetLastError(ERROR_FILE_NOT_FOUND);
3580 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3581 if (pEntry->dwSignature != URL_SIGNATURE)
3583 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3584 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3585 SetLastError(ERROR_FILE_NOT_FOUND);
3589 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3591 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3593 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3598 /***********************************************************************
3599 * GetDiskInfoA (WININET.@)
3601 BOOL WINAPI GetDiskInfoA(PCSTR path, PDWORD cluster_size, PDWORDLONG free, PDWORDLONG total)
3604 ULARGE_INTEGER bytes_free, bytes_total;
3606 TRACE("(%s, %p, %p, %p)\n", debugstr_a(path), cluster_size, free, total);
3610 SetLastError(ERROR_INVALID_PARAMETER);
3614 if ((ret = GetDiskFreeSpaceExA(path, NULL, &bytes_total, &bytes_free)))
3616 if (cluster_size) *cluster_size = 1;
3617 if (free) *free = bytes_free.QuadPart;
3618 if (total) *total = bytes_total.QuadPart;
3623 /***********************************************************************
3624 * RegisterUrlCacheNotification (WININET.@)
3626 DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
3628 FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f);
3632 /***********************************************************************
3633 * IncrementUrlCacheHeaderData (WININET.@)
3635 BOOL WINAPI IncrementUrlCacheHeaderData(DWORD index, LPDWORD data)
3637 FIXME("(%u, %p)\n", index, data);