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
26 #include "wine/port.h"
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
48 #include "wine/unicode.h"
49 #include "wine/list.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
54 #define ENTRY_START_OFFSET 0x4000
57 #define HASHTABLE_SIZE 448
58 #define HASHTABLE_BLOCKSIZE 7
59 #define HASHTABLE_FREE 3
60 #define ALLOCATION_TABLE_OFFSET 0x250
61 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
62 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
63 #define NEWFILE_NUM_BLOCKS 0xd80
64 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
66 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
67 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
68 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
69 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
70 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
72 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
74 typedef struct _CACHEFILE_ENTRY
78 DWORD dwSignature; /* e.g. "URL " */
79 /* CHAR szSignature[4];
81 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
84 typedef struct _URL_CACHEFILE_ENTRY
86 CACHEFILE_ENTRY CacheFileEntry;
87 FILETIME LastModifiedTime;
88 FILETIME LastAccessTime;
89 WORD wExpiredDate; /* expire date in dos format */
90 WORD wExpiredTime; /* expire time in dos format */
91 DWORD dwUnknown1; /* usually zero */
92 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
93 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
94 DWORD dwUnknown2; /* usually zero */
95 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
96 DWORD dwUnknown3; /* usually 0x60 */
97 DWORD dwOffsetUrl; /* offset of start of url from start of entry */
98 BYTE CacheDir; /* index of cache directory this url is stored in */
99 BYTE Unknown4; /* usually zero */
100 WORD wUnknown5; /* usually 0x1010 */
101 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
102 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
103 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
104 DWORD dwHeaderInfoSize;
105 DWORD dwUnknown6; /* usually zero */
106 WORD wLastSyncDate; /* last sync date in dos format */
107 WORD wLastSyncTime; /* last sync time in dos format */
108 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
109 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
110 WORD wUnknownDate; /* usually same as wLastSyncDate */
111 WORD wUnknownTime; /* usually same as wLastSyncTime */
112 DWORD dwUnknown7; /* usually zero */
113 DWORD dwUnknown8; /* usually zero */
114 /* packing to dword align start of next field */
115 /* CHAR szSourceUrlName[]; (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 HASH_CACHEFILE_ENTRY *URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash);
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];
301 dwFileSize = NEWFILE_SIZE;
303 /* First set some constants and defaults in the header */
304 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
305 pHeader->dwFileSize = dwFileSize;
306 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
307 /* 127MB - taken from default for Windows 2000 */
308 pHeader->dwCacheLimitHigh = 0;
309 pHeader->dwCacheLimitLow = 0x07ff5400;
310 /* Copied from a Windows 2000 cache index */
311 pHeader->DirectoryCount = 4;
313 /* If the registry has a cache size set, use the registry value */
314 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
317 DWORD len = sizeof(dw);
320 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
321 (BYTE *) &dw, &len) == ERROR_SUCCESS &&
322 keytype == REG_DWORD)
324 pHeader->dwCacheLimitHigh = (dw >> 22);
325 pHeader->dwCacheLimitLow = dw << 10;
330 URLCache_CreateHashTable(pHeader, NULL);
332 /* Last step - create the directories */
334 strcpyW(wszDirPath, pContainer->path);
335 pwchDir = wszDirPath + strlenW(wszDirPath);
338 GetSystemTimeAsFileTime(&ft);
340 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
342 /* The following values were copied from a Windows index.
343 * I don't know what the values are supposed to mean but
344 * have made them the same in the hope that this will
345 * be better for compatibility
347 pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
351 ULONGLONG n = ft.dwHighDateTime;
353 /* Generate a file name to attempt to create.
354 * This algorithm will create what will appear
355 * to be random and unrelated directory names
356 * of up to 9 characters in length.
359 n += ft.dwLowDateTime;
360 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
362 for (k = 0; k < 8; ++k)
366 /* Dividing by a prime greater than 36 helps
367 * with the appearance of randomness
372 pwchDir[k] = '0' + r;
374 pwchDir[k] = 'A' + (r - 10);
377 if (CreateDirectoryW(wszDirPath, 0))
381 /* The following is OK because we generated an
382 * 8 character directory name made from characters
383 * [A-Z0-9], which are equivalent for all code
384 * pages and for UTF-16
386 for (k = 0; k < 8; ++k)
387 pHeader->directory_data[i].filename[k] = pwchDir[k];
392 /* Give up. The most likely cause of this
393 * is a full disk, but whatever the cause
394 * is, it should be more than apparent that
397 dwError = GetLastError();
403 UnmapViewOfFile(pHeader);
407 dwError = GetLastError();
409 CloseHandle(hMapping);
413 dwError = GetLastError();
420 DeleteFileW(wszFilePath);
421 ReleaseMutex(pContainer->hMutex);
422 SetLastError(dwError);
428 ReleaseMutex(pContainer->hMutex);
430 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
431 URLCache_PathToObjectName(wszFilePath, '_');
432 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
433 if (!pContainer->hMapping)
434 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
436 if (!pContainer->hMapping)
438 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
445 /***********************************************************************
446 * URLCacheContainer_CloseIndex (Internal)
454 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
456 CloseHandle(pContainer->hMapping);
457 pContainer->hMapping = NULL;
460 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
462 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
463 int path_len = strlenW(path);
464 int cache_prefix_len = strlenW(cache_prefix);
471 pContainer->hMapping = NULL;
472 pContainer->file_size = 0;
474 pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR));
475 if (!pContainer->path)
477 HeapFree(GetProcessHeap(), 0, pContainer);
481 memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR));
483 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
484 if (!pContainer->cache_prefix)
486 HeapFree(GetProcessHeap(), 0, pContainer->path);
487 HeapFree(GetProcessHeap(), 0, pContainer);
491 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
493 CharLowerW(mutex_name);
494 URLCache_PathToObjectName(mutex_name, '!');
496 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
498 ERR("couldn't create mutex (error is %d)\n", GetLastError());
499 HeapFree(GetProcessHeap(), 0, pContainer->path);
500 HeapFree(GetProcessHeap(), 0, pContainer);
504 list_add_head(&UrlContainers, &pContainer->entry);
509 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
511 list_remove(&pContainer->entry);
513 URLCacheContainer_CloseIndex(pContainer);
514 CloseHandle(pContainer->hMutex);
515 HeapFree(GetProcessHeap(), 0, pContainer->path);
516 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
517 HeapFree(GetProcessHeap(), 0, pContainer);
520 void URLCacheContainers_CreateDefaults(void)
522 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
523 static const WCHAR UrlPrefix[] = {0};
524 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
525 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
526 static const WCHAR CookieSuffix[] = {0};
527 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
530 int nFolder; /* CSIDL_* constant */
531 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
532 const WCHAR * cache_prefix; /* prefix used to reference the container */
533 } DefaultContainerData[] =
535 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
536 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
537 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
541 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
543 WCHAR wszCachePath[MAX_PATH];
544 WCHAR wszMutexName[MAX_PATH];
545 int path_len, suffix_len;
547 if (FAILED(SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE)))
549 ERR("Couldn't get path for default container %u\n", i);
552 path_len = strlenW(wszCachePath);
553 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
555 if (path_len + suffix_len + 2 > MAX_PATH)
557 ERR("Path too long\n");
561 wszCachePath[path_len] = '\\';
562 wszCachePath[path_len+1] = 0;
564 strcpyW(wszMutexName, wszCachePath);
568 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
569 wszCachePath[path_len + suffix_len + 1] = '\\';
570 wszCachePath[path_len + suffix_len + 2] = '\0';
573 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
577 void URLCacheContainers_DeleteAll(void)
579 while(!list_empty(&UrlContainers))
580 URLCacheContainer_DeleteContainer(
581 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
585 static BOOL URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
587 struct list * cursor;
589 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
591 LIST_FOR_EACH(cursor, &UrlContainers)
593 URLCACHECONTAINER * pContainer = LIST_ENTRY(cursor, URLCACHECONTAINER, entry);
594 int prefix_len = strlenW(pContainer->cache_prefix);
595 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
597 TRACE("found container with prefx %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
598 *ppContainer = pContainer;
602 ERR("no container found\n");
603 SetLastError(ERROR_FILE_NOT_FOUND);
607 static BOOL URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
611 int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
612 if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR))))
614 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len);
615 ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer);
616 HeapFree(GetProcessHeap(), 0, lpwszUrl);
622 /***********************************************************************
623 * URLCacheContainer_LockIndex (Internal)
626 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
630 URLCACHE_HEADER * pHeader;
633 WaitForSingleObject(pContainer->hMutex, INFINITE);
635 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
639 ReleaseMutex(pContainer->hMutex);
640 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
643 pHeader = (URLCACHE_HEADER *)pIndexData;
645 /* file has grown - we need to remap to prevent us getting
646 * access violations when we try and access beyond the end
647 * of the memory mapped file */
648 if (pHeader->dwFileSize != pContainer->file_size)
650 URLCacheContainer_CloseIndex(pContainer);
651 if (!URLCacheContainer_OpenIndex(pContainer))
653 ReleaseMutex(pContainer->hMutex);
656 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
660 ReleaseMutex(pContainer->hMutex);
661 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
664 pHeader = (URLCACHE_HEADER *)pIndexData;
667 TRACE("Signature: %s, file size: %d bytes\n", pHeader->szSignature, pHeader->dwFileSize);
669 for (index = 0; index < pHeader->DirectoryCount; index++)
671 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
677 /***********************************************************************
678 * URLCacheContainer_UnlockIndex (Internal)
681 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
684 ReleaseMutex(pContainer->hMutex);
685 return UnmapViewOfFile(pHeader);
690 #define CHAR_BIT (8 * sizeof(CHAR))
693 /***********************************************************************
694 * URLCache_Allocation_BlockIsFree (Internal)
696 * Is the specified block number free?
703 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
705 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
706 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
709 /***********************************************************************
710 * URLCache_Allocation_BlockFree (Internal)
712 * Marks the specified block as free
718 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
720 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
721 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
724 /***********************************************************************
725 * URLCache_Allocation_BlockAllocate (Internal)
727 * Marks the specified block as allocated
733 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
735 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
736 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
739 /***********************************************************************
740 * URLCache_FindFirstFreeEntry (Internal)
742 * Finds and allocates the first block of free space big enough and
743 * sets ppEntry to point to it.
746 * TRUE if it had enough space
747 * FALSE if it couldn't find enough space
750 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
752 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
755 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
757 for (dwFreeCounter = 0;
758 dwFreeCounter < dwBlocksNeeded &&
759 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
760 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
762 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
764 if (dwFreeCounter == dwBlocksNeeded)
767 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
768 for (index = 0; index < dwBlocksNeeded; index++)
769 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
770 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
771 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
775 FIXME("Grow file\n");
779 /***********************************************************************
780 * URLCache_DeleteEntry (Internal)
782 * Deletes the specified entry and frees the space allocated to it
785 * TRUE if it succeeded
789 static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, CACHEFILE_ENTRY * pEntry)
793 BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
795 /* update allocation table */
796 dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE;
797 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
798 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
800 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
804 /***********************************************************************
805 * URLCache_LocalFileNameToPathW (Internal)
807 * Copies the full path to the specified buffer given the local file
808 * name and the index of the directory it is in. Always sets value in
809 * lpBufferSize to the required buffer size (in bytes).
812 * TRUE if the buffer was big enough
813 * FALSE if the buffer was too small
816 static BOOL URLCache_LocalFileNameToPathW(
817 const URLCACHECONTAINER * pContainer,
818 LPCURLCACHE_HEADER pHeader,
819 LPCSTR szLocalFileName,
825 int path_len = strlenW(pContainer->path);
826 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
827 if (Directory >= pHeader->DirectoryCount)
833 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
834 if (nRequired < *lpBufferSize)
838 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
839 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
840 wszPath[dir_len + path_len] = '\\';
841 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
842 *lpBufferSize = nRequired;
845 *lpBufferSize = nRequired;
849 /***********************************************************************
850 * URLCache_LocalFileNameToPathA (Internal)
852 * Copies the full path to the specified buffer given the local file
853 * name and the index of the directory it is in. Always sets value in
854 * lpBufferSize to the required buffer size.
857 * TRUE if the buffer was big enough
858 * FALSE if the buffer was too small
861 static BOOL URLCache_LocalFileNameToPathA(
862 const URLCACHECONTAINER * pContainer,
863 LPCURLCACHE_HEADER pHeader,
864 LPCSTR szLocalFileName,
870 int path_len, file_name_len, dir_len;
872 if (Directory >= pHeader->DirectoryCount)
878 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL);
879 file_name_len = strlen(szLocalFileName);
880 dir_len = DIR_LENGTH;
882 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(WCHAR);
883 if (nRequired < *lpBufferSize)
885 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, -1, NULL, NULL);
886 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
887 szPath[path_len + dir_len] = '\\';
888 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
889 *lpBufferSize = nRequired;
892 *lpBufferSize = nRequired;
896 /***********************************************************************
897 * URLCache_CopyEntry (Internal)
899 * Copies an entry from the cache index file to the Win32 structure
902 * TRUE if the buffer was big enough
903 * FALSE if the buffer was too small
906 static BOOL URLCache_CopyEntry(
907 URLCACHECONTAINER * pContainer,
908 LPCURLCACHE_HEADER pHeader,
909 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
910 LPDWORD lpdwBufferSize,
911 URL_CACHEFILE_ENTRY * pUrlEntry,
915 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
917 if (*lpdwBufferSize >= dwRequiredSize)
919 lpCacheEntryInfo->lpHeaderInfo = NULL;
920 lpCacheEntryInfo->lpszFileExtension = NULL;
921 lpCacheEntryInfo->lpszLocalFileName = NULL;
922 lpCacheEntryInfo->lpszSourceUrlName = NULL;
923 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
924 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
925 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
926 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
927 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
928 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
929 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
930 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
931 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
932 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
933 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
934 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
935 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
936 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
939 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
940 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
941 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
943 lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0);
945 lenUrl = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
946 dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
948 /* FIXME: is source url optional? */
949 if (*lpdwBufferSize >= dwRequiredSize)
951 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrl - 1;
953 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
955 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, (lenUrl + 1) * sizeof(CHAR));
958 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
959 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
960 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
962 if (pUrlEntry->dwOffsetLocalName)
964 LONG nLocalFilePathSize;
965 LPSTR lpszLocalFileName;
966 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
967 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
968 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
969 URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize))
971 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
973 dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ;
975 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
976 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
977 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
979 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
981 if (*lpdwBufferSize >= dwRequiredSize)
983 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
984 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
985 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
987 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
988 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
989 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
991 if (dwRequiredSize > *lpdwBufferSize)
993 *lpdwBufferSize = dwRequiredSize;
994 SetLastError(ERROR_INSUFFICIENT_BUFFER);
997 *lpdwBufferSize = dwRequiredSize;
1002 /***********************************************************************
1003 * URLCache_SetEntryInfo (Internal)
1005 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1006 * according the the flags set by dwFieldControl.
1009 * TRUE if the buffer was big enough
1010 * FALSE if the buffer was too small
1013 static BOOL URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1015 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1016 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1017 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1018 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1019 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1020 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1021 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1022 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1023 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1024 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1025 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1026 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1027 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1028 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1029 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1030 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1035 /***********************************************************************
1036 * URLCache_HashKey (Internal)
1038 * Returns the hash key for a given string
1041 * hash key for the string
1044 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1046 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1047 * but the algorithm and result are not the same!
1049 static const unsigned char lookupTable[256] =
1051 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1052 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1053 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1054 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1055 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1056 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1057 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1058 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1059 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1060 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1061 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1062 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1063 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1064 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1065 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1066 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1067 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1068 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1069 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1070 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1071 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1072 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1073 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1074 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1075 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1076 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1077 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1078 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1079 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1080 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1081 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1082 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1086 int subscript[sizeof(key) / sizeof(key[0])];
1088 subscript[0] = *lpszKey;
1089 subscript[1] = (char)(*lpszKey + 1);
1090 subscript[2] = (char)(*lpszKey + 2);
1091 subscript[3] = (char)(*lpszKey + 3);
1093 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1094 key[i] = lookupTable[i];
1096 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
1098 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1099 key[i] = lookupTable[*lpszKey ^ key[i]];
1102 return *(DWORD *)key;
1105 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
1107 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
1110 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1112 /* structure of hash table:
1113 * 448 entries divided into 64 blocks
1114 * each block therefore contains a chain of 7 key/offset pairs
1115 * how position in table is calculated:
1116 * 1. the url is hashed in helper function
1117 * 2. the key % 64 * 8 is the offset
1118 * 3. the key in the hash table is the hash key aligned to 64
1121 * there can be multiple hash tables in the file and the offset to
1122 * the next one is stored in the header of the hash table
1124 DWORD key = URLCache_HashKey(lpszUrl);
1125 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1126 HASH_CACHEFILE_ENTRY * pHashEntry;
1127 DWORD dwHashTableNumber = 0;
1129 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1131 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1132 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1133 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1136 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1138 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1141 /* make sure that it is in fact a hash entry */
1142 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1144 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1148 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1150 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1151 if (key == (DWORD)(pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
1153 /* FIXME: we should make sure that this is the right element
1154 * before returning and claiming that it is. We can do this
1155 * by doing a simple compare between the URL we were given
1156 * and the URL stored in the entry. However, this assumes
1157 * we know the format of all the entries stored in the
1159 *ppHashEntry = pHashElement;
1167 /***********************************************************************
1168 * URLCache_FindEntryInHash (Internal)
1170 * Searches all the hash tables in the index for the given URL and
1171 * returns the entry, if it was found, in ppEntry
1174 * TRUE if the entry was found
1175 * FALSE if the entry could not be found
1178 static BOOL URLCache_FindEntryInHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, CACHEFILE_ENTRY ** ppEntry)
1180 struct _HASH_ENTRY * pHashEntry;
1181 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1183 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1189 /***********************************************************************
1190 * URLCache_HashEntrySetUse (Internal)
1192 * Searches all the hash tables in the index for the given URL and
1193 * sets the use count (stored or'ed with key)
1196 * TRUE if the entry was found
1197 * FALSE if the entry could not be found
1200 static BOOL URLCache_HashEntrySetUse(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwUseCount)
1202 struct _HASH_ENTRY * pHashEntry;
1203 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1205 pHashEntry->dwHashKey = dwUseCount | (DWORD)(pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1211 /***********************************************************************
1212 * URLCache_DeleteEntryFromHash (Internal)
1214 * Searches all the hash tables in the index for the given URL and
1215 * then if found deletes the entry.
1218 * TRUE if the entry was found
1219 * FALSE if the entry could not be found
1222 static BOOL URLCache_DeleteEntryFromHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl)
1224 struct _HASH_ENTRY * pHashEntry;
1225 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1227 pHashEntry->dwHashKey = HASHTABLE_FREE;
1228 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1234 /***********************************************************************
1235 * URLCache_AddEntryToHash (Internal)
1237 * Searches all the hash tables for a free slot based on the offset
1238 * generated from the hash key. If a free slot is found, the offset and
1239 * key are entered into the hash table.
1242 * TRUE if the entry was added
1243 * FALSE if the entry could not be added
1246 static BOOL URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1248 /* see URLCache_FindEntryInHash for structure of hash tables */
1250 DWORD key = URLCache_HashKey(lpszUrl);
1251 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1252 HASH_CACHEFILE_ENTRY * pHashEntry;
1253 DWORD dwHashTableNumber = 0;
1255 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1257 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1258 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1259 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1262 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1264 ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1267 /* make sure that it is in fact a hash entry */
1268 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1270 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1274 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1276 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1277 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1279 pHashElement->dwHashKey = key;
1280 pHashElement->dwOffsetEntry = dwOffsetEntry;
1285 pHashEntry = URLCache_CreateHashTable(pHeader, pHashEntry);
1289 pHashEntry->HashTable[offset].dwHashKey = key;
1290 pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry;
1294 static HASH_CACHEFILE_ENTRY *URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash)
1296 HASH_CACHEFILE_ENTRY *pHash;
1300 if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)&pHash))
1302 FIXME("no free space for hash table\n");
1303 SetLastError(ERROR_DISK_FULL);
1307 dwOffset = (BYTE *)pHash - (BYTE *)pHeader;
1310 pPrevHash->dwAddressNext = dwOffset;
1312 pHeader->dwOffsetFirstHashTable = dwOffset;
1313 pHash->CacheFileEntry.dwSignature = HASH_SIGNATURE;
1314 pHash->CacheFileEntry.dwBlocksUsed = 0x20;
1315 pHash->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0;
1316 for (i = 0; i < HASHTABLE_SIZE; i++)
1318 pHash->HashTable[i].dwOffsetEntry = 0;
1319 pHash->HashTable[i].dwHashKey = HASHTABLE_FREE;
1324 /***********************************************************************
1325 * GetUrlCacheEntryInfoExA (WININET.@)
1328 BOOL WINAPI GetUrlCacheEntryInfoExA(
1330 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1331 LPDWORD lpdwCacheEntryInfoBufSize,
1333 LPDWORD lpdwReserved,
1337 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1338 debugstr_a(lpszUrl),
1340 lpdwCacheEntryInfoBufSize,
1346 if ((lpszReserved != NULL) ||
1347 (lpdwReserved != NULL) ||
1348 (lpReserved != NULL))
1350 ERR("Reserved value was not 0\n");
1351 SetLastError(ERROR_INVALID_PARAMETER);
1355 FIXME("Undocumented flag(s): %x\n", dwFlags);
1356 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1359 /***********************************************************************
1360 * GetUrlCacheEntryInfoA (WININET.@)
1363 BOOL WINAPI GetUrlCacheEntryInfoA(
1364 IN LPCSTR lpszUrlName,
1365 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1366 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1369 LPURLCACHE_HEADER pHeader;
1370 CACHEFILE_ENTRY * pEntry;
1371 URL_CACHEFILE_ENTRY * pUrlEntry;
1372 URLCACHECONTAINER * pContainer;
1374 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1376 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1379 if (!URLCacheContainer_OpenIndex(pContainer))
1382 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1385 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1387 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1388 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1389 SetLastError(ERROR_FILE_NOT_FOUND);
1393 if (pEntry->dwSignature != URL_SIGNATURE)
1395 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1396 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1397 SetLastError(ERROR_FILE_NOT_FOUND);
1401 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1402 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1403 if (pUrlEntry->dwOffsetHeaderInfo)
1404 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1406 if (!URLCache_CopyEntry(
1410 lpdwCacheEntryInfoBufferSize,
1414 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1417 TRACE("Local File Name: %s\n", debugstr_a(lpCacheEntryInfo->lpszLocalFileName));
1419 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1424 /***********************************************************************
1425 * GetUrlCacheEntryInfoW (WININET.@)
1428 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1429 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1430 LPDWORD lpdwCacheEntryInfoBufferSize)
1432 LPURLCACHE_HEADER pHeader;
1433 CACHEFILE_ENTRY * pEntry;
1434 URL_CACHEFILE_ENTRY * pUrlEntry;
1435 URLCACHECONTAINER * pContainer;
1439 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1441 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1442 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1445 SetLastError(ERROR_OUTOFMEMORY);
1448 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1450 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1452 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1456 if (!URLCacheContainer_OpenIndex(pContainer))
1458 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1462 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1464 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1468 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1470 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1471 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1472 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1473 SetLastError(ERROR_FILE_NOT_FOUND);
1476 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1478 if (pEntry->dwSignature != URL_SIGNATURE)
1480 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1481 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1482 SetLastError(ERROR_FILE_NOT_FOUND);
1486 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1487 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1488 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1490 if (!URLCache_CopyEntry(
1493 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1494 lpdwCacheEntryInfoBufferSize,
1496 TRUE /* UNICODE */))
1498 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1501 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1503 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1508 /***********************************************************************
1509 * GetUrlCacheEntryInfoExW (WININET.@)
1512 BOOL WINAPI GetUrlCacheEntryInfoExW(
1514 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1515 LPDWORD lpdwCacheEntryInfoBufSize,
1516 LPWSTR lpszReserved,
1517 LPDWORD lpdwReserved,
1521 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1522 debugstr_w(lpszUrl),
1524 lpdwCacheEntryInfoBufSize,
1530 if ((lpszReserved != NULL) ||
1531 (lpdwReserved != NULL) ||
1532 (lpReserved != NULL))
1534 ERR("Reserved value was not 0\n");
1535 SetLastError(ERROR_INVALID_PARAMETER);
1539 FIXME("Undocumented flag(s): %x\n", dwFlags);
1540 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1543 /***********************************************************************
1544 * SetUrlCacheEntryInfoA (WININET.@)
1546 BOOL WINAPI SetUrlCacheEntryInfoA(
1548 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1549 DWORD dwFieldControl)
1551 LPURLCACHE_HEADER pHeader;
1552 CACHEFILE_ENTRY * pEntry;
1553 URLCACHECONTAINER * pContainer;
1555 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1557 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1560 if (!URLCacheContainer_OpenIndex(pContainer))
1563 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1566 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1568 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1569 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1570 SetLastError(ERROR_FILE_NOT_FOUND);
1574 if (pEntry->dwSignature != URL_SIGNATURE)
1576 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1577 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1578 SetLastError(ERROR_FILE_NOT_FOUND);
1582 URLCache_SetEntryInfo(
1583 (URL_CACHEFILE_ENTRY *)pEntry,
1584 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1587 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1592 /***********************************************************************
1593 * SetUrlCacheEntryInfoW (WININET.@)
1595 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1597 LPURLCACHE_HEADER pHeader;
1598 CACHEFILE_ENTRY * pEntry;
1599 URLCACHECONTAINER * pContainer;
1603 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1605 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1606 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1609 SetLastError(ERROR_OUTOFMEMORY);
1612 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1614 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1616 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1620 if (!URLCacheContainer_OpenIndex(pContainer))
1622 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1626 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1628 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1632 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1634 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1635 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1636 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1637 SetLastError(ERROR_FILE_NOT_FOUND);
1640 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1642 if (pEntry->dwSignature != URL_SIGNATURE)
1644 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1645 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1646 SetLastError(ERROR_FILE_NOT_FOUND);
1650 URLCache_SetEntryInfo(
1651 (URL_CACHEFILE_ENTRY *)pEntry,
1655 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1660 /***********************************************************************
1661 * RetrieveUrlCacheEntryFileA (WININET.@)
1664 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1665 IN LPCSTR lpszUrlName,
1666 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1667 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1671 LPURLCACHE_HEADER pHeader;
1672 CACHEFILE_ENTRY * pEntry;
1673 URL_CACHEFILE_ENTRY * pUrlEntry;
1674 URLCACHECONTAINER * pContainer;
1676 TRACE("(%s, %p, %p, 0x%08x)\n",
1677 debugstr_a(lpszUrlName),
1679 lpdwCacheEntryInfoBufferSize,
1682 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1685 if (!URLCacheContainer_OpenIndex(pContainer))
1688 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1691 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1693 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1694 TRACE("entry %s not found!\n", lpszUrlName);
1695 SetLastError(ERROR_FILE_NOT_FOUND);
1699 if (pEntry->dwSignature != URL_SIGNATURE)
1701 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1702 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1703 SetLastError(ERROR_FILE_NOT_FOUND);
1707 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1708 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1709 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1711 pUrlEntry->dwHitRate++;
1712 pUrlEntry->dwUseCount++;
1713 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1715 if (!URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize, pUrlEntry, FALSE))
1717 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1720 TRACE("Local File Name: %s\n", lpCacheEntryInfo->lpszLocalFileName);
1722 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1727 /***********************************************************************
1728 * RetrieveUrlCacheEntryFileW (WININET.@)
1731 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1732 IN LPCWSTR lpszUrlName,
1733 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1734 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1738 TRACE("(%s, %p, %p, 0x%08x)\n",
1739 debugstr_w(lpszUrlName),
1741 lpdwCacheEntryInfoBufferSize,
1747 /***********************************************************************
1748 * UnlockUrlCacheEntryFileA (WININET.@)
1751 BOOL WINAPI UnlockUrlCacheEntryFileA(
1752 IN LPCSTR lpszUrlName,
1756 LPURLCACHE_HEADER pHeader;
1757 CACHEFILE_ENTRY * pEntry;
1758 URL_CACHEFILE_ENTRY * pUrlEntry;
1759 URLCACHECONTAINER * pContainer;
1761 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
1765 ERR("dwReserved != 0\n");
1766 SetLastError(ERROR_INVALID_PARAMETER);
1770 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1773 if (!URLCacheContainer_OpenIndex(pContainer))
1776 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1779 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1781 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1782 TRACE("entry %s not found!\n", lpszUrlName);
1783 SetLastError(ERROR_FILE_NOT_FOUND);
1787 if (pEntry->dwSignature != URL_SIGNATURE)
1789 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1790 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1791 SetLastError(ERROR_FILE_NOT_FOUND);
1795 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1797 if (pUrlEntry->dwUseCount == 0)
1799 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1802 pUrlEntry->dwUseCount--;
1803 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1805 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1810 /***********************************************************************
1811 * UnlockUrlCacheEntryFileW (WININET.@)
1814 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
1816 FIXME("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
1820 /***********************************************************************
1821 * CreateUrlCacheEntryA (WININET.@)
1824 BOOL WINAPI CreateUrlCacheEntryA(
1825 IN LPCSTR lpszUrlName,
1826 IN DWORD dwExpectedFileSize,
1827 IN LPCSTR lpszFileExtension,
1828 OUT LPSTR lpszFileName,
1834 WCHAR *file_extension;
1835 WCHAR file_name[MAX_PATH];
1836 BOOL bSuccess = FALSE;
1839 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
1840 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
1842 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
1843 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 &&
1844 (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
1846 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
1847 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
1849 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
1855 dwError = GetLastError();
1860 dwError = GetLastError();
1862 HeapFree(GetProcessHeap(), 0, file_extension);
1866 dwError = GetLastError();
1868 HeapFree(GetProcessHeap(), 0, url_name);
1870 SetLastError(dwError);
1874 /***********************************************************************
1875 * CreateUrlCacheEntryW (WININET.@)
1878 BOOL WINAPI CreateUrlCacheEntryW(
1879 IN LPCWSTR lpszUrlName,
1880 IN DWORD dwExpectedFileSize,
1881 IN LPCWSTR lpszFileExtension,
1882 OUT LPWSTR lpszFileName,
1886 URLCACHECONTAINER * pContainer;
1887 LPURLCACHE_HEADER pHeader;
1888 CHAR szFile[MAX_PATH];
1889 WCHAR szExtension[MAX_PATH];
1890 LPCWSTR lpszUrlPart;
1892 LPCWSTR lpszFileNameExtension;
1893 LPWSTR lpszFileNameNoPath;
1895 int countnoextension;
1898 BOOL bFound = FALSE;
1900 static const WCHAR szWWW[] = {'w','w','w',0};
1902 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
1903 debugstr_w(lpszUrlName),
1905 debugstr_w(lpszFileExtension),
1911 ERR("dwReserved != 0\n");
1912 SetLastError(ERROR_INVALID_PARAMETER);
1916 for (lpszUrlEnd = lpszUrlName; *lpszUrlEnd; lpszUrlEnd++)
1919 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
1922 for (lpszUrlPart = lpszUrlEnd;
1923 (lpszUrlPart >= lpszUrlName);
1926 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
1933 if (!lstrcmpW(lpszUrlPart, szWWW))
1935 lpszUrlPart += lstrlenW(szWWW);
1938 count = lpszUrlEnd - lpszUrlPart;
1940 if (bFound && (count < MAX_PATH))
1942 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
1946 /* FIXME: get rid of illegal characters like \, / and : */
1950 FIXME("need to generate a random filename\n");
1953 TRACE("File name: %s\n", debugstr_a(szFile));
1955 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
1958 if (!URLCacheContainer_OpenIndex(pContainer))
1961 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1964 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
1966 lBufferSize = MAX_PATH * sizeof(WCHAR);
1967 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
1969 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1971 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
1972 lpszFileNameNoPath >= lpszFileName;
1973 --lpszFileNameNoPath)
1975 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
1979 countnoextension = lstrlenW(lpszFileNameNoPath);
1980 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
1981 if (lpszFileNameExtension)
1982 countnoextension -= lstrlenW(lpszFileNameExtension);
1983 *szExtension = '\0';
1985 if (lpszFileExtension)
1987 szExtension[0] = '.';
1988 lstrcpyW(szExtension+1, lpszFileExtension);
1991 for (i = 0; i < 255; i++)
1993 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
1995 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
1996 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
1997 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
1998 if (hFile != INVALID_HANDLE_VALUE)
2009 /***********************************************************************
2010 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2012 * The bug we are compensating for is that some drongo at Microsoft
2013 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2014 * As a consequence, CommitUrlCacheEntryA has been effectively
2015 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2016 * is still defined as LPCWSTR. The result (other than madness) is
2017 * that we always need to store lpHeaderInfo in CP_ACP rather than
2018 * in UTF16, and we need to avoid converting lpHeaderInfo in
2019 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2020 * result will lose data for arbitrary binary data.
2023 static BOOL WINAPI CommitUrlCacheEntryInternal(
2024 IN LPCWSTR lpszUrlName,
2025 IN LPCWSTR lpszLocalFileName,
2026 IN FILETIME ExpireTime,
2027 IN FILETIME LastModifiedTime,
2028 IN DWORD CacheEntryType,
2029 IN LPBYTE lpHeaderInfo,
2030 IN DWORD dwHeaderSize,
2031 IN LPCWSTR lpszFileExtension,
2032 IN LPCWSTR lpszOriginalUrl
2035 URLCACHECONTAINER * pContainer;
2036 LPURLCACHE_HEADER pHeader;
2037 CACHEFILE_ENTRY * pEntry;
2038 URL_CACHEFILE_ENTRY * pUrlEntry;
2039 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2040 DWORD dwOffsetLocalFileName = 0;
2041 DWORD dwOffsetHeader = 0;
2042 DWORD dwFileSizeLow = 0;
2043 DWORD dwFileSizeHigh = 0;
2044 BYTE cDirectory = 0;
2045 char achFile[MAX_PATH];
2046 char achUrl[MAX_PATH];
2047 char *pchLocalFileName = 0;
2049 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2050 debugstr_w(lpszUrlName),
2051 debugstr_w(lpszLocalFileName),
2055 debugstr_w(lpszFileExtension),
2056 debugstr_w(lpszOriginalUrl));
2058 if (lpszOriginalUrl)
2059 WARN(": lpszOriginalUrl ignored\n");
2061 if (lpszLocalFileName)
2065 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2066 if (hFile == INVALID_HANDLE_VALUE)
2068 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2073 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2074 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2076 ERR("couldn't get file size (error is %d)\n", GetLastError());
2084 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
2087 if (!URLCacheContainer_OpenIndex(pContainer))
2090 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2093 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, achUrl, -1, NULL, NULL);
2095 if (URLCache_FindEntryInHash(pHeader, achUrl, &pEntry))
2097 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2098 FIXME("entry already in cache - don't know what to do!\n");
2100 * SetLastError(ERROR_FILE_NOT_FOUND);
2106 if (lpszLocalFileName)
2108 BOOL bFound = FALSE;
2110 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2112 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2113 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2114 SetLastError(ERROR_INVALID_PARAMETER);
2118 /* skip container path prefix */
2119 lpszLocalFileName += lstrlenW(pContainer->path);
2121 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, -1, NULL, NULL);
2122 pchLocalFileName = achFile;
2124 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2126 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2135 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2136 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2137 SetLastError(ERROR_INVALID_PARAMETER);
2141 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2144 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(achUrl) + 1);
2145 if (lpszLocalFileName)
2147 dwOffsetLocalFileName = dwBytesNeeded;
2148 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2152 dwOffsetHeader = dwBytesNeeded;
2153 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2156 /* round up to next block */
2157 if (dwBytesNeeded % BLOCKSIZE)
2159 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2160 dwBytesNeeded += BLOCKSIZE;
2163 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2165 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2166 ERR("no free entries\n");
2167 SetLastError(ERROR_DISK_FULL);
2171 /* FindFirstFreeEntry fills in blocks used */
2172 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2173 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2174 pUrlEntry->CacheDir = cDirectory;
2175 pUrlEntry->CacheEntryType = CacheEntryType;
2176 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2177 pUrlEntry->dwExemptDelta = 0;
2178 pUrlEntry->dwHitRate = 0;
2179 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2180 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2181 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2182 pUrlEntry->dwSizeHigh = 0;
2183 pUrlEntry->dwSizeLow = dwFileSizeLow;
2184 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2185 pUrlEntry->dwUseCount = 0;
2186 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2187 pUrlEntry->LastModifiedTime = LastModifiedTime;
2188 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2189 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2190 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2191 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2194 pUrlEntry->dwUnknown1 = 0;
2195 pUrlEntry->dwUnknown2 = 0;
2196 pUrlEntry->dwUnknown3 = 0x60;
2197 pUrlEntry->Unknown4 = 0;
2198 pUrlEntry->wUnknown5 = 0x1010;
2199 pUrlEntry->dwUnknown6 = 0;
2200 pUrlEntry->dwUnknown7 = 0;
2201 pUrlEntry->dwUnknown8 = 0;
2204 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, achUrl);
2205 if (dwOffsetLocalFileName)
2206 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2208 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2210 if (!URLCache_AddEntryToHash(pHeader, achUrl, (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader)))
2212 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2213 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2217 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2222 /***********************************************************************
2223 * CommitUrlCacheEntryA (WININET.@)
2226 BOOL WINAPI CommitUrlCacheEntryA(
2227 IN LPCSTR lpszUrlName,
2228 IN LPCSTR lpszLocalFileName,
2229 IN FILETIME ExpireTime,
2230 IN FILETIME LastModifiedTime,
2231 IN DWORD CacheEntryType,
2232 IN LPBYTE lpHeaderInfo,
2233 IN DWORD dwHeaderSize,
2234 IN LPCSTR lpszFileExtension,
2235 IN LPCSTR lpszOriginalUrl
2240 WCHAR *local_file_name;
2241 WCHAR *original_url = NULL;
2242 BOOL bSuccess = FALSE;
2245 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2246 debugstr_a(lpszUrlName),
2247 debugstr_a(lpszLocalFileName),
2251 debugstr_a(lpszFileExtension),
2252 debugstr_a(lpszOriginalUrl));
2254 if (lpszFileExtension != 0)
2256 SetLastError(ERROR_INVALID_PARAMETER);
2259 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
2260 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2262 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2263 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0)) != 0 &&
2264 (local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2266 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2267 if (!lpszOriginalUrl ||
2268 ((len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0)) != 0 &&
2269 (original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0))
2272 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2273 if (CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2274 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2275 NULL, original_url))
2281 dwError = GetLastError();
2283 HeapFree(GetProcessHeap(), 0, original_url);
2287 dwError = GetLastError();
2289 HeapFree(GetProcessHeap(), 0, local_file_name);
2293 dwError = GetLastError();
2295 HeapFree(GetProcessHeap(), 0, url_name);
2297 SetLastError(dwError);
2302 /***********************************************************************
2303 * CommitUrlCacheEntryW (WININET.@)
2306 BOOL WINAPI CommitUrlCacheEntryW(
2307 IN LPCWSTR lpszUrlName,
2308 IN LPCWSTR lpszLocalFileName,
2309 IN FILETIME ExpireTime,
2310 IN FILETIME LastModifiedTime,
2311 IN DWORD CacheEntryType,
2312 IN LPWSTR lpHeaderInfo,
2313 IN DWORD dwHeaderSize,
2314 IN LPCWSTR lpszFileExtension,
2315 IN LPCWSTR lpszOriginalUrl
2319 BOOL bSuccess = FALSE;
2321 CHAR *header_info = NULL;
2323 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2324 debugstr_w(lpszUrlName),
2325 debugstr_w(lpszLocalFileName),
2329 debugstr_w(lpszFileExtension),
2330 debugstr_w(lpszOriginalUrl));
2332 if (!lpHeaderInfo ||
2333 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2334 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2337 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2338 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2339 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2345 dwError = GetLastError();
2349 HeapFree(GetProcessHeap(), 0, header_info);
2351 SetLastError(dwError);
2357 /***********************************************************************
2358 * ReadUrlCacheEntryStream (WININET.@)
2361 BOOL WINAPI ReadUrlCacheEntryStream(
2362 IN HANDLE hUrlCacheStream,
2363 IN DWORD dwLocation,
2364 IN OUT LPVOID lpBuffer,
2365 IN OUT LPDWORD lpdwLen,
2369 /* Get handle to file from 'stream' */
2370 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2372 if (dwReserved != 0)
2374 ERR("dwReserved != 0\n");
2375 SetLastError(ERROR_INVALID_PARAMETER);
2379 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2381 SetLastError(ERROR_INVALID_HANDLE);
2385 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2387 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2390 /***********************************************************************
2391 * RetrieveUrlCacheEntryStreamA (WININET.@)
2394 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2395 IN LPCSTR lpszUrlName,
2396 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2397 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2398 IN BOOL fRandomRead,
2402 /* NOTE: this is not the same as the way that the native
2403 * version allocates 'stream' handles. I did it this way
2404 * as it is much easier and no applications should depend
2405 * on this behaviour. (Native version appears to allocate
2406 * indices into a table)
2408 STREAM_HANDLE * pStream;
2411 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2412 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2414 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2416 lpdwCacheEntryInfoBufferSize,
2422 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2427 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2429 if (hFile == INVALID_HANDLE_VALUE)
2432 /* allocate handle storage space */
2433 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2437 SetLastError(ERROR_OUTOFMEMORY);
2441 pStream->hFile = hFile;
2442 strcpy(pStream->lpszUrl, lpszUrlName);
2443 return (HANDLE)pStream;
2446 /***********************************************************************
2447 * RetrieveUrlCacheEntryStreamW (WININET.@)
2450 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2451 IN LPCWSTR lpszUrlName,
2452 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2453 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2454 IN BOOL fRandomRead,
2458 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2459 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2463 /***********************************************************************
2464 * UnlockUrlCacheEntryStream (WININET.@)
2467 BOOL WINAPI UnlockUrlCacheEntryStream(
2468 IN HANDLE hUrlCacheStream,
2472 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2474 if (dwReserved != 0)
2476 ERR("dwReserved != 0\n");
2477 SetLastError(ERROR_INVALID_PARAMETER);
2481 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2483 SetLastError(ERROR_INVALID_HANDLE);
2487 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2490 /* close file handle */
2491 CloseHandle(pStream->hFile);
2493 /* free allocated space */
2494 HeapFree(GetProcessHeap(), 0, pStream);
2500 /***********************************************************************
2501 * DeleteUrlCacheEntryA (WININET.@)
2504 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2506 URLCACHECONTAINER * pContainer;
2507 LPURLCACHE_HEADER pHeader;
2508 CACHEFILE_ENTRY * pEntry;
2510 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2512 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
2515 if (!URLCacheContainer_OpenIndex(pContainer))
2518 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2521 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
2523 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2524 TRACE("entry %s not found!\n", lpszUrlName);
2525 SetLastError(ERROR_FILE_NOT_FOUND);
2529 URLCache_DeleteEntry(pHeader, pEntry);
2531 URLCache_DeleteEntryFromHash(pHeader, lpszUrlName);
2533 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2538 /***********************************************************************
2539 * DeleteUrlCacheEntryW (WININET.@)
2542 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2544 FIXME("(%s) stub\n", debugstr_w(lpszUrlName));
2548 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2550 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2554 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2556 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2560 /***********************************************************************
2561 * CreateCacheContainerA (WININET.@)
2563 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2564 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2566 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2567 d1, d2, d3, d4, d5, d6, d7, d8);
2571 /***********************************************************************
2572 * CreateCacheContainerW (WININET.@)
2574 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2575 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2577 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2578 d1, d2, d3, d4, d5, d6, d7, d8);
2582 /***********************************************************************
2583 * FindCloseUrlCache (WININET.@)
2585 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
2587 FIXME("(%p) stub\n", hEnumHandle);
2591 /***********************************************************************
2592 * FindFirstUrlCacheContainerA (WININET.@)
2594 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2596 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
2600 /***********************************************************************
2601 * FindFirstUrlCacheContainerW (WININET.@)
2603 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2605 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
2609 /***********************************************************************
2610 * FindNextUrlCacheContainerA (WININET.@)
2612 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
2614 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2618 /***********************************************************************
2619 * FindNextUrlCacheContainerW (WININET.@)
2621 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
2623 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2627 HANDLE WINAPI FindFirstUrlCacheEntryExA(
2628 LPCSTR lpszUrlSearchPattern,
2632 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2633 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2635 LPDWORD pcbReserved2,
2639 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
2640 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2641 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2642 SetLastError(ERROR_FILE_NOT_FOUND);
2646 HANDLE WINAPI FindFirstUrlCacheEntryExW(
2647 LPCWSTR lpszUrlSearchPattern,
2651 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2652 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2654 LPDWORD pcbReserved2,
2658 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
2659 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2660 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2661 SetLastError(ERROR_FILE_NOT_FOUND);
2665 /***********************************************************************
2666 * FindFirstUrlCacheEntryA (WININET.@)
2669 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
2670 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2672 FIXME("(%s, %p, %p): stub\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2673 SetLastError(ERROR_FILE_NOT_FOUND);
2677 /***********************************************************************
2678 * FindFirstUrlCacheEntryW (WININET.@)
2681 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
2682 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2684 FIXME("(%s, %p, %p): stub\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2688 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
2689 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
2691 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
2692 dwSearchCondition, lpGroupId, lpReserved);
2696 BOOL WINAPI FindNextUrlCacheEntryA(
2698 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
2699 LPDWORD lpdwNextCacheEntryInfoBufferSize
2702 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2706 BOOL WINAPI FindNextUrlCacheEntryW(
2708 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
2709 LPDWORD lpdwNextCacheEntryInfoBufferSize
2712 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2716 BOOL WINAPI FindNextUrlCacheEntryExA(
2718 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2719 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2721 LPDWORD pcbReserved2,
2725 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2726 lpReserved, pcbReserved2, lpReserved3);
2730 BOOL WINAPI FindNextUrlCacheEntryExW(
2732 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2733 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2735 LPDWORD pcbReserved2,
2739 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2740 lpReserved, pcbReserved2, lpReserved3);
2744 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
2746 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
2750 /***********************************************************************
2751 * CreateUrlCacheGroup (WININET.@)
2754 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
2756 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
2760 /***********************************************************************
2761 * DeleteUrlCacheGroup (WININET.@)
2764 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
2766 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
2767 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
2771 /***********************************************************************
2772 * SetUrlCacheEntryGroupA (WININET.@)
2775 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
2776 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2779 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
2780 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2781 pbGroupAttributes, cbGroupAttributes, lpReserved);
2782 SetLastError(ERROR_FILE_NOT_FOUND);
2786 /***********************************************************************
2787 * SetUrlCacheEntryGroupW (WININET.@)
2790 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
2791 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2794 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
2795 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2796 pbGroupAttributes, cbGroupAttributes, lpReserved);
2797 SetLastError(ERROR_FILE_NOT_FOUND);
2801 /***********************************************************************
2802 * GetUrlCacheConfigInfoW (WININET.@)
2804 BOOL WINAPI GetUrlCacheConfigInfoW(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2806 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
2807 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2811 /***********************************************************************
2812 * GetUrlCacheConfigInfoA (WININET.@)
2814 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
2816 BOOL WINAPI GetUrlCacheConfigInfoA(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2818 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
2819 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2823 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2824 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
2825 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2827 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
2828 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2829 lpdwGroupInfo, lpReserved);
2833 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2834 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
2835 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2837 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
2838 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2839 lpdwGroupInfo, lpReserved);
2843 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2844 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
2846 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
2847 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2851 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2852 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
2854 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
2855 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2859 BOOL WINAPI SetUrlCacheConfigInfoA( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2861 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
2865 BOOL WINAPI SetUrlCacheConfigInfoW( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2867 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
2871 /***********************************************************************
2872 * DeleteIE3Cache (WININET.@)
2874 * Deletes the files used by the IE3 URL caching system.
2877 * hWnd [I] A dummy window.
2878 * hInst [I] Instance of process calling the function.
2879 * lpszCmdLine [I] Options used by function.
2880 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
2885 void WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
2887 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);