2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003 Robert Shearman
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #define COM_NO_WINDOWS_H
27 #include "wine/port.h"
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
49 #include "wine/unicode.h"
50 #include "wine/list.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
55 #define ENTRY_START_OFFSET 0x4000
58 #define HASHTABLE_SIZE 448
59 #define HASHTABLE_BLOCKSIZE 7
60 #define HASHTABLE_FREE 3
61 #define ALLOCATION_TABLE_OFFSET 0x250
62 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
63 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
64 #define NEWFILE_NUM_BLOCKS 0xd80
65 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
67 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
68 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
69 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
70 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
71 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
73 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
75 typedef struct _CACHEFILE_ENTRY
79 DWORD dwSignature; /* e.g. "URL " */
80 /* CHAR szSignature[4];
82 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
85 typedef struct _URL_CACHEFILE_ENTRY
87 CACHEFILE_ENTRY CacheFileEntry;
88 FILETIME LastModifiedTime;
89 FILETIME LastAccessTime;
90 WORD wExpiredDate; /* expire date in dos format */
91 WORD wExpiredTime; /* expire time in dos format */
92 DWORD dwUnknown1; /* usually zero */
93 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
94 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
95 DWORD dwUnknown2; /* usually zero */
96 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
97 DWORD dwUnknown3; /* usually 0x60 */
98 DWORD dwOffsetUrl; /* offset of start of url from start of entry */
99 BYTE CacheDir; /* index of cache directory this url is stored in */
100 BYTE Unknown4; /* usually zero */
101 WORD wUnknown5; /* usually 0x1010 */
102 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
103 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
104 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
105 DWORD dwHeaderInfoSize;
106 DWORD dwUnknown6; /* usually zero */
107 WORD wLastSyncDate; /* last sync date in dos format */
108 WORD wLastSyncTime; /* last sync time in dos format */
109 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
110 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
111 WORD wUnknownDate; /* usually same as wLastSyncDate */
112 WORD wUnknownTime; /* usually same as wLastSyncTime */
113 DWORD dwUnknown7; /* usually zero */
114 DWORD dwUnknown8; /* usually zero */
115 /* packing to dword align start of next field */
116 /* CHAR szSourceUrlName[]; (url) */
117 /* packing to dword align start of next field */
118 /* CHAR szLocalFileName[]; (local file name exluding path) */
119 /* packing to dword align start of next field */
120 /* CHAR szHeaderInfo[]; (header info) */
121 } URL_CACHEFILE_ENTRY;
129 typedef struct _HASH_CACHEFILE_ENTRY
131 CACHEFILE_ENTRY CacheFileEntry;
133 DWORD dwHashTableNumber;
134 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
135 } HASH_CACHEFILE_ENTRY;
137 typedef struct _DIRECTORY_DATA
140 char filename[DIR_LENGTH];
143 typedef struct _URLCACHE_HEADER
145 char szSignature[28];
147 DWORD dwOffsetFirstHashTable;
148 DWORD dwIndexCapacityInBlocks;
151 DWORD dwCacheLimitLow; /* disk space limit for cache */
152 DWORD dwCacheLimitHigh; /* disk space limit for cache */
153 DWORD dwUnknown4; /* current disk space usage for cache */
154 DWORD dwUnknown5; /* current disk space usage for cache */
155 DWORD dwUnknown6; /* possibly a flag? */
157 BYTE DirectoryCount; /* number of directory_data's */
158 BYTE Unknown8[3]; /* just padding? */
159 DIRECTORY_DATA directory_data[1]; /* first directory entry */
160 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
161 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
163 typedef struct _STREAM_HANDLE
169 typedef struct _URLCACHECONTAINER
171 struct list entry; /* part of a list */
172 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
173 LPWSTR path; /* path to url container directory */
174 HANDLE hMapping; /* handle of file mapping */
175 DWORD file_size; /* size of file when mapping was opened */
176 HANDLE hMutex; /* hande of mutex */
180 /* List of all containers available */
181 static struct list UrlContainers = LIST_INIT(UrlContainers);
183 static HASH_CACHEFILE_ENTRY *URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash);
185 /***********************************************************************
186 * URLCache_PathToObjectName (Internal)
188 * Converts a path to a name suitable for use as a Win32 object name.
189 * Replaces '\\' characters in-place with the specified character
190 * (usually '_' or '!')
196 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
198 for (; *lpszPath; lpszPath++)
200 if (*lpszPath == '\\')
205 /***********************************************************************
206 * URLCacheContainer_OpenIndex (Internal)
208 * Opens the index file and saves mapping handle in hCacheIndexMapping
215 static BOOL URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
218 WCHAR wszFilePath[MAX_PATH];
221 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
222 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
224 if (pContainer->hMapping)
227 strcpyW(wszFilePath, pContainer->path);
228 strcatW(wszFilePath, wszIndex);
230 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
231 if (hFile == INVALID_HANDLE_VALUE)
233 /* Maybe the directory wasn't there? Try to create it */
234 if (CreateDirectoryW(pContainer->path, 0))
235 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
237 if (hFile == INVALID_HANDLE_VALUE)
239 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath));
243 /* At this stage we need the mutex because we may be about to create the
246 WaitForSingleObject(pContainer->hMutex, INFINITE);
248 dwFileSize = GetFileSize(hFile, NULL);
249 if (dwFileSize == INVALID_FILE_SIZE)
251 ReleaseMutex(pContainer->hMutex);
257 static CHAR const szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Cache\\Content";
259 char achZeroes[0x1000];
263 /* Write zeroes to the entire file so we can safely map it without
264 * fear of getting a SEGV because the disk is full.
266 memset(achZeroes, 0, sizeof(achZeroes));
267 for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes))
269 DWORD dwWrite = sizeof(achZeroes);
272 if (NEWFILE_SIZE - dwOffset < dwWrite)
273 dwWrite = NEWFILE_SIZE - dwOffset;
274 if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) ||
275 dwWritten != dwWrite)
277 /* If we fail to write, we need to return the error that
278 * cause the problem and also make sure the file is no
279 * longer there, if possible.
281 dwError = GetLastError();
289 HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL);
293 URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE);
298 WCHAR wszDirPath[MAX_PATH];
302 dwFileSize = NEWFILE_SIZE;
304 /* First set some constants and defaults in the header */
305 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
306 pHeader->dwFileSize = dwFileSize;
307 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
308 /* 127MB - taken from default for Windows 2000 */
309 pHeader->dwCacheLimitHigh = 0;
310 pHeader->dwCacheLimitLow = 0x07ff5400;
311 /* Copied from a Windows 2000 cache index */
312 pHeader->DirectoryCount = 4;
314 /* If the registry has a cache size set, use the registry value */
315 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
318 DWORD len = sizeof(dw);
321 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
322 (BYTE *) &dw, &len) == ERROR_SUCCESS &&
323 keytype == REG_DWORD)
325 pHeader->dwCacheLimitHigh = (dw >> 22);
326 pHeader->dwCacheLimitLow = dw << 10;
331 URLCache_CreateHashTable(pHeader, NULL);
333 /* Last step - create the directories */
335 strcpyW(wszDirPath, pContainer->path);
336 pwchDir = wszDirPath + strlenW(wszDirPath);
339 GetSystemTimeAsFileTime(&ft);
341 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
343 /* The following values were copied from a Windows index.
344 * I don't know what the values are supposed to mean but
345 * have made them the same in the hope that this will
346 * be better for compatibility
348 pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
352 ULONGLONG n = ft.dwHighDateTime;
354 /* Generate a file name to attempt to create.
355 * This algorithm will create what will appear
356 * to be random and unrelated directory names
357 * of up to 9 characters in length.
360 n += ft.dwLowDateTime;
361 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
363 for (k = 0; k < 8; ++k)
367 /* Dividing by a prime greater than 36 helps
368 * with the appearance of randomness
373 pwchDir[k] = '0' + r;
375 pwchDir[k] = 'A' + (r - 10);
378 if (CreateDirectoryW(wszDirPath, 0))
382 /* The following is OK because we generated an
383 * 8 character directory name made from characters
384 * [A-Z0-9], which are equivalent for all code
385 * pages and for UTF-16
387 for (k = 0; k < 8; ++k)
388 pHeader->directory_data[i].filename[k] = pwchDir[k];
393 /* Give up. The most likely cause of this
394 * is a full disk, but whatever the cause
395 * is, it should be more than apparent that
398 dwError = GetLastError();
404 UnmapViewOfFile(pHeader);
408 dwError = GetLastError();
410 CloseHandle(hMapping);
414 dwError = GetLastError();
421 DeleteFileW(wszFilePath);
422 ReleaseMutex(pContainer->hMutex);
423 SetLastError(dwError);
429 ReleaseMutex(pContainer->hMutex);
431 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
432 URLCache_PathToObjectName(wszFilePath, '_');
433 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
434 if (!pContainer->hMapping)
435 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
437 if (!pContainer->hMapping)
439 ERR("Couldn't create file mapping (error is %ld)\n", GetLastError());
446 /***********************************************************************
447 * URLCacheContainer_CloseIndex (Internal)
455 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
457 CloseHandle(pContainer->hMapping);
458 pContainer->hMapping = NULL;
461 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
463 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
464 int path_len = strlenW(path);
465 int cache_prefix_len = strlenW(cache_prefix);
472 pContainer->hMapping = NULL;
473 pContainer->file_size = 0;
475 pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR));
476 if (!pContainer->path)
478 HeapFree(GetProcessHeap(), 0, pContainer);
482 memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR));
484 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
485 if (!pContainer->cache_prefix)
487 HeapFree(GetProcessHeap(), 0, pContainer->path);
488 HeapFree(GetProcessHeap(), 0, pContainer);
492 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
494 CharLowerW(mutex_name);
495 URLCache_PathToObjectName(mutex_name, '!');
497 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
499 ERR("couldn't create mutex (error is %ld)\n", GetLastError());
500 HeapFree(GetProcessHeap(), 0, pContainer->path);
501 HeapFree(GetProcessHeap(), 0, pContainer);
505 list_add_head(&UrlContainers, &pContainer->entry);
510 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
512 list_remove(&pContainer->entry);
514 URLCacheContainer_CloseIndex(pContainer);
515 CloseHandle(pContainer->hMutex);
516 HeapFree(GetProcessHeap(), 0, pContainer->path);
517 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
518 HeapFree(GetProcessHeap(), 0, pContainer);
521 void URLCacheContainers_CreateDefaults(void)
523 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
524 static const WCHAR UrlPrefix[] = {0};
525 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
526 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
527 static const WCHAR CookieSuffix[] = {0};
528 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
531 int nFolder; /* CSIDL_* constant */
532 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
533 const WCHAR * cache_prefix; /* prefix used to reference the container */
534 } DefaultContainerData[] =
536 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
537 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
538 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
542 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
544 WCHAR wszCachePath[MAX_PATH];
545 WCHAR wszMutexName[MAX_PATH];
546 int path_len, suffix_len;
548 if (FAILED(SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE)))
550 ERR("Couldn't get path for default container %lu\n", i);
553 path_len = strlenW(wszCachePath);
554 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
556 if (path_len + suffix_len + 2 > MAX_PATH)
558 ERR("Path too long\n");
562 wszCachePath[path_len] = '\\';
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: %ld\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: %ld\n", GetLastError());
664 pHeader = (URLCACHE_HEADER *)pIndexData;
667 TRACE("Signature: %s, file size: %ld 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. %ld (0x%lx)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
764 if (dwFreeCounter == dwBlocksNeeded)
767 TRACE("Found free blocks starting at no. %ld (0x%lx)\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 (%ld) expected %ld\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 (%ld) expected %ld\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, %lx)\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): %lx\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, %lx)\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): %lx\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%08lx)\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%08lx)\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%08lx)\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%08lx)\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%08lx)\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%08lx)\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%08lx, %s, %p, 0x%08lx)\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, ..., ..., %lx, %p, %ld, %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 %ld)\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 %ld)\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);
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, ..., ..., %lx, %p, %ld, %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, ..., ..., %lx, %p, %ld, %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%08lx)\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%08lx)\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%08lx, 0x%08lx) stub\n", d1, d2);
2554 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2556 FIXME("(0x%08lx, 0x%08lx) 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%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) 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%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) 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%08lx) 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%08lx) 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%08lx, 0x%08lx, 0x%08lx%08lx, %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%08lx, 0x%08lx, 0x%08lx%08lx, %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%08lx, 0x%08lx, %p, 0x%08lx, %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%08lx, %p): stub\n", dwFlags, lpReserved);
2760 /***********************************************************************
2761 * DeleteUrlCacheGroup (WININET.@)
2764 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
2766 FIXME("(0x%08lx%08lx, 0x%08lx, %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%08lx, 0x%08lx%08lx, %p, 0x%08lx, %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%08lx, 0x%08lx%08lx, %p, 0x%08lx, %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, %lx)\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, %lx)\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%08lx%08lx, 0x%08lx, 0x%08lx, %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%08lx%08lx, 0x%08lx, 0x%08lx, %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%08lx%08lx, 0x%08lx, 0x%08lx, %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%08lx%08lx, 0x%08lx, 0x%08lx, %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%08lx) stub\n", lpCacheConfigInfo, dwFieldControl);
2865 BOOL WINAPI SetUrlCacheConfigInfoW( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2867 FIXME("(%p, 0x%08lx) 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);