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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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; /* usually 0x68 */
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 CHAR szSourceUrlName[1]; /* start of url */
116 /* packing to dword align start of next field */
117 /* CHAR szLocalFileName[]; (local file name exluding path) */
118 /* packing to dword align start of next field */
119 /* CHAR szHeaderInfo[]; (header info) */
120 } URL_CACHEFILE_ENTRY;
128 typedef struct _HASH_CACHEFILE_ENTRY
130 CACHEFILE_ENTRY CacheFileEntry;
132 DWORD dwHashTableNumber;
133 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
134 } HASH_CACHEFILE_ENTRY;
136 typedef struct _DIRECTORY_DATA
139 char filename[DIR_LENGTH];
142 typedef struct _URLCACHE_HEADER
144 char szSignature[28];
146 DWORD dwOffsetFirstHashTable;
147 DWORD dwIndexCapacityInBlocks;
150 DWORD dwCacheLimitLow; /* disk space limit for cache */
151 DWORD dwCacheLimitHigh; /* disk space limit for cache */
152 DWORD dwUnknown4; /* current disk space usage for cache */
153 DWORD dwUnknown5; /* current disk space usage for cache */
154 DWORD dwUnknown6; /* possibly a flag? */
156 BYTE DirectoryCount; /* number of directory_data's */
157 BYTE Unknown8[3]; /* just padding? */
158 DIRECTORY_DATA directory_data[1]; /* first directory entry */
159 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
160 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
162 typedef struct _STREAM_HANDLE
168 typedef struct _URLCACHECONTAINER
170 struct list entry; /* part of a list */
171 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
172 LPWSTR path; /* path to url container directory */
173 HANDLE hMapping; /* handle of file mapping */
174 DWORD file_size; /* size of file when mapping was opened */
175 HANDLE hMutex; /* hande of mutex */
179 /* List of all containers available */
180 static struct list UrlContainers = LIST_INIT(UrlContainers);
182 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry);
184 /***********************************************************************
185 * URLCache_PathToObjectName (Internal)
187 * Converts a path to a name suitable for use as a Win32 object name.
188 * Replaces '\\' characters in-place with the specified character
189 * (usually '_' or '!')
195 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
197 for (; *lpszPath; lpszPath++)
199 if (*lpszPath == '\\')
204 /***********************************************************************
205 * URLCacheContainer_OpenIndex (Internal)
207 * Opens the index file and saves mapping handle in hCacheIndexMapping
214 static BOOL URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
217 WCHAR wszFilePath[MAX_PATH];
220 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
221 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
223 if (pContainer->hMapping)
226 strcpyW(wszFilePath, pContainer->path);
227 strcatW(wszFilePath, wszIndex);
229 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
230 if (hFile == INVALID_HANDLE_VALUE)
232 /* Maybe the directory wasn't there? Try to create it */
233 if (CreateDirectoryW(pContainer->path, 0))
234 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
236 if (hFile == INVALID_HANDLE_VALUE)
238 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath));
242 /* At this stage we need the mutex because we may be about to create the
245 WaitForSingleObject(pContainer->hMutex, INFINITE);
247 dwFileSize = GetFileSize(hFile, NULL);
248 if (dwFileSize == INVALID_FILE_SIZE)
250 ReleaseMutex(pContainer->hMutex);
256 static CHAR const szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Cache\\Content";
258 char achZeroes[0x1000];
262 /* Write zeroes to the entire file so we can safely map it without
263 * fear of getting a SEGV because the disk is full.
265 memset(achZeroes, 0, sizeof(achZeroes));
266 for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes))
268 DWORD dwWrite = sizeof(achZeroes);
271 if (NEWFILE_SIZE - dwOffset < dwWrite)
272 dwWrite = NEWFILE_SIZE - dwOffset;
273 if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) ||
274 dwWritten != dwWrite)
276 /* If we fail to write, we need to return the error that
277 * cause the problem and also make sure the file is no
278 * longer there, if possible.
280 dwError = GetLastError();
288 HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL);
292 URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE);
297 WCHAR wszDirPath[MAX_PATH];
300 HASH_CACHEFILE_ENTRY *pPrevHash = 0;
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 /* Now create the hash table entries. Windows would create
332 * these as needed, but WINE doesn't do that yet, so create
333 * four and hope it's enough.
336 for (i = 0; i < 4; ++i)
338 HASH_CACHEFILE_ENTRY *pHash;
341 /* Request 0x20 blocks - no need to check for failure here because
342 * we started with an empty file
344 URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **) &pHash);
346 dwOffset = (BYTE *) pHash - (BYTE *) pHeader;
349 pPrevHash->dwAddressNext = dwOffset;
351 pHeader->dwOffsetFirstHashTable = dwOffset;
352 pHash->CacheFileEntry.dwSignature = HASH_SIGNATURE;
353 pHash->CacheFileEntry.dwBlocksUsed = 0x20;
354 pHash->dwHashTableNumber = i;
355 for (j = 0; j < HASHTABLE_SIZE; ++j)
357 pHash->HashTable[j].dwOffsetEntry = 0;
358 pHash->HashTable[j].dwHashKey = HASHTABLE_FREE;
363 /* Last step - create the directories */
365 strcpyW(wszDirPath, pContainer->path);
366 pwchDir = wszDirPath + strlenW(wszDirPath);
369 GetSystemTimeAsFileTime(&ft);
371 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
373 /* The following values were copied from a Windows index.
374 * I don't know what the values are supposed to mean but
375 * have made them the same in the hope that this will
376 * be better for compatibility
378 pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
382 ULONGLONG n = ft.dwHighDateTime;
384 /* Generate a file name to attempt to create.
385 * This algorithm will create what will appear
386 * to be random and unrelated directory names
387 * of up to 9 characters in length.
390 n += ft.dwLowDateTime;
391 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
393 for (k = 0; k < 8; ++k)
397 /* Dividing by a prime greater than 36 helps
398 * with the appearance of randomness
403 pwchDir[k] = '0' + r;
405 pwchDir[k] = 'A' + (r - 10);
408 if (CreateDirectoryW(wszDirPath, 0))
412 /* The following is OK because we generated an
413 * 8 character directory name made from characters
414 * [A-Z0-9], which are equivalent for all code
415 * pages and for UTF-16
417 for (k = 0; k < 8; ++k)
418 pHeader->directory_data[i].filename[k] = pwchDir[k];
423 /* Give up. The most likely cause of this
424 * is a full disk, but whatever the cause
425 * is, it should be more than apparent that
428 dwError = GetLastError();
434 UnmapViewOfFile(pHeader);
438 dwError = GetLastError();
440 CloseHandle(hMapping);
444 dwError = GetLastError();
451 DeleteFileW(wszFilePath);
452 ReleaseMutex(pContainer->hMutex);
453 SetLastError(dwError);
459 ReleaseMutex(pContainer->hMutex);
461 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
462 URLCache_PathToObjectName(wszFilePath, '_');
463 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
464 if (!pContainer->hMapping)
465 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
467 if (!pContainer->hMapping)
469 ERR("Couldn't create file mapping (error is %ld)\n", GetLastError());
476 /***********************************************************************
477 * URLCacheContainer_CloseIndex (Internal)
485 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
487 CloseHandle(pContainer->hMapping);
488 pContainer->hMapping = NULL;
491 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
493 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
494 int path_len = strlenW(path);
495 int cache_prefix_len = strlenW(cache_prefix);
502 pContainer->hMapping = NULL;
503 pContainer->file_size = 0;
505 pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR));
506 if (!pContainer->path)
508 HeapFree(GetProcessHeap(), 0, pContainer);
512 memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR));
514 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
515 if (!pContainer->cache_prefix)
517 HeapFree(GetProcessHeap(), 0, pContainer->path);
518 HeapFree(GetProcessHeap(), 0, pContainer);
522 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
524 CharLowerW(mutex_name);
525 URLCache_PathToObjectName(mutex_name, '!');
527 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
529 ERR("couldn't create mutex (error is %ld)\n", GetLastError());
530 HeapFree(GetProcessHeap(), 0, pContainer->path);
531 HeapFree(GetProcessHeap(), 0, pContainer);
535 list_add_head(&UrlContainers, &pContainer->entry);
540 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
542 list_remove(&pContainer->entry);
544 URLCacheContainer_CloseIndex(pContainer);
545 CloseHandle(pContainer->hMutex);
546 HeapFree(GetProcessHeap(), 0, pContainer->path);
547 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
548 HeapFree(GetProcessHeap(), 0, pContainer);
551 void URLCacheContainers_CreateDefaults(void)
553 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
554 static const WCHAR UrlPrefix[] = {0};
555 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
556 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
557 static const WCHAR CookieSuffix[] = {0};
558 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
561 int nFolder; /* CSIDL_* constant */
562 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
563 const WCHAR * cache_prefix; /* prefix used to reference the container */
564 } DefaultContainerData[] =
566 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
567 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
568 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
572 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
574 WCHAR wszCachePath[MAX_PATH];
575 WCHAR wszMutexName[MAX_PATH];
576 int path_len, suffix_len;
578 if (FAILED(SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE)))
580 ERR("Couldn't get path for default container %lu\n", i);
583 path_len = strlenW(wszCachePath);
584 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
586 if (path_len + suffix_len + 2 > MAX_PATH)
588 ERR("Path too long\n");
592 wszCachePath[path_len] = '\\';
594 strcpyW(wszMutexName, wszCachePath);
598 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
599 wszCachePath[path_len + suffix_len + 1] = '\\';
600 wszCachePath[path_len + suffix_len + 2] = '\0';
603 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
607 void URLCacheContainers_DeleteAll(void)
609 while(!list_empty(&UrlContainers))
610 URLCacheContainer_DeleteContainer(
611 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
615 static BOOL URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
617 struct list * cursor;
619 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
621 LIST_FOR_EACH(cursor, &UrlContainers)
623 URLCACHECONTAINER * pContainer = LIST_ENTRY(cursor, URLCACHECONTAINER, entry);
624 int prefix_len = strlenW(pContainer->cache_prefix);
625 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
627 TRACE("found container with prefx %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
628 *ppContainer = pContainer;
632 ERR("no container found\n");
633 SetLastError(ERROR_FILE_NOT_FOUND);
637 static BOOL URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
641 int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
642 if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR))))
644 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len);
645 ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer);
646 HeapFree(GetProcessHeap(), 0, lpwszUrl);
652 /***********************************************************************
653 * URLCacheContainer_LockIndex (Internal)
656 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
660 URLCACHE_HEADER * pHeader;
663 WaitForSingleObject(pContainer->hMutex, INFINITE);
665 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
669 ReleaseMutex(pContainer->hMutex);
670 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
673 pHeader = (URLCACHE_HEADER *)pIndexData;
675 /* file has grown - we need to remap to prevent us getting
676 * access violations when we try and access beyond the end
677 * of the memory mapped file */
678 if (pHeader->dwFileSize != pContainer->file_size)
680 URLCacheContainer_CloseIndex(pContainer);
681 if (!URLCacheContainer_OpenIndex(pContainer))
683 ReleaseMutex(pContainer->hMutex);
686 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
690 ReleaseMutex(pContainer->hMutex);
691 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
694 pHeader = (URLCACHE_HEADER *)pIndexData;
697 TRACE("Signature: %s, file size: %ld bytes\n", pHeader->szSignature, pHeader->dwFileSize);
699 for (index = 0; index < pHeader->DirectoryCount; index++)
701 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
707 /***********************************************************************
708 * URLCacheContainer_UnlockIndex (Internal)
711 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
714 ReleaseMutex(pContainer->hMutex);
715 return UnmapViewOfFile(pHeader);
720 #define CHAR_BIT (8 * sizeof(CHAR))
723 /***********************************************************************
724 * URLCache_Allocation_BlockIsFree (Internal)
726 * Is the specified block number free?
733 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
735 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
736 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
739 /***********************************************************************
740 * URLCache_Allocation_BlockFree (Internal)
742 * Marks the specified block as free
748 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
750 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
751 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
754 /***********************************************************************
755 * URLCache_Allocation_BlockAllocate (Internal)
757 * Marks the specified block as allocated
763 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
765 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
766 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
769 /***********************************************************************
770 * URLCache_FindFirstFreeEntry (Internal)
772 * Finds and allocates the first block of free space big enough and
773 * sets ppEntry to point to it.
776 * TRUE if it had enough space
777 * FALSE if it couldn't find enough space
780 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
782 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
785 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
787 for (dwFreeCounter = 0;
788 dwFreeCounter < dwBlocksNeeded &&
789 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
790 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
792 TRACE("Found free block at no. %ld (0x%lx)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
794 if (dwFreeCounter == dwBlocksNeeded)
797 TRACE("Found free blocks starting at no. %ld (0x%lx)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
798 for (index = 0; index < dwBlocksNeeded; index++)
799 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
800 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
801 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
805 FIXME("Grow file\n");
809 /***********************************************************************
810 * URLCache_DeleteEntry (Internal)
812 * Deletes the specified entry and frees the space allocated to it
815 * TRUE if it succeeded
819 static BOOL URLCache_DeleteEntry(CACHEFILE_ENTRY * pEntry)
821 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
825 /***********************************************************************
826 * URLCache_LocalFileNameToPathW (Internal)
828 * Copies the full path to the specified buffer given the local file
829 * name and the index of the directory it is in. Always sets value in
830 * lpBufferSize to the required buffer size (in bytes).
833 * TRUE if the buffer was big enough
834 * FALSE if the buffer was too small
837 static BOOL URLCache_LocalFileNameToPathW(
838 const URLCACHECONTAINER * pContainer,
839 LPCURLCACHE_HEADER pHeader,
840 LPCSTR szLocalFileName,
846 int path_len = strlenW(pContainer->path);
847 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
848 if (Directory >= pHeader->DirectoryCount)
854 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
855 if (nRequired < *lpBufferSize)
859 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
860 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
861 wszPath[dir_len + path_len] = '\\';
862 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
863 *lpBufferSize = nRequired;
866 *lpBufferSize = nRequired;
870 /***********************************************************************
871 * URLCache_LocalFileNameToPathA (Internal)
873 * Copies the full path to the specified buffer given the local file
874 * name and the index of the directory it is in. Always sets value in
875 * lpBufferSize to the required buffer size.
878 * TRUE if the buffer was big enough
879 * FALSE if the buffer was too small
882 static BOOL URLCache_LocalFileNameToPathA(
883 const URLCACHECONTAINER * pContainer,
884 LPCURLCACHE_HEADER pHeader,
885 LPCSTR szLocalFileName,
891 int path_len, file_name_len, dir_len;
893 if (Directory >= pHeader->DirectoryCount)
899 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL);
900 file_name_len = strlen(szLocalFileName);
901 dir_len = DIR_LENGTH;
903 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(WCHAR);
904 if (nRequired < *lpBufferSize)
906 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, -1, NULL, NULL);
907 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
908 szPath[path_len + dir_len] = '\\';
909 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
910 *lpBufferSize = nRequired;
913 *lpBufferSize = nRequired;
917 /***********************************************************************
918 * URLCache_CopyEntry (Internal)
920 * Copies an entry from the cache index file to the Win32 structure
923 * TRUE if the buffer was big enough
924 * FALSE if the buffer was too small
927 static BOOL URLCache_CopyEntry(
928 URLCACHECONTAINER * pContainer,
929 LPCURLCACHE_HEADER pHeader,
930 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
931 LPDWORD lpdwBufferSize,
932 URL_CACHEFILE_ENTRY * pUrlEntry,
936 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
938 if (*lpdwBufferSize >= dwRequiredSize)
940 lpCacheEntryInfo->lpHeaderInfo = NULL;
941 lpCacheEntryInfo->lpszFileExtension = NULL;
942 lpCacheEntryInfo->lpszLocalFileName = NULL;
943 lpCacheEntryInfo->lpszSourceUrlName = NULL;
944 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
945 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
946 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
947 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
948 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
949 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
950 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
951 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
952 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
953 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
954 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
955 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
956 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
957 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
960 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
961 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
962 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
964 lenUrl = MultiByteToWideChar(CP_ACP, 0, pUrlEntry->szSourceUrlName, -1, NULL, 0);
966 lenUrl = strlen(pUrlEntry->szSourceUrlName);
967 dwRequiredSize += lenUrl + 1;
969 /* FIXME: is source url optional? */
970 if (*lpdwBufferSize >= dwRequiredSize)
972 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrl - 1;
974 MultiByteToWideChar(CP_ACP, 0, pUrlEntry->szSourceUrlName, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
976 memcpy(lpCacheEntryInfo->lpszSourceUrlName, pUrlEntry->szSourceUrlName, (lenUrl + 1) * sizeof(CHAR));
979 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
980 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
981 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
983 if (pUrlEntry->dwOffsetLocalName)
985 LONG nLocalFilePathSize;
986 LPSTR lpszLocalFileName;
987 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
988 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
989 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
990 URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize))
992 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
994 dwRequiredSize += nLocalFilePathSize;
996 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
997 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
998 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1000 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
1002 if (*lpdwBufferSize >= dwRequiredSize)
1004 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
1005 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
1006 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
1008 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1009 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1010 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1012 if (dwRequiredSize > *lpdwBufferSize)
1014 *lpdwBufferSize = dwRequiredSize;
1015 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1018 *lpdwBufferSize = dwRequiredSize;
1023 /***********************************************************************
1024 * URLCache_SetEntryInfo (Internal)
1026 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1027 * according the the flags set by dwFieldControl.
1030 * TRUE if the buffer was big enough
1031 * FALSE if the buffer was too small
1034 static BOOL URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1036 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1037 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1038 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1039 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1040 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1041 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1042 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1043 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1044 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1045 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1046 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1047 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1048 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1049 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1050 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1051 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1056 /***********************************************************************
1057 * URLCache_HashKey (Internal)
1059 * Returns the hash key for a given string
1062 * hash key for the string
1065 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1067 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1068 * but the algorithm and result are not the same!
1070 static const unsigned char lookupTable[256] =
1072 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1073 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1074 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1075 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1076 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1077 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1078 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1079 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1080 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1081 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1082 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1083 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1084 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1085 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1086 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1087 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1088 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1089 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1090 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1091 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1092 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1093 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1094 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1095 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1096 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1097 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1098 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1099 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1100 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1101 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1102 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1103 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1107 int subscript[sizeof(key) / sizeof(key[0])];
1109 subscript[0] = *lpszKey;
1110 subscript[1] = (char)(*lpszKey + 1);
1111 subscript[2] = (char)(*lpszKey + 2);
1112 subscript[3] = (char)(*lpszKey + 3);
1114 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1115 key[i] = lookupTable[i];
1117 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
1119 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1120 key[i] = lookupTable[*lpszKey ^ key[i]];
1123 return *(DWORD *)key;
1126 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
1128 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
1131 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1133 /* structure of hash table:
1134 * 448 entries divided into 64 blocks
1135 * each block therefore contains a chain of 7 key/offset pairs
1136 * how position in table is calculated:
1137 * 1. the url is hashed in helper function
1138 * 2. the key % 64 * 8 is the offset
1139 * 3. the key in the hash table is the hash key aligned to 64
1142 * there can be multiple hash tables in the file and the offset to
1143 * the next one is stored in the header of the hash table
1145 DWORD key = URLCache_HashKey(lpszUrl);
1146 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1147 HASH_CACHEFILE_ENTRY * pHashEntry;
1148 DWORD dwHashTableNumber = 0;
1150 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1152 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1153 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1154 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1157 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1159 ERR("Error: not right hash table number (%ld) expected %ld\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1162 /* make sure that it is in fact a hash entry */
1163 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1165 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1169 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1171 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1172 if (key == (DWORD)(pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
1174 /* FIXME: we should make sure that this is the right element
1175 * before returning and claiming that it is. We can do this
1176 * by doing a simple compare between the URL we were given
1177 * and the URL stored in the entry. However, this assumes
1178 * we know the format of all the entries stored in the
1180 *ppHashEntry = pHashElement;
1188 /***********************************************************************
1189 * URLCache_FindEntryInHash (Internal)
1191 * Searches all the hash tables in the index for the given URL and
1192 * returns the entry, if it was found, in ppEntry
1195 * TRUE if the entry was found
1196 * FALSE if the entry could not be found
1199 static BOOL URLCache_FindEntryInHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, CACHEFILE_ENTRY ** ppEntry)
1201 struct _HASH_ENTRY * pHashEntry;
1202 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1204 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1210 /***********************************************************************
1211 * URLCache_HashEntrySetUse (Internal)
1213 * Searches all the hash tables in the index for the given URL and
1214 * sets the use count (stored or'ed with key)
1217 * TRUE if the entry was found
1218 * FALSE if the entry could not be found
1221 static BOOL URLCache_HashEntrySetUse(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwUseCount)
1223 struct _HASH_ENTRY * pHashEntry;
1224 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1226 pHashEntry->dwHashKey = dwUseCount | (DWORD)(pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1232 /***********************************************************************
1233 * URLCache_DeleteEntryFromHash (Internal)
1235 * Searches all the hash tables in the index for the given URL and
1236 * then if found deletes the entry.
1239 * TRUE if the entry was found
1240 * FALSE if the entry could not be found
1243 static BOOL URLCache_DeleteEntryFromHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl)
1245 struct _HASH_ENTRY * pHashEntry;
1246 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1248 pHashEntry->dwHashKey = HASHTABLE_FREE;
1249 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1255 /***********************************************************************
1256 * URLCache_AddEntryToHash (Internal)
1258 * Searches all the hash tables for a free slot based on the offset
1259 * generated from the hash key. If a free slot is found, the offset and
1260 * key are entered into the hash table.
1263 * TRUE if the entry was added
1264 * FALSE if the entry could not be added
1267 static BOOL URLCache_AddEntryToHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1269 /* see URLCache_FindEntryInHash for structure of hash tables */
1271 DWORD key = URLCache_HashKey(lpszUrl);
1272 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1273 HASH_CACHEFILE_ENTRY * pHashEntry;
1274 DWORD dwHashTableNumber = 0;
1276 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1278 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1279 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1280 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1283 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1285 ERR("not right hash table number (%ld) expected %ld\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1288 /* make sure that it is in fact a hash entry */
1289 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1291 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1295 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1297 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1298 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1300 pHashElement->dwHashKey = key;
1301 pHashElement->dwOffsetEntry = dwOffsetEntry;
1306 FIXME("need to create another hash table\n");
1310 /***********************************************************************
1311 * GetUrlCacheEntryInfoExA (WININET.@)
1314 BOOL WINAPI GetUrlCacheEntryInfoExA(
1316 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1317 LPDWORD lpdwCacheEntryInfoBufSize,
1319 LPDWORD lpdwReserved,
1323 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1324 debugstr_a(lpszUrl),
1326 lpdwCacheEntryInfoBufSize,
1332 if ((lpszReserved != NULL) ||
1333 (lpdwReserved != NULL) ||
1334 (lpReserved != NULL))
1336 ERR("Reserved value was not 0\n");
1337 SetLastError(ERROR_INVALID_PARAMETER);
1341 FIXME("Undocumented flag(s): %lx\n", dwFlags);
1342 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1345 /***********************************************************************
1346 * GetUrlCacheEntryInfoA (WININET.@)
1349 BOOL WINAPI GetUrlCacheEntryInfoA(
1350 IN LPCSTR lpszUrlName,
1351 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1352 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1355 LPURLCACHE_HEADER pHeader;
1356 CACHEFILE_ENTRY * pEntry;
1357 URL_CACHEFILE_ENTRY * pUrlEntry;
1358 URLCACHECONTAINER * pContainer;
1360 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1362 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1365 if (!URLCacheContainer_OpenIndex(pContainer))
1368 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1371 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1373 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1374 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1375 SetLastError(ERROR_FILE_NOT_FOUND);
1379 if (pEntry->dwSignature != URL_SIGNATURE)
1381 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1382 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1383 SetLastError(ERROR_FILE_NOT_FOUND);
1387 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1388 TRACE("Found URL: %s\n", debugstr_a(pUrlEntry->szSourceUrlName));
1389 if (pUrlEntry->dwOffsetHeaderInfo)
1390 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1392 if (!URLCache_CopyEntry(
1396 lpdwCacheEntryInfoBufferSize,
1400 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1403 TRACE("Local File Name: %s\n", debugstr_a(lpCacheEntryInfo->lpszLocalFileName));
1405 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1410 /***********************************************************************
1411 * GetUrlCacheEntryInfoW (WININET.@)
1414 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1415 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1416 LPDWORD lpdwCacheEntryInfoBufferSize)
1418 LPURLCACHE_HEADER pHeader;
1419 CACHEFILE_ENTRY * pEntry;
1420 URL_CACHEFILE_ENTRY * pUrlEntry;
1421 URLCACHECONTAINER * pContainer;
1425 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1427 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1428 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1431 SetLastError(ERROR_OUTOFMEMORY);
1434 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1436 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1438 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1442 if (!URLCacheContainer_OpenIndex(pContainer))
1444 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1448 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1450 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1454 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1456 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1457 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1458 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1459 SetLastError(ERROR_FILE_NOT_FOUND);
1462 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1464 if (pEntry->dwSignature != URL_SIGNATURE)
1466 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1467 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1468 SetLastError(ERROR_FILE_NOT_FOUND);
1472 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1473 TRACE("Found URL: %s\n", debugstr_a(pUrlEntry->szSourceUrlName));
1474 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1476 if (!URLCache_CopyEntry(
1479 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1480 lpdwCacheEntryInfoBufferSize,
1482 TRUE /* UNICODE */))
1484 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1487 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1489 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1494 /***********************************************************************
1495 * GetUrlCacheEntryInfoExW (WININET.@)
1498 BOOL WINAPI GetUrlCacheEntryInfoExW(
1500 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1501 LPDWORD lpdwCacheEntryInfoBufSize,
1502 LPWSTR lpszReserved,
1503 LPDWORD lpdwReserved,
1507 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1508 debugstr_w(lpszUrl),
1510 lpdwCacheEntryInfoBufSize,
1516 if ((lpszReserved != NULL) ||
1517 (lpdwReserved != NULL) ||
1518 (lpReserved != NULL))
1520 ERR("Reserved value was not 0\n");
1521 SetLastError(ERROR_INVALID_PARAMETER);
1525 FIXME("Undocumented flag(s): %lx\n", dwFlags);
1526 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1529 /***********************************************************************
1530 * SetUrlCacheEntryInfoA (WININET.@)
1532 BOOL WINAPI SetUrlCacheEntryInfoA(
1534 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1535 DWORD dwFieldControl)
1537 LPURLCACHE_HEADER pHeader;
1538 CACHEFILE_ENTRY * pEntry;
1539 URLCACHECONTAINER * pContainer;
1541 TRACE("(%s, %p, 0x%08lx)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1543 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1546 if (!URLCacheContainer_OpenIndex(pContainer))
1549 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1552 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1554 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1555 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1556 SetLastError(ERROR_FILE_NOT_FOUND);
1560 if (pEntry->dwSignature != URL_SIGNATURE)
1562 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1563 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1564 SetLastError(ERROR_FILE_NOT_FOUND);
1568 URLCache_SetEntryInfo(
1569 (URL_CACHEFILE_ENTRY *)pEntry,
1570 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1573 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1578 /***********************************************************************
1579 * SetUrlCacheEntryInfoW (WININET.@)
1581 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1583 LPURLCACHE_HEADER pHeader;
1584 CACHEFILE_ENTRY * pEntry;
1585 URLCACHECONTAINER * pContainer;
1589 TRACE("(%s, %p, 0x%08lx)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1591 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1592 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1595 SetLastError(ERROR_OUTOFMEMORY);
1598 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1600 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1602 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1606 if (!URLCacheContainer_OpenIndex(pContainer))
1608 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1612 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1614 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1618 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1620 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1621 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1622 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1623 SetLastError(ERROR_FILE_NOT_FOUND);
1626 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1628 if (pEntry->dwSignature != URL_SIGNATURE)
1630 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1631 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1632 SetLastError(ERROR_FILE_NOT_FOUND);
1636 URLCache_SetEntryInfo(
1637 (URL_CACHEFILE_ENTRY *)pEntry,
1641 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1646 /***********************************************************************
1647 * RetrieveUrlCacheEntryFileA (WININET.@)
1650 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1651 IN LPCSTR lpszUrlName,
1652 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1653 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1657 LPURLCACHE_HEADER pHeader;
1658 CACHEFILE_ENTRY * pEntry;
1659 URL_CACHEFILE_ENTRY * pUrlEntry;
1660 URLCACHECONTAINER * pContainer;
1662 TRACE("(%s, %p, %p, 0x%08lx)\n",
1663 debugstr_a(lpszUrlName),
1665 lpdwCacheEntryInfoBufferSize,
1668 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1671 if (!URLCacheContainer_OpenIndex(pContainer))
1674 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1677 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1679 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1680 TRACE("entry %s not found!\n", lpszUrlName);
1681 SetLastError(ERROR_FILE_NOT_FOUND);
1685 if (pEntry->dwSignature != URL_SIGNATURE)
1687 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1688 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1689 SetLastError(ERROR_FILE_NOT_FOUND);
1693 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1694 TRACE("Found URL: %s\n", pUrlEntry->szSourceUrlName);
1695 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1697 pUrlEntry->dwHitRate++;
1698 pUrlEntry->dwUseCount++;
1699 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1701 if (!URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize, pUrlEntry, FALSE))
1703 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1706 TRACE("Local File Name: %s\n", lpCacheEntryInfo->lpszLocalFileName);
1708 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1713 /***********************************************************************
1714 * RetrieveUrlCacheEntryFileW (WININET.@)
1717 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1718 IN LPCWSTR lpszUrlName,
1719 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1720 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1724 TRACE("(%s, %p, %p, 0x%08lx)\n",
1725 debugstr_w(lpszUrlName),
1727 lpdwCacheEntryInfoBufferSize,
1733 /***********************************************************************
1734 * UnlockUrlCacheEntryFileA (WININET.@)
1737 BOOL WINAPI UnlockUrlCacheEntryFileA(
1738 IN LPCSTR lpszUrlName,
1742 LPURLCACHE_HEADER pHeader;
1743 CACHEFILE_ENTRY * pEntry;
1744 URL_CACHEFILE_ENTRY * pUrlEntry;
1745 URLCACHECONTAINER * pContainer;
1747 TRACE("(%s, 0x%08lx)\n", debugstr_a(lpszUrlName), dwReserved);
1751 ERR("dwReserved != 0\n");
1752 SetLastError(ERROR_INVALID_PARAMETER);
1756 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1759 if (!URLCacheContainer_OpenIndex(pContainer))
1762 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1765 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1767 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1768 TRACE("entry %s not found!\n", lpszUrlName);
1769 SetLastError(ERROR_FILE_NOT_FOUND);
1773 if (pEntry->dwSignature != URL_SIGNATURE)
1775 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1776 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1777 SetLastError(ERROR_FILE_NOT_FOUND);
1781 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1783 if (pUrlEntry->dwUseCount == 0)
1785 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1788 pUrlEntry->dwUseCount--;
1789 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1791 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1796 /***********************************************************************
1797 * UnlockUrlCacheEntryFileW (WININET.@)
1800 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
1802 FIXME("(%s, 0x%08lx)\n", debugstr_w(lpszUrlName), dwReserved);
1806 /***********************************************************************
1807 * CreateUrlCacheEntryA (WININET.@)
1810 BOOL WINAPI CreateUrlCacheEntryA(
1811 IN LPCSTR lpszUrlName,
1812 IN DWORD dwExpectedFileSize,
1813 IN LPCSTR lpszFileExtension,
1814 OUT LPSTR lpszFileName,
1820 WCHAR *file_extension;
1821 WCHAR file_name[MAX_PATH];
1822 BOOL bSuccess = FALSE;
1825 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
1826 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
1828 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
1829 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 &&
1830 (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
1832 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
1833 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
1835 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
1841 dwError = GetLastError();
1846 dwError = GetLastError();
1848 HeapFree(GetProcessHeap(), 0, file_extension);
1852 dwError = GetLastError();
1854 HeapFree(GetProcessHeap(), 0, url_name);
1856 SetLastError(dwError);
1860 /***********************************************************************
1861 * CreateUrlCacheEntryW (WININET.@)
1864 BOOL WINAPI CreateUrlCacheEntryW(
1865 IN LPCWSTR lpszUrlName,
1866 IN DWORD dwExpectedFileSize,
1867 IN LPCWSTR lpszFileExtension,
1868 OUT LPWSTR lpszFileName,
1872 URLCACHECONTAINER * pContainer;
1873 LPURLCACHE_HEADER pHeader;
1874 CHAR szFile[MAX_PATH];
1875 WCHAR szExtension[MAX_PATH];
1876 LPCWSTR lpszUrlPart;
1878 LPCWSTR lpszFileNameExtension;
1879 LPWSTR lpszFileNameNoPath;
1881 int countnoextension;
1884 BOOL bFound = FALSE;
1886 static WCHAR szWWW[] = {'w','w','w',0};
1888 TRACE("(%s, 0x%08lx, %s, %p, 0x%08lx)\n",
1889 debugstr_w(lpszUrlName),
1891 debugstr_w(lpszFileExtension),
1897 ERR("dwReserved != 0\n");
1898 SetLastError(ERROR_INVALID_PARAMETER);
1902 for (lpszUrlEnd = lpszUrlName; *lpszUrlEnd; lpszUrlEnd++)
1905 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
1908 for (lpszUrlPart = lpszUrlEnd;
1909 (lpszUrlPart >= lpszUrlName);
1912 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
1919 if (!lstrcmpW(lpszUrlPart, szWWW))
1921 lpszUrlPart += lstrlenW(szWWW);
1924 count = lpszUrlEnd - lpszUrlPart;
1926 if (bFound && (count < MAX_PATH))
1928 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
1932 /* FIXME: get rid of illegal characters like \, / and : */
1936 FIXME("need to generate a random filename\n");
1939 TRACE("File name: %s\n", debugstr_a(szFile));
1941 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
1944 if (!URLCacheContainer_OpenIndex(pContainer))
1947 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1950 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
1952 lBufferSize = MAX_PATH * sizeof(CHAR);
1953 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
1955 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1957 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(CHAR) - 2;
1958 lpszFileNameNoPath >= lpszFileName;
1959 --lpszFileNameNoPath)
1961 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
1965 countnoextension = lstrlenW(lpszFileNameNoPath);
1966 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
1967 if (lpszFileNameExtension)
1968 countnoextension -= lstrlenW(lpszFileNameExtension);
1969 *szExtension = '\0';
1971 if (lpszFileExtension)
1973 szExtension[0] = '.';
1974 lstrcpyW(szExtension+1, lpszFileExtension);
1977 for (i = 0; i < 255; i++)
1979 static WCHAR szFormat[] = {'[','%','u',']','%','s',0};
1981 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
1982 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
1983 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
1984 if (hFile != INVALID_HANDLE_VALUE)
1995 /***********************************************************************
1996 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
1998 * The bug we are compensating for is that some drongo at Microsoft
1999 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2000 * As a consequence, CommitUrlCacheEntryA has been effectively
2001 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2002 * is still defined as LPCWSTR. The result (other than madness) is
2003 * that we always need to store lpHeaderInfo in CP_ACP rather than
2004 * in UTF16, and we need to avoid converting lpHeaderInfo in
2005 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2006 * result will lose data for arbitrary binary data.
2009 static BOOL WINAPI CommitUrlCacheEntryInternal(
2010 IN LPCWSTR lpszUrlName,
2011 IN LPCWSTR lpszLocalFileName,
2012 IN FILETIME ExpireTime,
2013 IN FILETIME LastModifiedTime,
2014 IN DWORD CacheEntryType,
2015 IN LPBYTE lpHeaderInfo,
2016 IN DWORD dwHeaderSize,
2017 IN LPCWSTR lpszFileExtension,
2018 IN LPCWSTR lpszOriginalUrl
2021 URLCACHECONTAINER * pContainer;
2022 LPURLCACHE_HEADER pHeader;
2023 CACHEFILE_ENTRY * pEntry;
2024 URL_CACHEFILE_ENTRY * pUrlEntry;
2025 DWORD dwBytesNeeded = sizeof(*pUrlEntry) - sizeof(pUrlEntry->szSourceUrlName);
2026 DWORD dwOffsetLocalFileName = 0;
2027 DWORD dwOffsetHeader = 0;
2028 DWORD dwFileSizeLow = 0;
2029 DWORD dwFileSizeHigh = 0;
2030 BYTE cDirectory = 0;
2031 char achFile[MAX_PATH];
2032 char achUrl[MAX_PATH];
2033 char *pchLocalFileName = 0;
2035 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %s)\n",
2036 debugstr_w(lpszUrlName),
2037 debugstr_w(lpszLocalFileName),
2041 debugstr_w(lpszFileExtension),
2042 debugstr_w(lpszOriginalUrl));
2044 if (lpszOriginalUrl)
2045 WARN(": lpszOriginalUrl ignored\n");
2047 if (lpszLocalFileName)
2051 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2052 if (hFile == INVALID_HANDLE_VALUE)
2054 ERR("couldn't open file %s (error is %ld)\n", debugstr_w(lpszLocalFileName), GetLastError());
2059 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2060 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2062 ERR("couldn't get file size (error is %ld)\n", GetLastError());
2070 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
2073 if (!URLCacheContainer_OpenIndex(pContainer))
2076 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2079 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, achUrl, -1, NULL, NULL);
2081 if (URLCache_FindEntryInHash(pHeader, achUrl, &pEntry))
2083 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2084 FIXME("entry already in cache - don't know what to do!\n");
2086 * SetLastError(ERROR_FILE_NOT_FOUND);
2092 if (lpszLocalFileName)
2094 BOOL bFound = FALSE;
2096 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2098 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2099 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2100 SetLastError(ERROR_INVALID_PARAMETER);
2104 /* skip container path prefix */
2105 lpszLocalFileName += lstrlenW(pContainer->path);
2107 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, -1, NULL, NULL);
2108 pchLocalFileName = achFile;
2110 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2112 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2121 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2122 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2123 SetLastError(ERROR_INVALID_PARAMETER);
2127 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2130 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(achUrl) + 1);
2131 if (lpszLocalFileName)
2133 dwOffsetLocalFileName = dwBytesNeeded;
2134 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2138 dwOffsetHeader = dwBytesNeeded;
2139 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2142 /* round up to next block */
2143 if (dwBytesNeeded % BLOCKSIZE)
2145 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2146 dwBytesNeeded += BLOCKSIZE;
2149 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2151 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2152 ERR("no free entries\n");
2156 /* FindFirstFreeEntry fills in blocks used */
2157 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2158 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2159 pUrlEntry->CacheDir = cDirectory;
2160 pUrlEntry->CacheEntryType = CacheEntryType;
2161 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2162 pUrlEntry->dwExemptDelta = 0;
2163 pUrlEntry->dwHitRate = 0;
2164 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2165 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2166 pUrlEntry->dwOffsetUrl = sizeof(*pUrlEntry) - sizeof(pUrlEntry->szSourceUrlName);
2167 pUrlEntry->dwSizeHigh = 0;
2168 pUrlEntry->dwSizeLow = dwFileSizeLow;
2169 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2170 pUrlEntry->dwUseCount = 0;
2171 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2172 pUrlEntry->LastModifiedTime = LastModifiedTime;
2173 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2174 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2175 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2176 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2179 pUrlEntry->dwUnknown1 = 0;
2180 pUrlEntry->dwUnknown2 = 0;
2181 pUrlEntry->dwUnknown3 = 0x60;
2182 pUrlEntry->Unknown4 = 0;
2183 pUrlEntry->wUnknown5 = 0x1010;
2184 pUrlEntry->dwUnknown6 = 0;
2185 pUrlEntry->dwUnknown7 = 0;
2186 pUrlEntry->dwUnknown8 = 0;
2189 strcpy(pUrlEntry->szSourceUrlName, achUrl);
2190 if (dwOffsetLocalFileName)
2191 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName);
2193 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2195 if (!URLCache_AddEntryToHash(pHeader, achUrl, (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader)))
2197 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2201 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2206 /***********************************************************************
2207 * CommitUrlCacheEntryA (WININET.@)
2210 BOOL WINAPI CommitUrlCacheEntryA(
2211 IN LPCSTR lpszUrlName,
2212 IN LPCSTR lpszLocalFileName,
2213 IN FILETIME ExpireTime,
2214 IN FILETIME LastModifiedTime,
2215 IN DWORD CacheEntryType,
2216 IN LPBYTE lpHeaderInfo,
2217 IN DWORD dwHeaderSize,
2218 IN LPCSTR lpszFileExtension,
2219 IN LPCSTR lpszOriginalUrl
2224 WCHAR *local_file_name;
2225 WCHAR *original_url = NULL;
2226 BOOL bSuccess = FALSE;
2229 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %s)\n",
2230 debugstr_a(lpszUrlName),
2231 debugstr_a(lpszLocalFileName),
2235 debugstr_a(lpszFileExtension),
2236 debugstr_a(lpszOriginalUrl));
2238 if (lpszFileExtension != 0)
2240 SetLastError(ERROR_INVALID_PARAMETER);
2243 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
2244 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2246 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2247 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0)) != 0 &&
2248 (local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2250 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2251 if (!lpszOriginalUrl ||
2252 ((len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0)) != 0 &&
2253 (original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0))
2256 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2257 if (CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2258 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2259 NULL, original_url))
2265 dwError = GetLastError();
2268 HeapFree(GetProcessHeap(), 0, original_url);
2272 dwError = GetLastError();
2274 HeapFree(GetProcessHeap(), 0, local_file_name);
2278 dwError = GetLastError();
2280 HeapFree(GetProcessHeap(), 0, url_name);
2282 SetLastError(dwError);
2287 /***********************************************************************
2288 * CommitUrlCacheEntryW (WININET.@)
2291 BOOL WINAPI CommitUrlCacheEntryW(
2292 IN LPCWSTR lpszUrlName,
2293 IN LPCWSTR lpszLocalFileName,
2294 IN FILETIME ExpireTime,
2295 IN FILETIME LastModifiedTime,
2296 IN DWORD CacheEntryType,
2297 IN LPWSTR lpHeaderInfo,
2298 IN DWORD dwHeaderSize,
2299 IN LPCWSTR lpszFileExtension,
2300 IN LPCWSTR lpszOriginalUrl
2304 BOOL bSuccess = FALSE;
2306 CHAR *header_info = NULL;
2308 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %s)\n",
2309 debugstr_w(lpszUrlName),
2310 debugstr_w(lpszLocalFileName),
2314 debugstr_w(lpszFileExtension),
2315 debugstr_w(lpszOriginalUrl));
2317 if (!lpHeaderInfo ||
2318 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2319 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2322 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2323 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2324 CacheEntryType, header_info, len, lpszFileExtension, lpszOriginalUrl))
2330 dwError = GetLastError();
2334 HeapFree(GetProcessHeap(), 0, header_info);
2336 SetLastError(dwError);
2342 /***********************************************************************
2343 * ReadUrlCacheEntryStream (WININET.@)
2346 BOOL WINAPI ReadUrlCacheEntryStream(
2347 IN HANDLE hUrlCacheStream,
2348 IN DWORD dwLocation,
2349 IN OUT LPVOID lpBuffer,
2350 IN OUT LPDWORD lpdwLen,
2354 /* Get handle to file from 'stream' */
2355 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2357 if (dwReserved != 0)
2359 ERR("dwReserved != 0\n");
2360 SetLastError(ERROR_INVALID_PARAMETER);
2364 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2366 SetLastError(ERROR_INVALID_HANDLE);
2370 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2372 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2375 /***********************************************************************
2376 * RetrieveUrlCacheEntryStreamA (WININET.@)
2379 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2380 IN LPCSTR lpszUrlName,
2381 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2382 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2383 IN BOOL fRandomRead,
2387 /* NOTE: this is not the same as the way that the native
2388 * version allocates 'stream' handles. I did it this way
2389 * as it is much easier and no applications should depend
2390 * on this behaviour. (Native version appears to allocate
2391 * indices into a table)
2393 STREAM_HANDLE * pStream;
2396 TRACE( "(%s, %p, %p, %x, 0x%08lx)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2397 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2399 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2401 lpdwCacheEntryInfoBufferSize,
2407 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2412 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2414 if (hFile == INVALID_HANDLE_VALUE)
2417 /* allocate handle storage space */
2418 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2422 SetLastError(ERROR_OUTOFMEMORY);
2426 pStream->hFile = hFile;
2427 strcpy(pStream->lpszUrl, lpszUrlName);
2428 return (HANDLE)pStream;
2431 /***********************************************************************
2432 * RetrieveUrlCacheEntryStreamW (WININET.@)
2435 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2436 IN LPCWSTR lpszUrlName,
2437 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2438 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2439 IN BOOL fRandomRead,
2443 FIXME( "(%s, %p, %p, %x, 0x%08lx)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2444 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2448 /***********************************************************************
2449 * UnlockUrlCacheEntryStream (WININET.@)
2452 BOOL WINAPI UnlockUrlCacheEntryStream(
2453 IN HANDLE hUrlCacheStream,
2457 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2459 if (dwReserved != 0)
2461 ERR("dwReserved != 0\n");
2462 SetLastError(ERROR_INVALID_PARAMETER);
2466 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2468 SetLastError(ERROR_INVALID_HANDLE);
2472 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2475 /* close file handle */
2476 CloseHandle(pStream->hFile);
2478 /* free allocated space */
2479 HeapFree(GetProcessHeap(), 0, pStream);
2485 /***********************************************************************
2486 * DeleteUrlCacheEntryA (WININET.@)
2489 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2491 URLCACHECONTAINER * pContainer;
2492 LPURLCACHE_HEADER pHeader;
2493 CACHEFILE_ENTRY * pEntry;
2496 BYTE * AllocationTable;
2498 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2500 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
2503 if (!URLCacheContainer_OpenIndex(pContainer))
2506 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2509 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
2511 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2512 TRACE("entry %s not found!\n", lpszUrlName);
2513 SetLastError(ERROR_FILE_NOT_FOUND);
2517 AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
2519 /* update allocation table */
2520 dwStartBlock = ((DWORD)pEntry - (DWORD)pHeader) / BLOCKSIZE;
2521 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
2522 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
2524 URLCache_DeleteEntry(pEntry);
2526 URLCache_DeleteEntryFromHash(pHeader, lpszUrlName);
2528 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2533 /***********************************************************************
2534 * DeleteUrlCacheEntryW (WININET.@)
2537 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2539 FIXME("(%s) stub\n", debugstr_w(lpszUrlName));
2543 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2545 FIXME("(0x%08lx, 0x%08lx) stub\n", d1, d2);
2549 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2551 FIXME("(0x%08lx, 0x%08lx) stub\n", d1, d2);
2555 /***********************************************************************
2556 * CreateCacheContainerA (WININET.@)
2558 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2559 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2561 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) stub\n",
2562 d1, d2, d3, d4, d5, d6, d7, d8);
2566 /***********************************************************************
2567 * CreateCacheContainerW (WININET.@)
2569 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2570 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2572 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) stub\n",
2573 d1, d2, d3, d4, d5, d6, d7, d8);
2577 /***********************************************************************
2578 * FindCloseUrlCache (WININET.@)
2580 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
2582 FIXME("(%p) stub\n", hEnumHandle);
2586 /***********************************************************************
2587 * FindFirstUrlCacheContainerA (WININET.@)
2589 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2591 FIXME("(%p, %p, %p, 0x%08lx) stub\n", p1, p2, p3, d1 );
2595 /***********************************************************************
2596 * FindFirstUrlCacheContainerW (WININET.@)
2598 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2600 FIXME("(%p, %p, %p, 0x%08lx) stub\n", p1, p2, p3, d1 );
2604 /***********************************************************************
2605 * FindNextUrlCacheContainerA (WININET.@)
2607 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
2609 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2613 /***********************************************************************
2614 * FindNextUrlCacheContainerW (WININET.@)
2616 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
2618 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2622 HANDLE WINAPI FindFirstUrlCacheEntryExA(
2623 LPCSTR lpszUrlSearchPattern,
2627 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2628 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2630 LPDWORD pcbReserved2,
2634 FIXME("(%s, 0x%08lx, 0x%08lx, 0x%08lx%08lx, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
2635 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2636 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2637 SetLastError(ERROR_FILE_NOT_FOUND);
2641 HANDLE WINAPI FindFirstUrlCacheEntryExW(
2642 LPCWSTR lpszUrlSearchPattern,
2646 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2647 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2649 LPDWORD pcbReserved2,
2653 FIXME("(%s, 0x%08lx, 0x%08lx, 0x%08lx%08lx, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
2654 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2655 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2656 SetLastError(ERROR_FILE_NOT_FOUND);
2660 /***********************************************************************
2661 * FindFirstUrlCacheEntryA (WININET.@)
2664 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
2665 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2667 FIXME("(%s, %p, %p): stub\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2668 SetLastError(ERROR_FILE_NOT_FOUND);
2672 /***********************************************************************
2673 * FindFirstUrlCacheEntryW (WININET.@)
2676 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
2677 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2679 FIXME("(%s, %p, %p): stub\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2683 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
2684 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
2686 FIXME("(0x%08lx, 0x%08lx, %p, 0x%08lx, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
2687 dwSearchCondition, lpGroupId, lpReserved);
2691 BOOL WINAPI FindNextUrlCacheEntryA(
2693 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
2694 LPDWORD lpdwNextCacheEntryInfoBufferSize
2697 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2701 BOOL WINAPI FindNextUrlCacheEntryW(
2703 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
2704 LPDWORD lpdwNextCacheEntryInfoBufferSize
2707 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2711 BOOL WINAPI FindNextUrlCacheEntryExA(
2713 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2714 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2716 LPDWORD pcbReserved2,
2720 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2721 lpReserved, pcbReserved2, lpReserved3);
2725 BOOL WINAPI FindNextUrlCacheEntryExW(
2727 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2728 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2730 LPDWORD pcbReserved2,
2734 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2735 lpReserved, pcbReserved2, lpReserved3);
2739 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
2741 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
2745 /***********************************************************************
2746 * CreateUrlCacheGroup (WININET.@)
2749 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
2751 FIXME("(0x%08lx, %p): stub\n", dwFlags, lpReserved);
2755 /***********************************************************************
2756 * DeleteUrlCacheGroup (WININET.@)
2759 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
2761 FIXME("(0x%08lx%08lx, 0x%08lx, %p) stub\n",
2762 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
2766 /***********************************************************************
2767 * SetUrlCacheEntryGroupA (WININET.@)
2770 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
2771 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2774 FIXME("(%s, 0x%08lx, 0x%08lx%08lx, %p, 0x%08lx, %p) stub\n",
2775 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2776 pbGroupAttributes, cbGroupAttributes, lpReserved);
2777 SetLastError(ERROR_FILE_NOT_FOUND);
2781 /***********************************************************************
2782 * SetUrlCacheEntryGroupW (WININET.@)
2785 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
2786 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2789 FIXME("(%s, 0x%08lx, 0x%08lx%08lx, %p, 0x%08lx, %p) stub\n",
2790 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2791 pbGroupAttributes, cbGroupAttributes, lpReserved);
2792 SetLastError(ERROR_FILE_NOT_FOUND);
2796 /***********************************************************************
2797 * GetUrlCacheConfigInfoW (WININET.@)
2799 BOOL WINAPI GetUrlCacheConfigInfoW(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2801 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2802 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2806 /***********************************************************************
2807 * GetUrlCacheConfigInfoA (WININET.@)
2809 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
2811 BOOL WINAPI GetUrlCacheConfigInfoA(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2813 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2814 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2818 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2819 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
2820 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2822 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p, %p) stub\n",
2823 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2824 lpdwGroupInfo, lpReserved);
2828 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2829 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
2830 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2832 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p, %p) stub\n",
2833 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2834 lpdwGroupInfo, lpReserved);
2838 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2839 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
2841 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p) stub\n",
2842 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2846 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2847 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
2849 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p) stub\n",
2850 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2854 BOOL WINAPI SetUrlCacheConfigInfoA( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2856 FIXME("(%p, 0x%08lx) stub\n", lpCacheConfigInfo, dwFieldControl);
2860 BOOL WINAPI SetUrlCacheConfigInfoW( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2862 FIXME("(%p, 0x%08lx) stub\n", lpCacheConfigInfo, dwFieldControl);
2866 /***********************************************************************
2867 * DeleteIE3Cache (WININET.@)
2869 * Deletes the files used by the IE3 URL caching system.
2872 * hWnd [I] A dummy window.
2873 * hInst [I] Instance of process calling the function.
2874 * lpszCmdLine [I] Options used by function.
2875 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
2880 void WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
2882 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);