2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003 Robert Shearman
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #define COM_NO_WINDOWS_H
27 #include "wine/port.h"
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
49 #include "wine/unicode.h"
50 #include "wine/list.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
55 #define ENTRY_START_OFFSET 0x4000
58 #define HASHTABLE_SIZE 448
59 #define HASHTABLE_BLOCKSIZE 7
60 #define HASHTABLE_FREE 3
61 #define ALLOCATION_TABLE_OFFSET 0x250
62 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
63 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
64 #define NEWFILE_NUM_BLOCKS 0xd80
65 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
67 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
68 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
69 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
70 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
71 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
73 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
75 typedef struct _CACHEFILE_ENTRY
79 DWORD dwSignature; /* e.g. "URL " */
80 /* CHAR szSignature[4];
82 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
85 typedef struct _URL_CACHEFILE_ENTRY
87 CACHEFILE_ENTRY CacheFileEntry;
88 FILETIME LastModifiedTime;
89 FILETIME LastAccessTime;
90 WORD wExpiredDate; /* expire date in dos format */
91 WORD wExpiredTime; /* expire time in dos format */
92 DWORD dwUnknown1; /* usually zero */
93 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
94 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
95 DWORD dwUnknown2; /* usually zero */
96 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
97 DWORD dwUnknown3; /* usually 0x60 */
98 DWORD dwOffsetUrl; /* 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 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 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();
2284 HeapFree(GetProcessHeap(), 0, original_url);
2288 dwError = GetLastError();
2290 HeapFree(GetProcessHeap(), 0, local_file_name);
2294 dwError = GetLastError();
2296 HeapFree(GetProcessHeap(), 0, url_name);
2298 SetLastError(dwError);
2303 /***********************************************************************
2304 * CommitUrlCacheEntryW (WININET.@)
2307 BOOL WINAPI CommitUrlCacheEntryW(
2308 IN LPCWSTR lpszUrlName,
2309 IN LPCWSTR lpszLocalFileName,
2310 IN FILETIME ExpireTime,
2311 IN FILETIME LastModifiedTime,
2312 IN DWORD CacheEntryType,
2313 IN LPWSTR lpHeaderInfo,
2314 IN DWORD dwHeaderSize,
2315 IN LPCWSTR lpszFileExtension,
2316 IN LPCWSTR lpszOriginalUrl
2320 BOOL bSuccess = FALSE;
2322 CHAR *header_info = NULL;
2324 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %s)\n",
2325 debugstr_w(lpszUrlName),
2326 debugstr_w(lpszLocalFileName),
2330 debugstr_w(lpszFileExtension),
2331 debugstr_w(lpszOriginalUrl));
2333 if (!lpHeaderInfo ||
2334 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2335 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2338 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2339 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2340 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2346 dwError = GetLastError();
2350 HeapFree(GetProcessHeap(), 0, header_info);
2352 SetLastError(dwError);
2358 /***********************************************************************
2359 * ReadUrlCacheEntryStream (WININET.@)
2362 BOOL WINAPI ReadUrlCacheEntryStream(
2363 IN HANDLE hUrlCacheStream,
2364 IN DWORD dwLocation,
2365 IN OUT LPVOID lpBuffer,
2366 IN OUT LPDWORD lpdwLen,
2370 /* Get handle to file from 'stream' */
2371 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2373 if (dwReserved != 0)
2375 ERR("dwReserved != 0\n");
2376 SetLastError(ERROR_INVALID_PARAMETER);
2380 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2382 SetLastError(ERROR_INVALID_HANDLE);
2386 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2388 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2391 /***********************************************************************
2392 * RetrieveUrlCacheEntryStreamA (WININET.@)
2395 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2396 IN LPCSTR lpszUrlName,
2397 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2398 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2399 IN BOOL fRandomRead,
2403 /* NOTE: this is not the same as the way that the native
2404 * version allocates 'stream' handles. I did it this way
2405 * as it is much easier and no applications should depend
2406 * on this behaviour. (Native version appears to allocate
2407 * indices into a table)
2409 STREAM_HANDLE * pStream;
2412 TRACE( "(%s, %p, %p, %x, 0x%08lx)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2413 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2415 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2417 lpdwCacheEntryInfoBufferSize,
2423 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2428 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2430 if (hFile == INVALID_HANDLE_VALUE)
2433 /* allocate handle storage space */
2434 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2438 SetLastError(ERROR_OUTOFMEMORY);
2442 pStream->hFile = hFile;
2443 strcpy(pStream->lpszUrl, lpszUrlName);
2444 return (HANDLE)pStream;
2447 /***********************************************************************
2448 * RetrieveUrlCacheEntryStreamW (WININET.@)
2451 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2452 IN LPCWSTR lpszUrlName,
2453 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2454 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2455 IN BOOL fRandomRead,
2459 FIXME( "(%s, %p, %p, %x, 0x%08lx)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2460 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2464 /***********************************************************************
2465 * UnlockUrlCacheEntryStream (WININET.@)
2468 BOOL WINAPI UnlockUrlCacheEntryStream(
2469 IN HANDLE hUrlCacheStream,
2473 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2475 if (dwReserved != 0)
2477 ERR("dwReserved != 0\n");
2478 SetLastError(ERROR_INVALID_PARAMETER);
2482 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2484 SetLastError(ERROR_INVALID_HANDLE);
2488 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2491 /* close file handle */
2492 CloseHandle(pStream->hFile);
2494 /* free allocated space */
2495 HeapFree(GetProcessHeap(), 0, pStream);
2501 /***********************************************************************
2502 * DeleteUrlCacheEntryA (WININET.@)
2505 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2507 URLCACHECONTAINER * pContainer;
2508 LPURLCACHE_HEADER pHeader;
2509 CACHEFILE_ENTRY * pEntry;
2511 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2513 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
2516 if (!URLCacheContainer_OpenIndex(pContainer))
2519 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2522 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
2524 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2525 TRACE("entry %s not found!\n", lpszUrlName);
2526 SetLastError(ERROR_FILE_NOT_FOUND);
2530 URLCache_DeleteEntry(pHeader, pEntry);
2532 URLCache_DeleteEntryFromHash(pHeader, lpszUrlName);
2534 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2539 /***********************************************************************
2540 * DeleteUrlCacheEntryW (WININET.@)
2543 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2545 FIXME("(%s) stub\n", debugstr_w(lpszUrlName));
2549 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2551 FIXME("(0x%08lx, 0x%08lx) stub\n", d1, d2);
2555 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2557 FIXME("(0x%08lx, 0x%08lx) stub\n", d1, d2);
2561 /***********************************************************************
2562 * CreateCacheContainerA (WININET.@)
2564 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2565 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2567 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) stub\n",
2568 d1, d2, d3, d4, d5, d6, d7, d8);
2572 /***********************************************************************
2573 * CreateCacheContainerW (WININET.@)
2575 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2576 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2578 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) stub\n",
2579 d1, d2, d3, d4, d5, d6, d7, d8);
2583 /***********************************************************************
2584 * FindCloseUrlCache (WININET.@)
2586 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
2588 FIXME("(%p) stub\n", hEnumHandle);
2592 /***********************************************************************
2593 * FindFirstUrlCacheContainerA (WININET.@)
2595 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2597 FIXME("(%p, %p, %p, 0x%08lx) stub\n", p1, p2, p3, d1 );
2601 /***********************************************************************
2602 * FindFirstUrlCacheContainerW (WININET.@)
2604 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2606 FIXME("(%p, %p, %p, 0x%08lx) stub\n", p1, p2, p3, d1 );
2610 /***********************************************************************
2611 * FindNextUrlCacheContainerA (WININET.@)
2613 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
2615 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2619 /***********************************************************************
2620 * FindNextUrlCacheContainerW (WININET.@)
2622 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
2624 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2628 HANDLE WINAPI FindFirstUrlCacheEntryExA(
2629 LPCSTR lpszUrlSearchPattern,
2633 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2634 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2636 LPDWORD pcbReserved2,
2640 FIXME("(%s, 0x%08lx, 0x%08lx, 0x%08lx%08lx, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
2641 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2642 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2643 SetLastError(ERROR_FILE_NOT_FOUND);
2647 HANDLE WINAPI FindFirstUrlCacheEntryExW(
2648 LPCWSTR lpszUrlSearchPattern,
2652 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2653 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2655 LPDWORD pcbReserved2,
2659 FIXME("(%s, 0x%08lx, 0x%08lx, 0x%08lx%08lx, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
2660 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2661 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2662 SetLastError(ERROR_FILE_NOT_FOUND);
2666 /***********************************************************************
2667 * FindFirstUrlCacheEntryA (WININET.@)
2670 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
2671 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2673 FIXME("(%s, %p, %p): stub\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2674 SetLastError(ERROR_FILE_NOT_FOUND);
2678 /***********************************************************************
2679 * FindFirstUrlCacheEntryW (WININET.@)
2682 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
2683 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2685 FIXME("(%s, %p, %p): stub\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2689 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
2690 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
2692 FIXME("(0x%08lx, 0x%08lx, %p, 0x%08lx, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
2693 dwSearchCondition, lpGroupId, lpReserved);
2697 BOOL WINAPI FindNextUrlCacheEntryA(
2699 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
2700 LPDWORD lpdwNextCacheEntryInfoBufferSize
2703 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2707 BOOL WINAPI FindNextUrlCacheEntryW(
2709 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
2710 LPDWORD lpdwNextCacheEntryInfoBufferSize
2713 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2717 BOOL WINAPI FindNextUrlCacheEntryExA(
2719 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2720 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2722 LPDWORD pcbReserved2,
2726 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2727 lpReserved, pcbReserved2, lpReserved3);
2731 BOOL WINAPI FindNextUrlCacheEntryExW(
2733 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2734 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2736 LPDWORD pcbReserved2,
2740 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2741 lpReserved, pcbReserved2, lpReserved3);
2745 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
2747 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
2751 /***********************************************************************
2752 * CreateUrlCacheGroup (WININET.@)
2755 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
2757 FIXME("(0x%08lx, %p): stub\n", dwFlags, lpReserved);
2761 /***********************************************************************
2762 * DeleteUrlCacheGroup (WININET.@)
2765 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
2767 FIXME("(0x%08lx%08lx, 0x%08lx, %p) stub\n",
2768 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
2772 /***********************************************************************
2773 * SetUrlCacheEntryGroupA (WININET.@)
2776 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
2777 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2780 FIXME("(%s, 0x%08lx, 0x%08lx%08lx, %p, 0x%08lx, %p) stub\n",
2781 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2782 pbGroupAttributes, cbGroupAttributes, lpReserved);
2783 SetLastError(ERROR_FILE_NOT_FOUND);
2787 /***********************************************************************
2788 * SetUrlCacheEntryGroupW (WININET.@)
2791 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
2792 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2795 FIXME("(%s, 0x%08lx, 0x%08lx%08lx, %p, 0x%08lx, %p) stub\n",
2796 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2797 pbGroupAttributes, cbGroupAttributes, lpReserved);
2798 SetLastError(ERROR_FILE_NOT_FOUND);
2802 /***********************************************************************
2803 * GetUrlCacheConfigInfoW (WININET.@)
2805 BOOL WINAPI GetUrlCacheConfigInfoW(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2807 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2808 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2812 /***********************************************************************
2813 * GetUrlCacheConfigInfoA (WININET.@)
2815 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
2817 BOOL WINAPI GetUrlCacheConfigInfoA(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2819 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2820 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2824 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2825 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
2826 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2828 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p, %p) stub\n",
2829 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2830 lpdwGroupInfo, lpReserved);
2834 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2835 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
2836 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2838 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p, %p) stub\n",
2839 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2840 lpdwGroupInfo, lpReserved);
2844 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2845 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
2847 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p) stub\n",
2848 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2852 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2853 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
2855 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p) stub\n",
2856 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2860 BOOL WINAPI SetUrlCacheConfigInfoA( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2862 FIXME("(%p, 0x%08lx) stub\n", lpCacheConfigInfo, dwFieldControl);
2866 BOOL WINAPI SetUrlCacheConfigInfoW( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2868 FIXME("(%p, 0x%08lx) stub\n", lpCacheConfigInfo, dwFieldControl);
2872 /***********************************************************************
2873 * DeleteIE3Cache (WININET.@)
2875 * Deletes the files used by the IE3 URL caching system.
2878 * hWnd [I] A dummy window.
2879 * hInst [I] Instance of process calling the function.
2880 * lpszCmdLine [I] Options used by function.
2881 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
2886 void WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
2888 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);