2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003 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
25 #define COM_NO_WINDOWS_H
27 #include "wine/port.h"
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
49 #include "wine/unicode.h"
50 #include "wine/list.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
55 #define ENTRY_START_OFFSET 0x4000
58 #define HASHTABLE_SIZE 448
59 #define HASHTABLE_BLOCKSIZE 7
60 #define HASHTABLE_FREE 3
61 #define ALLOCATION_TABLE_OFFSET 0x250
62 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
63 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
64 #define NEWFILE_NUM_BLOCKS 0xd80
65 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
67 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
68 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
69 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
70 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
71 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
73 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
75 typedef struct _CACHEFILE_ENTRY
79 DWORD dwSignature; /* e.g. "URL " */
80 /* CHAR szSignature[4];
82 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
85 typedef struct _URL_CACHEFILE_ENTRY
87 CACHEFILE_ENTRY CacheFileEntry;
88 FILETIME LastModifiedTime;
89 FILETIME LastAccessTime;
90 WORD wExpiredDate; /* expire date in dos format */
91 WORD wExpiredTime; /* expire time in dos format */
92 DWORD dwUnknown1; /* usually zero */
93 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
94 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
95 DWORD dwUnknown2; /* usually zero */
96 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
97 DWORD dwUnknown3; /* usually 0x60 */
98 DWORD dwOffsetUrl; /* offset of start of url from start of entry */
99 BYTE CacheDir; /* index of cache directory this url is stored in */
100 BYTE Unknown4; /* usually zero */
101 WORD wUnknown5; /* usually 0x1010 */
102 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
103 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
104 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
105 DWORD dwHeaderInfoSize;
106 DWORD dwUnknown6; /* usually zero */
107 WORD wLastSyncDate; /* last sync date in dos format */
108 WORD wLastSyncTime; /* last sync time in dos format */
109 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
110 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
111 WORD wUnknownDate; /* usually same as wLastSyncDate */
112 WORD wUnknownTime; /* usually same as wLastSyncTime */
113 DWORD dwUnknown7; /* usually zero */
114 DWORD dwUnknown8; /* usually zero */
115 /* packing to dword align start of next field */
116 /* CHAR szSourceUrlName[]; (url) */
117 /* packing to dword align start of next field */
118 /* CHAR szLocalFileName[]; (local file name exluding path) */
119 /* packing to dword align start of next field */
120 /* CHAR szHeaderInfo[]; (header info) */
121 } URL_CACHEFILE_ENTRY;
129 typedef struct _HASH_CACHEFILE_ENTRY
131 CACHEFILE_ENTRY CacheFileEntry;
133 DWORD dwHashTableNumber;
134 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
135 } HASH_CACHEFILE_ENTRY;
137 typedef struct _DIRECTORY_DATA
140 char filename[DIR_LENGTH];
143 typedef struct _URLCACHE_HEADER
145 char szSignature[28];
147 DWORD dwOffsetFirstHashTable;
148 DWORD dwIndexCapacityInBlocks;
151 DWORD dwCacheLimitLow; /* disk space limit for cache */
152 DWORD dwCacheLimitHigh; /* disk space limit for cache */
153 DWORD dwUnknown4; /* current disk space usage for cache */
154 DWORD dwUnknown5; /* current disk space usage for cache */
155 DWORD dwUnknown6; /* possibly a flag? */
157 BYTE DirectoryCount; /* number of directory_data's */
158 BYTE Unknown8[3]; /* just padding? */
159 DIRECTORY_DATA directory_data[1]; /* first directory entry */
160 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
161 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
163 typedef struct _STREAM_HANDLE
169 typedef struct _URLCACHECONTAINER
171 struct list entry; /* part of a list */
172 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
173 LPWSTR path; /* path to url container directory */
174 HANDLE hMapping; /* handle of file mapping */
175 DWORD file_size; /* size of file when mapping was opened */
176 HANDLE hMutex; /* hande of mutex */
180 /* List of all containers available */
181 static struct list UrlContainers = LIST_INIT(UrlContainers);
183 static HASH_CACHEFILE_ENTRY *URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash);
185 /***********************************************************************
186 * URLCache_PathToObjectName (Internal)
188 * Converts a path to a name suitable for use as a Win32 object name.
189 * Replaces '\\' characters in-place with the specified character
190 * (usually '_' or '!')
196 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
198 for (; *lpszPath; lpszPath++)
200 if (*lpszPath == '\\')
205 /***********************************************************************
206 * URLCacheContainer_OpenIndex (Internal)
208 * Opens the index file and saves mapping handle in hCacheIndexMapping
215 static BOOL URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
218 WCHAR wszFilePath[MAX_PATH];
221 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
222 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
224 if (pContainer->hMapping)
227 strcpyW(wszFilePath, pContainer->path);
228 strcatW(wszFilePath, wszIndex);
230 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
231 if (hFile == INVALID_HANDLE_VALUE)
233 /* Maybe the directory wasn't there? Try to create it */
234 if (CreateDirectoryW(pContainer->path, 0))
235 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 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath));
243 /* At this stage we need the mutex because we may be about to create the
246 WaitForSingleObject(pContainer->hMutex, INFINITE);
248 dwFileSize = GetFileSize(hFile, NULL);
249 if (dwFileSize == INVALID_FILE_SIZE)
251 ReleaseMutex(pContainer->hMutex);
257 static CHAR const szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Cache\\Content";
259 char achZeroes[0x1000];
263 /* Write zeroes to the entire file so we can safely map it without
264 * fear of getting a SEGV because the disk is full.
266 memset(achZeroes, 0, sizeof(achZeroes));
267 for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes))
269 DWORD dwWrite = sizeof(achZeroes);
272 if (NEWFILE_SIZE - dwOffset < dwWrite)
273 dwWrite = NEWFILE_SIZE - dwOffset;
274 if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) ||
275 dwWritten != dwWrite)
277 /* If we fail to write, we need to return the error that
278 * cause the problem and also make sure the file is no
279 * longer there, if possible.
281 dwError = GetLastError();
289 HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL);
293 URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE);
298 WCHAR wszDirPath[MAX_PATH];
302 dwFileSize = NEWFILE_SIZE;
304 /* First set some constants and defaults in the header */
305 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
306 pHeader->dwFileSize = dwFileSize;
307 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
308 /* 127MB - taken from default for Windows 2000 */
309 pHeader->dwCacheLimitHigh = 0;
310 pHeader->dwCacheLimitLow = 0x07ff5400;
311 /* Copied from a Windows 2000 cache index */
312 pHeader->DirectoryCount = 4;
314 /* If the registry has a cache size set, use the registry value */
315 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
318 DWORD len = sizeof(dw);
321 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
322 (BYTE *) &dw, &len) == ERROR_SUCCESS &&
323 keytype == REG_DWORD)
325 pHeader->dwCacheLimitHigh = (dw >> 22);
326 pHeader->dwCacheLimitLow = dw << 10;
331 URLCache_CreateHashTable(pHeader, NULL);
333 /* Last step - create the directories */
335 strcpyW(wszDirPath, pContainer->path);
336 pwchDir = wszDirPath + strlenW(wszDirPath);
339 GetSystemTimeAsFileTime(&ft);
341 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
343 /* The following values were copied from a Windows index.
344 * I don't know what the values are supposed to mean but
345 * have made them the same in the hope that this will
346 * be better for compatibility
348 pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
352 ULONGLONG n = ft.dwHighDateTime;
354 /* Generate a file name to attempt to create.
355 * This algorithm will create what will appear
356 * to be random and unrelated directory names
357 * of up to 9 characters in length.
360 n += ft.dwLowDateTime;
361 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
363 for (k = 0; k < 8; ++k)
367 /* Dividing by a prime greater than 36 helps
368 * with the appearance of randomness
373 pwchDir[k] = '0' + r;
375 pwchDir[k] = 'A' + (r - 10);
378 if (CreateDirectoryW(wszDirPath, 0))
382 /* The following is OK because we generated an
383 * 8 character directory name made from characters
384 * [A-Z0-9], which are equivalent for all code
385 * pages and for UTF-16
387 for (k = 0; k < 8; ++k)
388 pHeader->directory_data[i].filename[k] = pwchDir[k];
393 /* Give up. The most likely cause of this
394 * is a full disk, but whatever the cause
395 * is, it should be more than apparent that
398 dwError = GetLastError();
404 UnmapViewOfFile(pHeader);
408 dwError = GetLastError();
410 CloseHandle(hMapping);
414 dwError = GetLastError();
421 DeleteFileW(wszFilePath);
422 ReleaseMutex(pContainer->hMutex);
423 SetLastError(dwError);
429 ReleaseMutex(pContainer->hMutex);
431 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
432 URLCache_PathToObjectName(wszFilePath, '_');
433 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
434 if (!pContainer->hMapping)
435 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
437 if (!pContainer->hMapping)
439 ERR("Couldn't create file mapping (error is %ld)\n", GetLastError());
446 /***********************************************************************
447 * URLCacheContainer_CloseIndex (Internal)
455 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
457 CloseHandle(pContainer->hMapping);
458 pContainer->hMapping = NULL;
461 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
463 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
464 int path_len = strlenW(path);
465 int cache_prefix_len = strlenW(cache_prefix);
472 pContainer->hMapping = NULL;
473 pContainer->file_size = 0;
475 pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR));
476 if (!pContainer->path)
478 HeapFree(GetProcessHeap(), 0, pContainer);
482 memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR));
484 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
485 if (!pContainer->cache_prefix)
487 HeapFree(GetProcessHeap(), 0, pContainer->path);
488 HeapFree(GetProcessHeap(), 0, pContainer);
492 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
494 CharLowerW(mutex_name);
495 URLCache_PathToObjectName(mutex_name, '!');
497 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
499 ERR("couldn't create mutex (error is %ld)\n", GetLastError());
500 HeapFree(GetProcessHeap(), 0, pContainer->path);
501 HeapFree(GetProcessHeap(), 0, pContainer);
505 list_add_head(&UrlContainers, &pContainer->entry);
510 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
512 list_remove(&pContainer->entry);
514 URLCacheContainer_CloseIndex(pContainer);
515 CloseHandle(pContainer->hMutex);
516 HeapFree(GetProcessHeap(), 0, pContainer->path);
517 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
518 HeapFree(GetProcessHeap(), 0, pContainer);
521 void URLCacheContainers_CreateDefaults(void)
523 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
524 static const WCHAR UrlPrefix[] = {0};
525 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
526 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
527 static const WCHAR CookieSuffix[] = {0};
528 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
531 int nFolder; /* CSIDL_* constant */
532 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
533 const WCHAR * cache_prefix; /* prefix used to reference the container */
534 } DefaultContainerData[] =
536 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
537 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
538 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
542 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
544 WCHAR wszCachePath[MAX_PATH];
545 WCHAR wszMutexName[MAX_PATH];
546 int path_len, suffix_len;
548 if (FAILED(SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE)))
550 ERR("Couldn't get path for default container %lu\n", i);
553 path_len = strlenW(wszCachePath);
554 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
556 if (path_len + suffix_len + 2 > MAX_PATH)
558 ERR("Path too long\n");
562 wszCachePath[path_len] = '\\';
563 wszCachePath[path_len+1] = 0;
565 strcpyW(wszMutexName, wszCachePath);
569 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
570 wszCachePath[path_len + suffix_len + 1] = '\\';
571 wszCachePath[path_len + suffix_len + 2] = '\0';
574 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
578 void URLCacheContainers_DeleteAll(void)
580 while(!list_empty(&UrlContainers))
581 URLCacheContainer_DeleteContainer(
582 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
586 static BOOL URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
588 struct list * cursor;
590 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
592 LIST_FOR_EACH(cursor, &UrlContainers)
594 URLCACHECONTAINER * pContainer = LIST_ENTRY(cursor, URLCACHECONTAINER, entry);
595 int prefix_len = strlenW(pContainer->cache_prefix);
596 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
598 TRACE("found container with prefx %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
599 *ppContainer = pContainer;
603 ERR("no container found\n");
604 SetLastError(ERROR_FILE_NOT_FOUND);
608 static BOOL URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
612 int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
613 if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR))))
615 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len);
616 ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer);
617 HeapFree(GetProcessHeap(), 0, lpwszUrl);
623 /***********************************************************************
624 * URLCacheContainer_LockIndex (Internal)
627 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
631 URLCACHE_HEADER * pHeader;
634 WaitForSingleObject(pContainer->hMutex, INFINITE);
636 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
640 ReleaseMutex(pContainer->hMutex);
641 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
644 pHeader = (URLCACHE_HEADER *)pIndexData;
646 /* file has grown - we need to remap to prevent us getting
647 * access violations when we try and access beyond the end
648 * of the memory mapped file */
649 if (pHeader->dwFileSize != pContainer->file_size)
651 URLCacheContainer_CloseIndex(pContainer);
652 if (!URLCacheContainer_OpenIndex(pContainer))
654 ReleaseMutex(pContainer->hMutex);
657 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
661 ReleaseMutex(pContainer->hMutex);
662 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
665 pHeader = (URLCACHE_HEADER *)pIndexData;
668 TRACE("Signature: %s, file size: %ld bytes\n", pHeader->szSignature, pHeader->dwFileSize);
670 for (index = 0; index < pHeader->DirectoryCount; index++)
672 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
678 /***********************************************************************
679 * URLCacheContainer_UnlockIndex (Internal)
682 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
685 ReleaseMutex(pContainer->hMutex);
686 return UnmapViewOfFile(pHeader);
691 #define CHAR_BIT (8 * sizeof(CHAR))
694 /***********************************************************************
695 * URLCache_Allocation_BlockIsFree (Internal)
697 * Is the specified block number free?
704 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
706 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
707 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
710 /***********************************************************************
711 * URLCache_Allocation_BlockFree (Internal)
713 * Marks the specified block as free
719 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
721 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
722 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
725 /***********************************************************************
726 * URLCache_Allocation_BlockAllocate (Internal)
728 * Marks the specified block as allocated
734 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
736 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
737 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
740 /***********************************************************************
741 * URLCache_FindFirstFreeEntry (Internal)
743 * Finds and allocates the first block of free space big enough and
744 * sets ppEntry to point to it.
747 * TRUE if it had enough space
748 * FALSE if it couldn't find enough space
751 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
753 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
756 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
758 for (dwFreeCounter = 0;
759 dwFreeCounter < dwBlocksNeeded &&
760 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
761 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
763 TRACE("Found free block at no. %ld (0x%lx)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
765 if (dwFreeCounter == dwBlocksNeeded)
768 TRACE("Found free blocks starting at no. %ld (0x%lx)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
769 for (index = 0; index < dwBlocksNeeded; index++)
770 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
771 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
772 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
776 FIXME("Grow file\n");
780 /***********************************************************************
781 * URLCache_DeleteEntry (Internal)
783 * Deletes the specified entry and frees the space allocated to it
786 * TRUE if it succeeded
790 static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, CACHEFILE_ENTRY * pEntry)
794 BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
796 /* update allocation table */
797 dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE;
798 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
799 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
801 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
805 /***********************************************************************
806 * URLCache_LocalFileNameToPathW (Internal)
808 * Copies the full path to the specified buffer given the local file
809 * name and the index of the directory it is in. Always sets value in
810 * lpBufferSize to the required buffer size (in bytes).
813 * TRUE if the buffer was big enough
814 * FALSE if the buffer was too small
817 static BOOL URLCache_LocalFileNameToPathW(
818 const URLCACHECONTAINER * pContainer,
819 LPCURLCACHE_HEADER pHeader,
820 LPCSTR szLocalFileName,
826 int path_len = strlenW(pContainer->path);
827 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
828 if (Directory >= pHeader->DirectoryCount)
834 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
835 if (nRequired < *lpBufferSize)
839 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
840 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
841 wszPath[dir_len + path_len] = '\\';
842 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
843 *lpBufferSize = nRequired;
846 *lpBufferSize = nRequired;
850 /***********************************************************************
851 * URLCache_LocalFileNameToPathA (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.
858 * TRUE if the buffer was big enough
859 * FALSE if the buffer was too small
862 static BOOL URLCache_LocalFileNameToPathA(
863 const URLCACHECONTAINER * pContainer,
864 LPCURLCACHE_HEADER pHeader,
865 LPCSTR szLocalFileName,
871 int path_len, file_name_len, dir_len;
873 if (Directory >= pHeader->DirectoryCount)
879 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL);
880 file_name_len = strlen(szLocalFileName);
881 dir_len = DIR_LENGTH;
883 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(WCHAR);
884 if (nRequired < *lpBufferSize)
886 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, -1, NULL, NULL);
887 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
888 szPath[path_len + dir_len] = '\\';
889 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
890 *lpBufferSize = nRequired;
893 *lpBufferSize = nRequired;
897 /***********************************************************************
898 * URLCache_CopyEntry (Internal)
900 * Copies an entry from the cache index file to the Win32 structure
903 * TRUE if the buffer was big enough
904 * FALSE if the buffer was too small
907 static BOOL URLCache_CopyEntry(
908 URLCACHECONTAINER * pContainer,
909 LPCURLCACHE_HEADER pHeader,
910 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
911 LPDWORD lpdwBufferSize,
912 URL_CACHEFILE_ENTRY * pUrlEntry,
916 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
918 if (*lpdwBufferSize >= dwRequiredSize)
920 lpCacheEntryInfo->lpHeaderInfo = NULL;
921 lpCacheEntryInfo->lpszFileExtension = NULL;
922 lpCacheEntryInfo->lpszLocalFileName = NULL;
923 lpCacheEntryInfo->lpszSourceUrlName = NULL;
924 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
925 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
926 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
927 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
928 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
929 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
930 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
931 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
932 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
933 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
934 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
935 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
936 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
937 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
940 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
941 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
942 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
944 lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0);
946 lenUrl = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
947 dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
949 /* FIXME: is source url optional? */
950 if (*lpdwBufferSize >= dwRequiredSize)
952 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrl - 1;
954 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
956 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, (lenUrl + 1) * sizeof(CHAR));
959 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
960 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
961 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
963 if (pUrlEntry->dwOffsetLocalName)
965 LONG nLocalFilePathSize;
966 LPSTR lpszLocalFileName;
967 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
968 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
969 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
970 URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize))
972 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
974 dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ;
976 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
977 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
978 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
980 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
982 if (*lpdwBufferSize >= dwRequiredSize)
984 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
985 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
986 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
988 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
989 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
990 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
992 if (dwRequiredSize > *lpdwBufferSize)
994 *lpdwBufferSize = dwRequiredSize;
995 SetLastError(ERROR_INSUFFICIENT_BUFFER);
998 *lpdwBufferSize = dwRequiredSize;
1003 /***********************************************************************
1004 * URLCache_SetEntryInfo (Internal)
1006 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1007 * according the the flags set by dwFieldControl.
1010 * TRUE if the buffer was big enough
1011 * FALSE if the buffer was too small
1014 static BOOL URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1016 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1017 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1018 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1019 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1020 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1021 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1022 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1023 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1024 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1025 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1026 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1027 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1028 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1029 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1030 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1031 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1036 /***********************************************************************
1037 * URLCache_HashKey (Internal)
1039 * Returns the hash key for a given string
1042 * hash key for the string
1045 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1047 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1048 * but the algorithm and result are not the same!
1050 static const unsigned char lookupTable[256] =
1052 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1053 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1054 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1055 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1056 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1057 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1058 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1059 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1060 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1061 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1062 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1063 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1064 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1065 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1066 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1067 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1068 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1069 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1070 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1071 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1072 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1073 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1074 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1075 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1076 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1077 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1078 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1079 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1080 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1081 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1082 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1083 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1087 int subscript[sizeof(key) / sizeof(key[0])];
1089 subscript[0] = *lpszKey;
1090 subscript[1] = (char)(*lpszKey + 1);
1091 subscript[2] = (char)(*lpszKey + 2);
1092 subscript[3] = (char)(*lpszKey + 3);
1094 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1095 key[i] = lookupTable[i];
1097 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
1099 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1100 key[i] = lookupTable[*lpszKey ^ key[i]];
1103 return *(DWORD *)key;
1106 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
1108 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
1111 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1113 /* structure of hash table:
1114 * 448 entries divided into 64 blocks
1115 * each block therefore contains a chain of 7 key/offset pairs
1116 * how position in table is calculated:
1117 * 1. the url is hashed in helper function
1118 * 2. the key % 64 * 8 is the offset
1119 * 3. the key in the hash table is the hash key aligned to 64
1122 * there can be multiple hash tables in the file and the offset to
1123 * the next one is stored in the header of the hash table
1125 DWORD key = URLCache_HashKey(lpszUrl);
1126 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1127 HASH_CACHEFILE_ENTRY * pHashEntry;
1128 DWORD dwHashTableNumber = 0;
1130 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1132 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1133 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1134 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1137 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1139 ERR("Error: not right hash table number (%ld) expected %ld\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1142 /* make sure that it is in fact a hash entry */
1143 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1145 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1149 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1151 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1152 if (key == (DWORD)(pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
1154 /* FIXME: we should make sure that this is the right element
1155 * before returning and claiming that it is. We can do this
1156 * by doing a simple compare between the URL we were given
1157 * and the URL stored in the entry. However, this assumes
1158 * we know the format of all the entries stored in the
1160 *ppHashEntry = pHashElement;
1168 /***********************************************************************
1169 * URLCache_FindEntryInHash (Internal)
1171 * Searches all the hash tables in the index for the given URL and
1172 * returns the entry, if it was found, in ppEntry
1175 * TRUE if the entry was found
1176 * FALSE if the entry could not be found
1179 static BOOL URLCache_FindEntryInHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, CACHEFILE_ENTRY ** ppEntry)
1181 struct _HASH_ENTRY * pHashEntry;
1182 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1184 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1190 /***********************************************************************
1191 * URLCache_HashEntrySetUse (Internal)
1193 * Searches all the hash tables in the index for the given URL and
1194 * sets the use count (stored or'ed with key)
1197 * TRUE if the entry was found
1198 * FALSE if the entry could not be found
1201 static BOOL URLCache_HashEntrySetUse(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwUseCount)
1203 struct _HASH_ENTRY * pHashEntry;
1204 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1206 pHashEntry->dwHashKey = dwUseCount | (DWORD)(pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1212 /***********************************************************************
1213 * URLCache_DeleteEntryFromHash (Internal)
1215 * Searches all the hash tables in the index for the given URL and
1216 * then if found deletes the entry.
1219 * TRUE if the entry was found
1220 * FALSE if the entry could not be found
1223 static BOOL URLCache_DeleteEntryFromHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl)
1225 struct _HASH_ENTRY * pHashEntry;
1226 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1228 pHashEntry->dwHashKey = HASHTABLE_FREE;
1229 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1235 /***********************************************************************
1236 * URLCache_AddEntryToHash (Internal)
1238 * Searches all the hash tables for a free slot based on the offset
1239 * generated from the hash key. If a free slot is found, the offset and
1240 * key are entered into the hash table.
1243 * TRUE if the entry was added
1244 * FALSE if the entry could not be added
1247 static BOOL URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1249 /* see URLCache_FindEntryInHash for structure of hash tables */
1251 DWORD key = URLCache_HashKey(lpszUrl);
1252 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1253 HASH_CACHEFILE_ENTRY * pHashEntry;
1254 DWORD dwHashTableNumber = 0;
1256 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1258 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1259 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1260 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1263 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1265 ERR("not right hash table number (%ld) expected %ld\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1268 /* make sure that it is in fact a hash entry */
1269 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1271 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1275 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1277 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1278 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1280 pHashElement->dwHashKey = key;
1281 pHashElement->dwOffsetEntry = dwOffsetEntry;
1286 pHashEntry = URLCache_CreateHashTable(pHeader, pHashEntry);
1290 pHashEntry->HashTable[offset].dwHashKey = key;
1291 pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry;
1295 static HASH_CACHEFILE_ENTRY *URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash)
1297 HASH_CACHEFILE_ENTRY *pHash;
1301 if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)&pHash))
1303 FIXME("no free space for hash table\n");
1304 SetLastError(ERROR_DISK_FULL);
1308 dwOffset = (BYTE *)pHash - (BYTE *)pHeader;
1311 pPrevHash->dwAddressNext = dwOffset;
1313 pHeader->dwOffsetFirstHashTable = dwOffset;
1314 pHash->CacheFileEntry.dwSignature = HASH_SIGNATURE;
1315 pHash->CacheFileEntry.dwBlocksUsed = 0x20;
1316 pHash->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0;
1317 for (i = 0; i < HASHTABLE_SIZE; i++)
1319 pHash->HashTable[i].dwOffsetEntry = 0;
1320 pHash->HashTable[i].dwHashKey = HASHTABLE_FREE;
1325 /***********************************************************************
1326 * GetUrlCacheEntryInfoExA (WININET.@)
1329 BOOL WINAPI GetUrlCacheEntryInfoExA(
1331 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1332 LPDWORD lpdwCacheEntryInfoBufSize,
1334 LPDWORD lpdwReserved,
1338 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1339 debugstr_a(lpszUrl),
1341 lpdwCacheEntryInfoBufSize,
1347 if ((lpszReserved != NULL) ||
1348 (lpdwReserved != NULL) ||
1349 (lpReserved != NULL))
1351 ERR("Reserved value was not 0\n");
1352 SetLastError(ERROR_INVALID_PARAMETER);
1356 FIXME("Undocumented flag(s): %lx\n", dwFlags);
1357 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1360 /***********************************************************************
1361 * GetUrlCacheEntryInfoA (WININET.@)
1364 BOOL WINAPI GetUrlCacheEntryInfoA(
1365 IN LPCSTR lpszUrlName,
1366 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1367 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1370 LPURLCACHE_HEADER pHeader;
1371 CACHEFILE_ENTRY * pEntry;
1372 URL_CACHEFILE_ENTRY * pUrlEntry;
1373 URLCACHECONTAINER * pContainer;
1375 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1377 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1380 if (!URLCacheContainer_OpenIndex(pContainer))
1383 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1386 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1388 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1389 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1390 SetLastError(ERROR_FILE_NOT_FOUND);
1394 if (pEntry->dwSignature != URL_SIGNATURE)
1396 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1397 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1398 SetLastError(ERROR_FILE_NOT_FOUND);
1402 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1403 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1404 if (pUrlEntry->dwOffsetHeaderInfo)
1405 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1407 if (!URLCache_CopyEntry(
1411 lpdwCacheEntryInfoBufferSize,
1415 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1418 TRACE("Local File Name: %s\n", debugstr_a(lpCacheEntryInfo->lpszLocalFileName));
1420 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1425 /***********************************************************************
1426 * GetUrlCacheEntryInfoW (WININET.@)
1429 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1430 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1431 LPDWORD lpdwCacheEntryInfoBufferSize)
1433 LPURLCACHE_HEADER pHeader;
1434 CACHEFILE_ENTRY * pEntry;
1435 URL_CACHEFILE_ENTRY * pUrlEntry;
1436 URLCACHECONTAINER * pContainer;
1440 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1442 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1443 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1446 SetLastError(ERROR_OUTOFMEMORY);
1449 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1451 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1453 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1457 if (!URLCacheContainer_OpenIndex(pContainer))
1459 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1463 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1465 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1469 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1471 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1472 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1473 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1474 SetLastError(ERROR_FILE_NOT_FOUND);
1477 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1479 if (pEntry->dwSignature != URL_SIGNATURE)
1481 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1482 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1483 SetLastError(ERROR_FILE_NOT_FOUND);
1487 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1488 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1489 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1491 if (!URLCache_CopyEntry(
1494 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1495 lpdwCacheEntryInfoBufferSize,
1497 TRUE /* UNICODE */))
1499 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1502 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1504 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1509 /***********************************************************************
1510 * GetUrlCacheEntryInfoExW (WININET.@)
1513 BOOL WINAPI GetUrlCacheEntryInfoExW(
1515 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1516 LPDWORD lpdwCacheEntryInfoBufSize,
1517 LPWSTR lpszReserved,
1518 LPDWORD lpdwReserved,
1522 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1523 debugstr_w(lpszUrl),
1525 lpdwCacheEntryInfoBufSize,
1531 if ((lpszReserved != NULL) ||
1532 (lpdwReserved != NULL) ||
1533 (lpReserved != NULL))
1535 ERR("Reserved value was not 0\n");
1536 SetLastError(ERROR_INVALID_PARAMETER);
1540 FIXME("Undocumented flag(s): %lx\n", dwFlags);
1541 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1544 /***********************************************************************
1545 * SetUrlCacheEntryInfoA (WININET.@)
1547 BOOL WINAPI SetUrlCacheEntryInfoA(
1549 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1550 DWORD dwFieldControl)
1552 LPURLCACHE_HEADER pHeader;
1553 CACHEFILE_ENTRY * pEntry;
1554 URLCACHECONTAINER * pContainer;
1556 TRACE("(%s, %p, 0x%08lx)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1558 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1561 if (!URLCacheContainer_OpenIndex(pContainer))
1564 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1567 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1569 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1570 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1571 SetLastError(ERROR_FILE_NOT_FOUND);
1575 if (pEntry->dwSignature != URL_SIGNATURE)
1577 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1578 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1579 SetLastError(ERROR_FILE_NOT_FOUND);
1583 URLCache_SetEntryInfo(
1584 (URL_CACHEFILE_ENTRY *)pEntry,
1585 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1588 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1593 /***********************************************************************
1594 * SetUrlCacheEntryInfoW (WININET.@)
1596 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1598 LPURLCACHE_HEADER pHeader;
1599 CACHEFILE_ENTRY * pEntry;
1600 URLCACHECONTAINER * pContainer;
1604 TRACE("(%s, %p, 0x%08lx)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1606 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1607 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1610 SetLastError(ERROR_OUTOFMEMORY);
1613 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1615 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1617 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1621 if (!URLCacheContainer_OpenIndex(pContainer))
1623 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1627 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1629 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1633 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1635 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1636 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1637 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1638 SetLastError(ERROR_FILE_NOT_FOUND);
1641 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1643 if (pEntry->dwSignature != URL_SIGNATURE)
1645 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1646 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1647 SetLastError(ERROR_FILE_NOT_FOUND);
1651 URLCache_SetEntryInfo(
1652 (URL_CACHEFILE_ENTRY *)pEntry,
1656 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1661 /***********************************************************************
1662 * RetrieveUrlCacheEntryFileA (WININET.@)
1665 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1666 IN LPCSTR lpszUrlName,
1667 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1668 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1672 LPURLCACHE_HEADER pHeader;
1673 CACHEFILE_ENTRY * pEntry;
1674 URL_CACHEFILE_ENTRY * pUrlEntry;
1675 URLCACHECONTAINER * pContainer;
1677 TRACE("(%s, %p, %p, 0x%08lx)\n",
1678 debugstr_a(lpszUrlName),
1680 lpdwCacheEntryInfoBufferSize,
1683 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1686 if (!URLCacheContainer_OpenIndex(pContainer))
1689 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1692 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1694 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1695 TRACE("entry %s not found!\n", lpszUrlName);
1696 SetLastError(ERROR_FILE_NOT_FOUND);
1700 if (pEntry->dwSignature != URL_SIGNATURE)
1702 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1703 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1704 SetLastError(ERROR_FILE_NOT_FOUND);
1708 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1709 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1710 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1712 pUrlEntry->dwHitRate++;
1713 pUrlEntry->dwUseCount++;
1714 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1716 if (!URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize, pUrlEntry, FALSE))
1718 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1721 TRACE("Local File Name: %s\n", lpCacheEntryInfo->lpszLocalFileName);
1723 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1728 /***********************************************************************
1729 * RetrieveUrlCacheEntryFileW (WININET.@)
1732 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1733 IN LPCWSTR lpszUrlName,
1734 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1735 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1739 TRACE("(%s, %p, %p, 0x%08lx)\n",
1740 debugstr_w(lpszUrlName),
1742 lpdwCacheEntryInfoBufferSize,
1748 /***********************************************************************
1749 * UnlockUrlCacheEntryFileA (WININET.@)
1752 BOOL WINAPI UnlockUrlCacheEntryFileA(
1753 IN LPCSTR lpszUrlName,
1757 LPURLCACHE_HEADER pHeader;
1758 CACHEFILE_ENTRY * pEntry;
1759 URL_CACHEFILE_ENTRY * pUrlEntry;
1760 URLCACHECONTAINER * pContainer;
1762 TRACE("(%s, 0x%08lx)\n", debugstr_a(lpszUrlName), dwReserved);
1766 ERR("dwReserved != 0\n");
1767 SetLastError(ERROR_INVALID_PARAMETER);
1771 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1774 if (!URLCacheContainer_OpenIndex(pContainer))
1777 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1780 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1782 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1783 TRACE("entry %s not found!\n", lpszUrlName);
1784 SetLastError(ERROR_FILE_NOT_FOUND);
1788 if (pEntry->dwSignature != URL_SIGNATURE)
1790 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1791 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1792 SetLastError(ERROR_FILE_NOT_FOUND);
1796 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1798 if (pUrlEntry->dwUseCount == 0)
1800 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1803 pUrlEntry->dwUseCount--;
1804 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1806 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1811 /***********************************************************************
1812 * UnlockUrlCacheEntryFileW (WININET.@)
1815 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
1817 FIXME("(%s, 0x%08lx)\n", debugstr_w(lpszUrlName), dwReserved);
1821 /***********************************************************************
1822 * CreateUrlCacheEntryA (WININET.@)
1825 BOOL WINAPI CreateUrlCacheEntryA(
1826 IN LPCSTR lpszUrlName,
1827 IN DWORD dwExpectedFileSize,
1828 IN LPCSTR lpszFileExtension,
1829 OUT LPSTR lpszFileName,
1835 WCHAR *file_extension;
1836 WCHAR file_name[MAX_PATH];
1837 BOOL bSuccess = FALSE;
1840 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
1841 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
1843 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
1844 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 &&
1845 (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
1847 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
1848 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
1850 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
1856 dwError = GetLastError();
1861 dwError = GetLastError();
1863 HeapFree(GetProcessHeap(), 0, file_extension);
1867 dwError = GetLastError();
1869 HeapFree(GetProcessHeap(), 0, url_name);
1871 SetLastError(dwError);
1875 /***********************************************************************
1876 * CreateUrlCacheEntryW (WININET.@)
1879 BOOL WINAPI CreateUrlCacheEntryW(
1880 IN LPCWSTR lpszUrlName,
1881 IN DWORD dwExpectedFileSize,
1882 IN LPCWSTR lpszFileExtension,
1883 OUT LPWSTR lpszFileName,
1887 URLCACHECONTAINER * pContainer;
1888 LPURLCACHE_HEADER pHeader;
1889 CHAR szFile[MAX_PATH];
1890 WCHAR szExtension[MAX_PATH];
1891 LPCWSTR lpszUrlPart;
1893 LPCWSTR lpszFileNameExtension;
1894 LPWSTR lpszFileNameNoPath;
1896 int countnoextension;
1899 BOOL bFound = FALSE;
1901 static const WCHAR szWWW[] = {'w','w','w',0};
1903 TRACE("(%s, 0x%08lx, %s, %p, 0x%08lx)\n",
1904 debugstr_w(lpszUrlName),
1906 debugstr_w(lpszFileExtension),
1912 ERR("dwReserved != 0\n");
1913 SetLastError(ERROR_INVALID_PARAMETER);
1917 for (lpszUrlEnd = lpszUrlName; *lpszUrlEnd; lpszUrlEnd++)
1920 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
1923 for (lpszUrlPart = lpszUrlEnd;
1924 (lpszUrlPart >= lpszUrlName);
1927 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
1934 if (!lstrcmpW(lpszUrlPart, szWWW))
1936 lpszUrlPart += lstrlenW(szWWW);
1939 count = lpszUrlEnd - lpszUrlPart;
1941 if (bFound && (count < MAX_PATH))
1943 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
1947 /* FIXME: get rid of illegal characters like \, / and : */
1951 FIXME("need to generate a random filename\n");
1954 TRACE("File name: %s\n", debugstr_a(szFile));
1956 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
1959 if (!URLCacheContainer_OpenIndex(pContainer))
1962 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1965 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
1967 lBufferSize = MAX_PATH * sizeof(WCHAR);
1968 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
1970 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1972 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
1973 lpszFileNameNoPath >= lpszFileName;
1974 --lpszFileNameNoPath)
1976 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
1980 countnoextension = lstrlenW(lpszFileNameNoPath);
1981 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
1982 if (lpszFileNameExtension)
1983 countnoextension -= lstrlenW(lpszFileNameExtension);
1984 *szExtension = '\0';
1986 if (lpszFileExtension)
1988 szExtension[0] = '.';
1989 lstrcpyW(szExtension+1, lpszFileExtension);
1992 for (i = 0; i < 255; i++)
1994 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
1996 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
1997 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
1998 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
1999 if (hFile != INVALID_HANDLE_VALUE)
2010 /***********************************************************************
2011 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2013 * The bug we are compensating for is that some drongo at Microsoft
2014 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2015 * As a consequence, CommitUrlCacheEntryA has been effectively
2016 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2017 * is still defined as LPCWSTR. The result (other than madness) is
2018 * that we always need to store lpHeaderInfo in CP_ACP rather than
2019 * in UTF16, and we need to avoid converting lpHeaderInfo in
2020 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2021 * result will lose data for arbitrary binary data.
2024 static BOOL WINAPI CommitUrlCacheEntryInternal(
2025 IN LPCWSTR lpszUrlName,
2026 IN LPCWSTR lpszLocalFileName,
2027 IN FILETIME ExpireTime,
2028 IN FILETIME LastModifiedTime,
2029 IN DWORD CacheEntryType,
2030 IN LPBYTE lpHeaderInfo,
2031 IN DWORD dwHeaderSize,
2032 IN LPCWSTR lpszFileExtension,
2033 IN LPCWSTR lpszOriginalUrl
2036 URLCACHECONTAINER * pContainer;
2037 LPURLCACHE_HEADER pHeader;
2038 CACHEFILE_ENTRY * pEntry;
2039 URL_CACHEFILE_ENTRY * pUrlEntry;
2040 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2041 DWORD dwOffsetLocalFileName = 0;
2042 DWORD dwOffsetHeader = 0;
2043 DWORD dwFileSizeLow = 0;
2044 DWORD dwFileSizeHigh = 0;
2045 BYTE cDirectory = 0;
2046 char achFile[MAX_PATH];
2047 char achUrl[MAX_PATH];
2048 char *pchLocalFileName = 0;
2050 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %s)\n",
2051 debugstr_w(lpszUrlName),
2052 debugstr_w(lpszLocalFileName),
2056 debugstr_w(lpszFileExtension),
2057 debugstr_w(lpszOriginalUrl));
2059 if (lpszOriginalUrl)
2060 WARN(": lpszOriginalUrl ignored\n");
2062 if (lpszLocalFileName)
2066 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2067 if (hFile == INVALID_HANDLE_VALUE)
2069 ERR("couldn't open file %s (error is %ld)\n", debugstr_w(lpszLocalFileName), GetLastError());
2074 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2075 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2077 ERR("couldn't get file size (error is %ld)\n", GetLastError());
2085 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
2088 if (!URLCacheContainer_OpenIndex(pContainer))
2091 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2094 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, achUrl, -1, NULL, NULL);
2096 if (URLCache_FindEntryInHash(pHeader, achUrl, &pEntry))
2098 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2099 FIXME("entry already in cache - don't know what to do!\n");
2101 * SetLastError(ERROR_FILE_NOT_FOUND);
2107 if (lpszLocalFileName)
2109 BOOL bFound = FALSE;
2111 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2113 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2114 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2115 SetLastError(ERROR_INVALID_PARAMETER);
2119 /* skip container path prefix */
2120 lpszLocalFileName += lstrlenW(pContainer->path);
2122 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, -1, NULL, NULL);
2123 pchLocalFileName = achFile;
2125 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2127 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2136 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2137 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2138 SetLastError(ERROR_INVALID_PARAMETER);
2142 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2145 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(achUrl) + 1);
2146 if (lpszLocalFileName)
2148 dwOffsetLocalFileName = dwBytesNeeded;
2149 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2153 dwOffsetHeader = dwBytesNeeded;
2154 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2157 /* round up to next block */
2158 if (dwBytesNeeded % BLOCKSIZE)
2160 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2161 dwBytesNeeded += BLOCKSIZE;
2164 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2166 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2167 ERR("no free entries\n");
2168 SetLastError(ERROR_DISK_FULL);
2172 /* FindFirstFreeEntry fills in blocks used */
2173 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2174 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2175 pUrlEntry->CacheDir = cDirectory;
2176 pUrlEntry->CacheEntryType = CacheEntryType;
2177 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2178 pUrlEntry->dwExemptDelta = 0;
2179 pUrlEntry->dwHitRate = 0;
2180 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2181 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2182 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2183 pUrlEntry->dwSizeHigh = 0;
2184 pUrlEntry->dwSizeLow = dwFileSizeLow;
2185 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2186 pUrlEntry->dwUseCount = 0;
2187 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2188 pUrlEntry->LastModifiedTime = LastModifiedTime;
2189 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2190 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2191 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2192 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2195 pUrlEntry->dwUnknown1 = 0;
2196 pUrlEntry->dwUnknown2 = 0;
2197 pUrlEntry->dwUnknown3 = 0x60;
2198 pUrlEntry->Unknown4 = 0;
2199 pUrlEntry->wUnknown5 = 0x1010;
2200 pUrlEntry->dwUnknown6 = 0;
2201 pUrlEntry->dwUnknown7 = 0;
2202 pUrlEntry->dwUnknown8 = 0;
2205 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, achUrl);
2206 if (dwOffsetLocalFileName)
2207 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2209 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2211 if (!URLCache_AddEntryToHash(pHeader, achUrl, (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader)))
2213 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2214 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2218 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2223 /***********************************************************************
2224 * CommitUrlCacheEntryA (WININET.@)
2227 BOOL WINAPI CommitUrlCacheEntryA(
2228 IN LPCSTR lpszUrlName,
2229 IN LPCSTR lpszLocalFileName,
2230 IN FILETIME ExpireTime,
2231 IN FILETIME LastModifiedTime,
2232 IN DWORD CacheEntryType,
2233 IN LPBYTE lpHeaderInfo,
2234 IN DWORD dwHeaderSize,
2235 IN LPCSTR lpszFileExtension,
2236 IN LPCSTR lpszOriginalUrl
2241 WCHAR *local_file_name;
2242 WCHAR *original_url = NULL;
2243 BOOL bSuccess = FALSE;
2246 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %s)\n",
2247 debugstr_a(lpszUrlName),
2248 debugstr_a(lpszLocalFileName),
2252 debugstr_a(lpszFileExtension),
2253 debugstr_a(lpszOriginalUrl));
2255 if (lpszFileExtension != 0)
2257 SetLastError(ERROR_INVALID_PARAMETER);
2260 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
2261 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2263 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2264 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0)) != 0 &&
2265 (local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2267 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2268 if (!lpszOriginalUrl ||
2269 ((len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0)) != 0 &&
2270 (original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0))
2273 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2274 if (CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2275 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2276 NULL, original_url))
2282 dwError = GetLastError();
2284 HeapFree(GetProcessHeap(), 0, original_url);
2288 dwError = GetLastError();
2290 HeapFree(GetProcessHeap(), 0, local_file_name);
2294 dwError = GetLastError();
2296 HeapFree(GetProcessHeap(), 0, url_name);
2298 SetLastError(dwError);
2303 /***********************************************************************
2304 * CommitUrlCacheEntryW (WININET.@)
2307 BOOL WINAPI CommitUrlCacheEntryW(
2308 IN LPCWSTR lpszUrlName,
2309 IN LPCWSTR lpszLocalFileName,
2310 IN FILETIME ExpireTime,
2311 IN FILETIME LastModifiedTime,
2312 IN DWORD CacheEntryType,
2313 IN LPWSTR lpHeaderInfo,
2314 IN DWORD dwHeaderSize,
2315 IN LPCWSTR lpszFileExtension,
2316 IN LPCWSTR lpszOriginalUrl
2320 BOOL bSuccess = FALSE;
2322 CHAR *header_info = NULL;
2324 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %s)\n",
2325 debugstr_w(lpszUrlName),
2326 debugstr_w(lpszLocalFileName),
2330 debugstr_w(lpszFileExtension),
2331 debugstr_w(lpszOriginalUrl));
2333 if (!lpHeaderInfo ||
2334 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2335 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2338 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2339 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2340 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2346 dwError = GetLastError();
2350 HeapFree(GetProcessHeap(), 0, header_info);
2352 SetLastError(dwError);
2358 /***********************************************************************
2359 * ReadUrlCacheEntryStream (WININET.@)
2362 BOOL WINAPI ReadUrlCacheEntryStream(
2363 IN HANDLE hUrlCacheStream,
2364 IN DWORD dwLocation,
2365 IN OUT LPVOID lpBuffer,
2366 IN OUT LPDWORD lpdwLen,
2370 /* Get handle to file from 'stream' */
2371 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2373 if (dwReserved != 0)
2375 ERR("dwReserved != 0\n");
2376 SetLastError(ERROR_INVALID_PARAMETER);
2380 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2382 SetLastError(ERROR_INVALID_HANDLE);
2386 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2388 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2391 /***********************************************************************
2392 * RetrieveUrlCacheEntryStreamA (WININET.@)
2395 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2396 IN LPCSTR lpszUrlName,
2397 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2398 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2399 IN BOOL fRandomRead,
2403 /* NOTE: this is not the same as the way that the native
2404 * version allocates 'stream' handles. I did it this way
2405 * as it is much easier and no applications should depend
2406 * on this behaviour. (Native version appears to allocate
2407 * indices into a table)
2409 STREAM_HANDLE * pStream;
2412 TRACE( "(%s, %p, %p, %x, 0x%08lx)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2413 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2415 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2417 lpdwCacheEntryInfoBufferSize,
2423 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2428 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2430 if (hFile == INVALID_HANDLE_VALUE)
2433 /* allocate handle storage space */
2434 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2438 SetLastError(ERROR_OUTOFMEMORY);
2442 pStream->hFile = hFile;
2443 strcpy(pStream->lpszUrl, lpszUrlName);
2444 return (HANDLE)pStream;
2447 /***********************************************************************
2448 * RetrieveUrlCacheEntryStreamW (WININET.@)
2451 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2452 IN LPCWSTR lpszUrlName,
2453 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2454 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2455 IN BOOL fRandomRead,
2459 FIXME( "(%s, %p, %p, %x, 0x%08lx)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2460 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2464 /***********************************************************************
2465 * UnlockUrlCacheEntryStream (WININET.@)
2468 BOOL WINAPI UnlockUrlCacheEntryStream(
2469 IN HANDLE hUrlCacheStream,
2473 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2475 if (dwReserved != 0)
2477 ERR("dwReserved != 0\n");
2478 SetLastError(ERROR_INVALID_PARAMETER);
2482 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2484 SetLastError(ERROR_INVALID_HANDLE);
2488 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2491 /* close file handle */
2492 CloseHandle(pStream->hFile);
2494 /* free allocated space */
2495 HeapFree(GetProcessHeap(), 0, pStream);
2501 /***********************************************************************
2502 * DeleteUrlCacheEntryA (WININET.@)
2505 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2507 URLCACHECONTAINER * pContainer;
2508 LPURLCACHE_HEADER pHeader;
2509 CACHEFILE_ENTRY * pEntry;
2511 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2513 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
2516 if (!URLCacheContainer_OpenIndex(pContainer))
2519 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2522 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
2524 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2525 TRACE("entry %s not found!\n", lpszUrlName);
2526 SetLastError(ERROR_FILE_NOT_FOUND);
2530 URLCache_DeleteEntry(pHeader, pEntry);
2532 URLCache_DeleteEntryFromHash(pHeader, lpszUrlName);
2534 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2539 /***********************************************************************
2540 * DeleteUrlCacheEntryW (WININET.@)
2543 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2545 FIXME("(%s) stub\n", debugstr_w(lpszUrlName));
2549 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2551 FIXME("(0x%08lx, 0x%08lx) stub\n", d1, d2);
2555 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2557 FIXME("(0x%08lx, 0x%08lx) stub\n", d1, d2);
2561 /***********************************************************************
2562 * CreateCacheContainerA (WININET.@)
2564 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2565 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2567 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) stub\n",
2568 d1, d2, d3, d4, d5, d6, d7, d8);
2572 /***********************************************************************
2573 * CreateCacheContainerW (WININET.@)
2575 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2576 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2578 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) stub\n",
2579 d1, d2, d3, d4, d5, d6, d7, d8);
2583 /***********************************************************************
2584 * FindCloseUrlCache (WININET.@)
2586 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
2588 FIXME("(%p) stub\n", hEnumHandle);
2592 /***********************************************************************
2593 * FindFirstUrlCacheContainerA (WININET.@)
2595 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2597 FIXME("(%p, %p, %p, 0x%08lx) stub\n", p1, p2, p3, d1 );
2601 /***********************************************************************
2602 * FindFirstUrlCacheContainerW (WININET.@)
2604 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2606 FIXME("(%p, %p, %p, 0x%08lx) stub\n", p1, p2, p3, d1 );
2610 /***********************************************************************
2611 * FindNextUrlCacheContainerA (WININET.@)
2613 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
2615 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2619 /***********************************************************************
2620 * FindNextUrlCacheContainerW (WININET.@)
2622 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
2624 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2628 HANDLE WINAPI FindFirstUrlCacheEntryExA(
2629 LPCSTR lpszUrlSearchPattern,
2633 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2634 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2636 LPDWORD pcbReserved2,
2640 FIXME("(%s, 0x%08lx, 0x%08lx, 0x%08lx%08lx, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
2641 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2642 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2643 SetLastError(ERROR_FILE_NOT_FOUND);
2647 HANDLE WINAPI FindFirstUrlCacheEntryExW(
2648 LPCWSTR lpszUrlSearchPattern,
2652 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2653 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2655 LPDWORD pcbReserved2,
2659 FIXME("(%s, 0x%08lx, 0x%08lx, 0x%08lx%08lx, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
2660 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2661 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2662 SetLastError(ERROR_FILE_NOT_FOUND);
2666 /***********************************************************************
2667 * FindFirstUrlCacheEntryA (WININET.@)
2670 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
2671 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2673 FIXME("(%s, %p, %p): stub\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2674 SetLastError(ERROR_FILE_NOT_FOUND);
2678 /***********************************************************************
2679 * FindFirstUrlCacheEntryW (WININET.@)
2682 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
2683 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2685 FIXME("(%s, %p, %p): stub\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2689 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
2690 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
2692 FIXME("(0x%08lx, 0x%08lx, %p, 0x%08lx, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
2693 dwSearchCondition, lpGroupId, lpReserved);
2697 BOOL WINAPI FindNextUrlCacheEntryA(
2699 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
2700 LPDWORD lpdwNextCacheEntryInfoBufferSize
2703 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2707 BOOL WINAPI FindNextUrlCacheEntryW(
2709 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
2710 LPDWORD lpdwNextCacheEntryInfoBufferSize
2713 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2717 BOOL WINAPI FindNextUrlCacheEntryExA(
2719 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2720 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2722 LPDWORD pcbReserved2,
2726 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2727 lpReserved, pcbReserved2, lpReserved3);
2731 BOOL WINAPI FindNextUrlCacheEntryExW(
2733 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2734 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2736 LPDWORD pcbReserved2,
2740 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2741 lpReserved, pcbReserved2, lpReserved3);
2745 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
2747 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
2751 /***********************************************************************
2752 * CreateUrlCacheGroup (WININET.@)
2755 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
2757 FIXME("(0x%08lx, %p): stub\n", dwFlags, lpReserved);
2761 /***********************************************************************
2762 * DeleteUrlCacheGroup (WININET.@)
2765 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
2767 FIXME("(0x%08lx%08lx, 0x%08lx, %p) stub\n",
2768 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
2772 /***********************************************************************
2773 * SetUrlCacheEntryGroupA (WININET.@)
2776 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
2777 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2780 FIXME("(%s, 0x%08lx, 0x%08lx%08lx, %p, 0x%08lx, %p) stub\n",
2781 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2782 pbGroupAttributes, cbGroupAttributes, lpReserved);
2783 SetLastError(ERROR_FILE_NOT_FOUND);
2787 /***********************************************************************
2788 * SetUrlCacheEntryGroupW (WININET.@)
2791 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
2792 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2795 FIXME("(%s, 0x%08lx, 0x%08lx%08lx, %p, 0x%08lx, %p) stub\n",
2796 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2797 pbGroupAttributes, cbGroupAttributes, lpReserved);
2798 SetLastError(ERROR_FILE_NOT_FOUND);
2802 /***********************************************************************
2803 * GetUrlCacheConfigInfoW (WININET.@)
2805 BOOL WINAPI GetUrlCacheConfigInfoW(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2807 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2808 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2812 /***********************************************************************
2813 * GetUrlCacheConfigInfoA (WININET.@)
2815 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
2817 BOOL WINAPI GetUrlCacheConfigInfoA(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2819 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2820 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2824 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2825 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
2826 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2828 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p, %p) stub\n",
2829 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2830 lpdwGroupInfo, lpReserved);
2834 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2835 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
2836 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2838 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p, %p) stub\n",
2839 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2840 lpdwGroupInfo, lpReserved);
2844 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2845 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
2847 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p) stub\n",
2848 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2852 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2853 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
2855 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p) stub\n",
2856 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2860 BOOL WINAPI SetUrlCacheConfigInfoA( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2862 FIXME("(%p, 0x%08lx) stub\n", lpCacheConfigInfo, dwFieldControl);
2866 BOOL WINAPI SetUrlCacheConfigInfoW( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2868 FIXME("(%p, 0x%08lx) stub\n", lpCacheConfigInfo, dwFieldControl);
2872 /***********************************************************************
2873 * DeleteIE3Cache (WININET.@)
2875 * Deletes the files used by the IE3 URL caching system.
2878 * hWnd [I] A dummy window.
2879 * hInst [I] Instance of process calling the function.
2880 * lpszCmdLine [I] Options used by function.
2881 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
2886 void WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
2888 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);