2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003 Robert Shearman
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
48 #include "wine/unicode.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
53 #define ENTRY_START_OFFSET 0x4000
56 #define HASHTABLE_SIZE 448
57 #define HASHTABLE_BLOCKSIZE 7
58 #define HASHTABLE_FREE 3
59 #define ALLOCATION_TABLE_OFFSET 0x250
60 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
61 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
62 #define NEWFILE_NUM_BLOCKS 0xd80
63 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
65 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
66 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
67 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
68 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
69 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
71 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
73 typedef struct _CACHEFILE_ENTRY
77 DWORD dwSignature; /* e.g. "URL " */
78 /* CHAR szSignature[4];
80 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
83 typedef struct _URL_CACHEFILE_ENTRY
85 CACHEFILE_ENTRY CacheFileEntry;
86 FILETIME LastModifiedTime;
87 FILETIME LastAccessTime;
88 WORD wExpiredDate; /* expire date in dos format */
89 WORD wExpiredTime; /* expire time in dos format */
90 DWORD dwUnknown1; /* usually zero */
91 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
92 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
93 DWORD dwUnknown2; /* usually zero */
94 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
95 DWORD dwUnknown3; /* usually 0x60 */
96 DWORD dwOffsetUrl; /* offset of start of url from start of entry */
97 BYTE CacheDir; /* index of cache directory this url is stored in */
98 BYTE Unknown4; /* usually zero */
99 WORD wUnknown5; /* usually 0x1010 */
100 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
101 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
102 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
103 DWORD dwHeaderInfoSize;
104 DWORD dwOffsetFileExtension; /* offset of start of file extension from start of entry */
105 WORD wLastSyncDate; /* last sync date in dos format */
106 WORD wLastSyncTime; /* last sync time in dos format */
107 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
108 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
109 WORD wUnknownDate; /* usually same as wLastSyncDate */
110 WORD wUnknownTime; /* usually same as wLastSyncTime */
111 DWORD dwUnknown7; /* usually zero */
112 DWORD dwUnknown8; /* usually zero */
113 /* packing to dword align start of next field */
114 /* CHAR szSourceUrlName[]; (url) */
115 /* packing to dword align start of next field */
116 /* CHAR szLocalFileName[]; (local file name excluding path) */
117 /* packing to dword align start of next field */
118 /* CHAR szHeaderInfo[]; (header info) */
119 } URL_CACHEFILE_ENTRY;
127 typedef struct _HASH_CACHEFILE_ENTRY
129 CACHEFILE_ENTRY CacheFileEntry;
131 DWORD dwHashTableNumber;
132 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
133 } HASH_CACHEFILE_ENTRY;
135 typedef struct _DIRECTORY_DATA
138 char filename[DIR_LENGTH];
141 typedef struct _URLCACHE_HEADER
143 char szSignature[28];
145 DWORD dwOffsetFirstHashTable;
146 DWORD dwIndexCapacityInBlocks;
149 DWORD dwCacheLimitLow; /* disk space limit for cache */
150 DWORD dwCacheLimitHigh; /* disk space limit for cache */
151 DWORD dwUnknown4; /* current disk space usage for cache */
152 DWORD dwUnknown5; /* current disk space usage for cache */
153 DWORD dwUnknown6; /* possibly a flag? */
155 BYTE DirectoryCount; /* number of directory_data's */
156 BYTE Unknown8[3]; /* just padding? */
157 DIRECTORY_DATA directory_data[1]; /* first directory entry */
158 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
159 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
161 typedef struct _STREAM_HANDLE
167 typedef struct _URLCACHECONTAINER
169 struct list entry; /* part of a list */
170 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
171 LPWSTR path; /* path to url container directory */
172 HANDLE hMapping; /* handle of file mapping */
173 DWORD file_size; /* size of file when mapping was opened */
174 HANDLE hMutex; /* handle of mutex */
178 /* List of all containers available */
179 static struct list UrlContainers = LIST_INIT(UrlContainers);
181 static HASH_CACHEFILE_ENTRY *URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash);
183 /***********************************************************************
184 * URLCache_PathToObjectName (Internal)
186 * Converts a path to a name suitable for use as a Win32 object name.
187 * Replaces '\\' characters in-place with the specified character
188 * (usually '_' or '!')
194 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
196 for (; *lpszPath; lpszPath++)
198 if (*lpszPath == '\\')
203 /***********************************************************************
204 * URLCacheContainer_OpenIndex (Internal)
206 * Opens the index file and saves mapping handle in hCacheIndexMapping
213 static BOOL URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
216 WCHAR wszFilePath[MAX_PATH];
219 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
220 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
222 if (pContainer->hMapping)
225 strcpyW(wszFilePath, pContainer->path);
226 strcatW(wszFilePath, wszIndex);
228 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
229 if (hFile == INVALID_HANDLE_VALUE)
231 /* Maybe the directory wasn't there? Try to create it */
232 if (CreateDirectoryW(pContainer->path, 0))
233 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
235 if (hFile == INVALID_HANDLE_VALUE)
237 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath));
241 /* At this stage we need the mutex because we may be about to create the
244 WaitForSingleObject(pContainer->hMutex, INFINITE);
246 dwFileSize = GetFileSize(hFile, NULL);
247 if (dwFileSize == INVALID_FILE_SIZE)
249 ReleaseMutex(pContainer->hMutex);
255 static const CHAR szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content";
257 char achZeroes[0x1000];
261 /* Write zeroes to the entire file so we can safely map it without
262 * fear of getting a SEGV because the disk is full.
264 memset(achZeroes, 0, sizeof(achZeroes));
265 for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes))
267 DWORD dwWrite = sizeof(achZeroes);
270 if (NEWFILE_SIZE - dwOffset < dwWrite)
271 dwWrite = NEWFILE_SIZE - dwOffset;
272 if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) ||
273 dwWritten != dwWrite)
275 /* If we fail to write, we need to return the error that
276 * cause the problem and also make sure the file is no
277 * longer there, if possible.
279 dwError = GetLastError();
287 HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL);
291 URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE);
296 WCHAR wszDirPath[MAX_PATH];
300 dwFileSize = NEWFILE_SIZE;
302 /* First set some constants and defaults in the header */
303 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
304 pHeader->dwFileSize = dwFileSize;
305 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
306 /* 127MB - taken from default for Windows 2000 */
307 pHeader->dwCacheLimitHigh = 0;
308 pHeader->dwCacheLimitLow = 0x07ff5400;
309 /* Copied from a Windows 2000 cache index */
310 pHeader->DirectoryCount = 4;
312 /* If the registry has a cache size set, use the registry value */
313 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
316 DWORD len = sizeof(dw);
319 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
320 (BYTE *) &dw, &len) == ERROR_SUCCESS &&
321 keytype == REG_DWORD)
323 pHeader->dwCacheLimitHigh = (dw >> 22);
324 pHeader->dwCacheLimitLow = dw << 10;
329 URLCache_CreateHashTable(pHeader, NULL);
331 /* Last step - create the directories */
333 strcpyW(wszDirPath, pContainer->path);
334 pwchDir = wszDirPath + strlenW(wszDirPath);
337 GetSystemTimeAsFileTime(&ft);
339 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
341 /* The following values were copied from a Windows index.
342 * I don't know what the values are supposed to mean but
343 * have made them the same in the hope that this will
344 * be better for compatibility
346 pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
350 ULONGLONG n = ft.dwHighDateTime;
352 /* Generate a file name to attempt to create.
353 * This algorithm will create what will appear
354 * to be random and unrelated directory names
355 * of up to 9 characters in length.
358 n += ft.dwLowDateTime;
359 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
361 for (k = 0; k < 8; ++k)
365 /* Dividing by a prime greater than 36 helps
366 * with the appearance of randomness
371 pwchDir[k] = '0' + r;
373 pwchDir[k] = 'A' + (r - 10);
376 if (CreateDirectoryW(wszDirPath, 0))
378 /* The following is OK because we generated an
379 * 8 character directory name made from characters
380 * [A-Z0-9], which are equivalent for all code
381 * pages and for UTF-16
383 for (k = 0; k < 8; ++k)
384 pHeader->directory_data[i].filename[k] = pwchDir[k];
389 /* Give up. The most likely cause of this
390 * is a full disk, but whatever the cause
391 * is, it should be more than apparent that
394 dwError = GetLastError();
400 UnmapViewOfFile(pHeader);
404 dwError = GetLastError();
406 CloseHandle(hMapping);
410 dwError = GetLastError();
417 DeleteFileW(wszFilePath);
418 ReleaseMutex(pContainer->hMutex);
419 SetLastError(dwError);
425 ReleaseMutex(pContainer->hMutex);
427 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
428 URLCache_PathToObjectName(wszFilePath, '_');
429 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
430 if (!pContainer->hMapping)
431 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
433 if (!pContainer->hMapping)
435 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
442 /***********************************************************************
443 * URLCacheContainer_CloseIndex (Internal)
451 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
453 CloseHandle(pContainer->hMapping);
454 pContainer->hMapping = NULL;
457 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
459 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
460 int path_len = strlenW(path);
461 int cache_prefix_len = strlenW(cache_prefix);
468 pContainer->hMapping = NULL;
469 pContainer->file_size = 0;
471 pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR));
472 if (!pContainer->path)
474 HeapFree(GetProcessHeap(), 0, pContainer);
478 memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR));
480 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
481 if (!pContainer->cache_prefix)
483 HeapFree(GetProcessHeap(), 0, pContainer->path);
484 HeapFree(GetProcessHeap(), 0, pContainer);
488 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
490 CharLowerW(mutex_name);
491 URLCache_PathToObjectName(mutex_name, '!');
493 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
495 ERR("couldn't create mutex (error is %d)\n", GetLastError());
496 HeapFree(GetProcessHeap(), 0, pContainer->path);
497 HeapFree(GetProcessHeap(), 0, pContainer);
501 list_add_head(&UrlContainers, &pContainer->entry);
506 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
508 list_remove(&pContainer->entry);
510 URLCacheContainer_CloseIndex(pContainer);
511 CloseHandle(pContainer->hMutex);
512 HeapFree(GetProcessHeap(), 0, pContainer->path);
513 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
514 HeapFree(GetProcessHeap(), 0, pContainer);
517 void URLCacheContainers_CreateDefaults(void)
519 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
520 static const WCHAR UrlPrefix[] = {0};
521 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
522 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
523 static const WCHAR CookieSuffix[] = {0};
524 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
527 int nFolder; /* CSIDL_* constant */
528 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
529 const WCHAR * cache_prefix; /* prefix used to reference the container */
530 } DefaultContainerData[] =
532 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
533 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
534 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
538 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
540 WCHAR wszCachePath[MAX_PATH];
541 WCHAR wszMutexName[MAX_PATH];
542 int path_len, suffix_len;
544 if (!SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE))
546 ERR("Couldn't get path for default container %u\n", i);
549 path_len = strlenW(wszCachePath);
550 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
552 if (path_len + suffix_len + 2 > MAX_PATH)
554 ERR("Path too long\n");
558 wszCachePath[path_len] = '\\';
559 wszCachePath[path_len+1] = 0;
561 strcpyW(wszMutexName, wszCachePath);
565 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
566 wszCachePath[path_len + suffix_len + 1] = '\\';
567 wszCachePath[path_len + suffix_len + 2] = '\0';
570 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
574 void URLCacheContainers_DeleteAll(void)
576 while(!list_empty(&UrlContainers))
577 URLCacheContainer_DeleteContainer(
578 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
582 static BOOL URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
584 URLCACHECONTAINER * pContainer;
586 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
588 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
590 int prefix_len = strlenW(pContainer->cache_prefix);
591 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
593 TRACE("found container with prefx %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
594 *ppContainer = pContainer;
598 ERR("no container found\n");
599 SetLastError(ERROR_FILE_NOT_FOUND);
603 static BOOL URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
607 int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
608 if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR))))
610 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len);
611 ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer);
612 HeapFree(GetProcessHeap(), 0, lpwszUrl);
618 static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, URLCACHECONTAINER ** ppContainer)
621 URLCACHECONTAINER * pContainer;
623 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern));
625 /* non-NULL search pattern only returns one container ever */
626 if (lpwszSearchPattern && dwIndex > 0)
629 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
631 if (lpwszSearchPattern)
633 if (!strcmpW(pContainer->cache_prefix, lpwszSearchPattern))
635 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
636 *ppContainer = pContainer;
644 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
645 *ppContainer = pContainer;
654 /***********************************************************************
655 * URLCacheContainer_LockIndex (Internal)
658 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
662 URLCACHE_HEADER * pHeader;
665 WaitForSingleObject(pContainer->hMutex, INFINITE);
667 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
671 ReleaseMutex(pContainer->hMutex);
672 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
675 pHeader = (URLCACHE_HEADER *)pIndexData;
677 /* file has grown - we need to remap to prevent us getting
678 * access violations when we try and access beyond the end
679 * of the memory mapped file */
680 if (pHeader->dwFileSize != pContainer->file_size)
682 URLCacheContainer_CloseIndex(pContainer);
683 if (!URLCacheContainer_OpenIndex(pContainer))
685 ReleaseMutex(pContainer->hMutex);
688 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
692 ReleaseMutex(pContainer->hMutex);
693 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
696 pHeader = (URLCACHE_HEADER *)pIndexData;
699 TRACE("Signature: %s, file size: %d bytes\n", pHeader->szSignature, pHeader->dwFileSize);
701 for (index = 0; index < pHeader->DirectoryCount; index++)
703 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
709 /***********************************************************************
710 * URLCacheContainer_UnlockIndex (Internal)
713 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
716 ReleaseMutex(pContainer->hMutex);
717 return UnmapViewOfFile(pHeader);
722 #define CHAR_BIT (8 * sizeof(CHAR))
725 /***********************************************************************
726 * URLCache_Allocation_BlockIsFree (Internal)
728 * Is the specified block number free?
735 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
737 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
738 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
741 /***********************************************************************
742 * URLCache_Allocation_BlockFree (Internal)
744 * Marks the specified block as free
750 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
752 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
753 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
756 /***********************************************************************
757 * URLCache_Allocation_BlockAllocate (Internal)
759 * Marks the specified block as allocated
765 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
767 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
768 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
771 /***********************************************************************
772 * URLCache_FindFirstFreeEntry (Internal)
774 * Finds and allocates the first block of free space big enough and
775 * sets ppEntry to point to it.
778 * TRUE if it had enough space
779 * FALSE if it couldn't find enough space
782 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
784 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
787 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
789 for (dwFreeCounter = 0;
790 dwFreeCounter < dwBlocksNeeded &&
791 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
792 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
794 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
796 if (dwFreeCounter == dwBlocksNeeded)
799 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
800 for (index = 0; index < dwBlocksNeeded; index++)
801 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
802 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
803 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
807 FIXME("Grow file\n");
811 /***********************************************************************
812 * URLCache_DeleteEntry (Internal)
814 * Deletes the specified entry and frees the space allocated to it
817 * TRUE if it succeeded
821 static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, CACHEFILE_ENTRY * pEntry)
825 BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
827 /* update allocation table */
828 dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE;
829 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
830 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
832 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
836 /***********************************************************************
837 * URLCache_LocalFileNameToPathW (Internal)
839 * Copies the full path to the specified buffer given the local file
840 * name and the index of the directory it is in. Always sets value in
841 * lpBufferSize to the required buffer size (in bytes).
844 * TRUE if the buffer was big enough
845 * FALSE if the buffer was too small
848 static BOOL URLCache_LocalFileNameToPathW(
849 const URLCACHECONTAINER * pContainer,
850 LPCURLCACHE_HEADER pHeader,
851 LPCSTR szLocalFileName,
857 int path_len = strlenW(pContainer->path);
858 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
859 if (Directory >= pHeader->DirectoryCount)
865 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
866 if (nRequired < *lpBufferSize)
870 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
871 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
872 wszPath[dir_len + path_len] = '\\';
873 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
874 *lpBufferSize = nRequired;
877 *lpBufferSize = nRequired;
881 /***********************************************************************
882 * URLCache_LocalFileNameToPathA (Internal)
884 * Copies the full path to the specified buffer given the local file
885 * name and the index of the directory it is in. Always sets value in
886 * lpBufferSize to the required buffer size.
889 * TRUE if the buffer was big enough
890 * FALSE if the buffer was too small
893 static BOOL URLCache_LocalFileNameToPathA(
894 const URLCACHECONTAINER * pContainer,
895 LPCURLCACHE_HEADER pHeader,
896 LPCSTR szLocalFileName,
902 int path_len, file_name_len, dir_len;
904 if (Directory >= pHeader->DirectoryCount)
910 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL) - 1;
911 file_name_len = strlen(szLocalFileName) + 1 /* for nul-terminator */;
912 dir_len = DIR_LENGTH;
914 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(char);
915 if (nRequired < *lpBufferSize)
917 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, path_len, NULL, NULL);
918 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
919 szPath[path_len + dir_len] = '\\';
920 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
921 *lpBufferSize = nRequired;
924 *lpBufferSize = nRequired;
928 /***********************************************************************
929 * URLCache_CopyEntry (Internal)
931 * Copies an entry from the cache index file to the Win32 structure
934 * TRUE if the buffer was big enough
935 * FALSE if the buffer was too small
938 static BOOL URLCache_CopyEntry(
939 URLCACHECONTAINER * pContainer,
940 LPCURLCACHE_HEADER pHeader,
941 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
942 LPDWORD lpdwBufferSize,
943 const URL_CACHEFILE_ENTRY * pUrlEntry,
947 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
949 if (*lpdwBufferSize >= dwRequiredSize)
951 lpCacheEntryInfo->lpHeaderInfo = NULL;
952 lpCacheEntryInfo->lpszFileExtension = NULL;
953 lpCacheEntryInfo->lpszLocalFileName = NULL;
954 lpCacheEntryInfo->lpszSourceUrlName = NULL;
955 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
956 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
957 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
958 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
959 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
960 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
961 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
962 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
963 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
964 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
965 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
966 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
967 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
968 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
971 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
972 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
973 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
975 lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0);
977 lenUrl = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
978 dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
980 /* FIXME: is source url optional? */
981 if (*lpdwBufferSize >= dwRequiredSize)
983 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrl - 1;
985 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
987 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, (lenUrl + 1) * sizeof(CHAR));
990 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
991 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
992 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
994 if (pUrlEntry->dwOffsetLocalName)
996 LONG nLocalFilePathSize;
997 LPSTR lpszLocalFileName;
998 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
999 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
1000 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
1001 URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize))
1003 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
1005 dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ;
1007 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1008 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1009 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1011 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
1013 if (*lpdwBufferSize >= dwRequiredSize)
1015 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
1016 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
1017 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
1019 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1020 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1021 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1023 if (pUrlEntry->dwOffsetFileExtension)
1028 lenExtension = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, NULL, 0);
1030 lenExtension = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension) + 1;
1031 dwRequiredSize += lenExtension * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
1033 if (*lpdwBufferSize >= dwRequiredSize)
1035 lpCacheEntryInfo->lpszFileExtension = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenExtension;
1037 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenExtension);
1039 memcpy(lpCacheEntryInfo->lpszFileExtension, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, lenExtension * sizeof(CHAR));
1042 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1043 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1044 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1047 if (dwRequiredSize > *lpdwBufferSize)
1049 *lpdwBufferSize = dwRequiredSize;
1050 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1053 *lpdwBufferSize = dwRequiredSize;
1058 /***********************************************************************
1059 * URLCache_SetEntryInfo (Internal)
1061 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1062 * according to the flags set by dwFieldControl.
1065 * TRUE if the buffer was big enough
1066 * FALSE if the buffer was too small
1069 static BOOL URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1071 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1072 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1073 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1074 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1075 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1076 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1077 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1078 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1079 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1080 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1081 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1082 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1083 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1084 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1085 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1086 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1091 /***********************************************************************
1092 * URLCache_HashKey (Internal)
1094 * Returns the hash key for a given string
1097 * hash key for the string
1100 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1102 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1103 * but the algorithm and result are not the same!
1105 static const unsigned char lookupTable[256] =
1107 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1108 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1109 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1110 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1111 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1112 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1113 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1114 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1115 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1116 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1117 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1118 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1119 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1120 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1121 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1122 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1123 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1124 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1125 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1126 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1127 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1128 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1129 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1130 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1131 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1132 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1133 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1134 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1135 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1136 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1137 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1138 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1142 int subscript[sizeof(key) / sizeof(key[0])];
1144 subscript[0] = *lpszKey;
1145 subscript[1] = (char)(*lpszKey + 1);
1146 subscript[2] = (char)(*lpszKey + 2);
1147 subscript[3] = (char)(*lpszKey + 3);
1149 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1150 key[i] = lookupTable[i];
1152 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
1154 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1155 key[i] = lookupTable[*lpszKey ^ key[i]];
1158 return *(DWORD *)key;
1161 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
1163 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
1166 static inline BOOL URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY *pHashEntry)
1168 /* check pHashEntry located within acceptable bounds in the URL cache mapping */
1169 return ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) &&
1170 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1173 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1175 /* structure of hash table:
1176 * 448 entries divided into 64 blocks
1177 * each block therefore contains a chain of 7 key/offset pairs
1178 * how position in table is calculated:
1179 * 1. the url is hashed in helper function
1180 * 2. the key % 64 * 8 is the offset
1181 * 3. the key in the hash table is the hash key aligned to 64
1184 * there can be multiple hash tables in the file and the offset to
1185 * the next one is stored in the header of the hash table
1187 DWORD key = URLCache_HashKey(lpszUrl);
1188 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1189 HASH_CACHEFILE_ENTRY * pHashEntry;
1190 DWORD dwHashTableNumber = 0;
1192 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1194 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1195 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1196 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1199 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1201 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1204 /* make sure that it is in fact a hash entry */
1205 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1207 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1211 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1213 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1214 if (key == (pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
1216 /* FIXME: we should make sure that this is the right element
1217 * before returning and claiming that it is. We can do this
1218 * by doing a simple compare between the URL we were given
1219 * and the URL stored in the entry. However, this assumes
1220 * we know the format of all the entries stored in the
1222 *ppHashEntry = pHashElement;
1230 static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1236 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1237 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1240 SetLastError(ERROR_OUTOFMEMORY);
1243 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, urlA, url_len, NULL, NULL);
1244 ret = URLCache_FindHash(pHeader, urlA, ppHashEntry);
1245 HeapFree(GetProcessHeap(), 0, urlA);
1249 /***********************************************************************
1250 * URLCache_HashEntrySetUse (Internal)
1252 * Searches all the hash tables in the index for the given URL and
1253 * sets the use count (stored or'ed with key)
1256 * TRUE if the entry was found
1257 * FALSE if the entry could not be found
1260 static BOOL URLCache_HashEntrySetUse(struct _HASH_ENTRY * pHashEntry, DWORD dwUseCount)
1262 pHashEntry->dwHashKey = dwUseCount | (pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1266 /***********************************************************************
1267 * URLCache_DeleteEntryFromHash (Internal)
1269 * Searches all the hash tables in the index for the given URL and
1270 * then if found deletes the entry.
1273 * TRUE if the entry was found
1274 * FALSE if the entry could not be found
1277 static BOOL URLCache_DeleteEntryFromHash(struct _HASH_ENTRY * pHashEntry)
1279 pHashEntry->dwHashKey = HASHTABLE_FREE;
1280 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1284 /***********************************************************************
1285 * URLCache_AddEntryToHash (Internal)
1287 * Searches all the hash tables for a free slot based on the offset
1288 * generated from the hash key. If a free slot is found, the offset and
1289 * key are entered into the hash table.
1292 * TRUE if the entry was added
1293 * FALSE if the entry could not be added
1296 static BOOL URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1298 /* see URLCache_FindEntryInHash for structure of hash tables */
1300 DWORD key = URLCache_HashKey(lpszUrl);
1301 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1302 HASH_CACHEFILE_ENTRY * pHashEntry;
1303 DWORD dwHashTableNumber = 0;
1305 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1307 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1308 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1309 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1312 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1314 ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1317 /* make sure that it is in fact a hash entry */
1318 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1320 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1324 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1326 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1327 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1329 pHashElement->dwHashKey = key;
1330 pHashElement->dwOffsetEntry = dwOffsetEntry;
1335 pHashEntry = URLCache_CreateHashTable(pHeader, pHashEntry);
1339 pHashEntry->HashTable[offset].dwHashKey = key;
1340 pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry;
1344 /***********************************************************************
1345 * URLCache_CreateHashTable (Internal)
1347 * Creates a new hash table in free space and adds it to the chain of existing
1351 * TRUE if the hash table was created
1352 * FALSE if the hash table could not be created
1355 static HASH_CACHEFILE_ENTRY *URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash)
1357 HASH_CACHEFILE_ENTRY *pHash;
1361 if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)&pHash))
1363 FIXME("no free space for hash table\n");
1364 SetLastError(ERROR_DISK_FULL);
1368 dwOffset = (BYTE *)pHash - (BYTE *)pHeader;
1371 pPrevHash->dwAddressNext = dwOffset;
1373 pHeader->dwOffsetFirstHashTable = dwOffset;
1374 pHash->CacheFileEntry.dwSignature = HASH_SIGNATURE;
1375 pHash->CacheFileEntry.dwBlocksUsed = 0x20;
1376 pHash->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0;
1377 for (i = 0; i < HASHTABLE_SIZE; i++)
1379 pHash->HashTable[i].dwOffsetEntry = 0;
1380 pHash->HashTable[i].dwHashKey = HASHTABLE_FREE;
1385 /***********************************************************************
1386 * URLCache_EnumHashTables (Internal)
1388 * Enumerates the hash tables in a container.
1391 * TRUE if an entry was found
1392 * FALSE if there are no more tables to enumerate.
1395 static BOOL URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader, DWORD *pdwHashTableNumber, HASH_CACHEFILE_ENTRY ** ppHashEntry)
1397 for (*ppHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1398 URLCache_IsHashEntryValid(pHeader, *ppHashEntry);
1399 *ppHashEntry = URLCache_HashEntryFromOffset(pHeader, (*ppHashEntry)->dwAddressNext))
1401 TRACE("looking at hash table number %d\n", (*ppHashEntry)->dwHashTableNumber);
1402 if ((*ppHashEntry)->dwHashTableNumber != *pdwHashTableNumber)
1404 /* make sure that it is in fact a hash entry */
1405 if ((*ppHashEntry)->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1407 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&(*ppHashEntry)->CacheFileEntry.dwSignature);
1408 (*pdwHashTableNumber)++;
1412 TRACE("hash table number %d found\n", *pdwHashTableNumber);
1418 /***********************************************************************
1419 * URLCache_EnumHashTableEntries (Internal)
1421 * Enumerates entries in a hash table and returns the next non-free entry.
1424 * TRUE if an entry was found
1425 * FALSE if the hash table is empty or there are no more entries to
1429 static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY * pHashEntry,
1430 DWORD * index, const struct _HASH_ENTRY ** ppHashEntry)
1432 for (; *index < HASHTABLE_SIZE ; (*index)++)
1434 if (pHashEntry->HashTable[*index].dwHashKey == HASHTABLE_FREE)
1437 *ppHashEntry = &pHashEntry->HashTable[*index];
1438 TRACE("entry found %d\n", *index);
1441 TRACE("no more entries (%d)\n", *index);
1445 /***********************************************************************
1446 * GetUrlCacheEntryInfoExA (WININET.@)
1449 BOOL WINAPI GetUrlCacheEntryInfoExA(
1451 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1452 LPDWORD lpdwCacheEntryInfoBufSize,
1454 LPDWORD lpdwReserved,
1458 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1459 debugstr_a(lpszUrl),
1461 lpdwCacheEntryInfoBufSize,
1467 if ((lpszReserved != NULL) ||
1468 (lpdwReserved != NULL) ||
1469 (lpReserved != NULL))
1471 ERR("Reserved value was not 0\n");
1472 SetLastError(ERROR_INVALID_PARAMETER);
1476 FIXME("Undocumented flag(s): %x\n", dwFlags);
1477 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1480 /***********************************************************************
1481 * GetUrlCacheEntryInfoA (WININET.@)
1484 BOOL WINAPI GetUrlCacheEntryInfoA(
1485 IN LPCSTR lpszUrlName,
1486 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1487 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1490 LPURLCACHE_HEADER pHeader;
1491 struct _HASH_ENTRY * pHashEntry;
1492 const CACHEFILE_ENTRY * pEntry;
1493 const URL_CACHEFILE_ENTRY * pUrlEntry;
1494 URLCACHECONTAINER * pContainer;
1496 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1498 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1501 if (!URLCacheContainer_OpenIndex(pContainer))
1504 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1507 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1509 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1510 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1511 SetLastError(ERROR_FILE_NOT_FOUND);
1515 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1516 if (pEntry->dwSignature != URL_SIGNATURE)
1518 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1519 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1520 SetLastError(ERROR_FILE_NOT_FOUND);
1524 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1525 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1526 if (pUrlEntry->dwOffsetHeaderInfo)
1527 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1529 if (!URLCache_CopyEntry(
1533 lpdwCacheEntryInfoBufferSize,
1537 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1540 TRACE("Local File Name: %s\n", debugstr_a(lpCacheEntryInfo->lpszLocalFileName));
1542 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1547 /***********************************************************************
1548 * GetUrlCacheEntryInfoW (WININET.@)
1551 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1552 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1553 LPDWORD lpdwCacheEntryInfoBufferSize)
1555 LPURLCACHE_HEADER pHeader;
1556 struct _HASH_ENTRY * pHashEntry;
1557 const CACHEFILE_ENTRY * pEntry;
1558 const URL_CACHEFILE_ENTRY * pUrlEntry;
1559 URLCACHECONTAINER * pContainer;
1561 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1563 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1566 if (!URLCacheContainer_OpenIndex(pContainer))
1569 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1572 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1574 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1575 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1576 SetLastError(ERROR_FILE_NOT_FOUND);
1580 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1581 if (pEntry->dwSignature != URL_SIGNATURE)
1583 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1584 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1585 SetLastError(ERROR_FILE_NOT_FOUND);
1589 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1590 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1591 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1593 if (!URLCache_CopyEntry(
1596 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1597 lpdwCacheEntryInfoBufferSize,
1599 TRUE /* UNICODE */))
1601 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1604 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1606 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1611 /***********************************************************************
1612 * GetUrlCacheEntryInfoExW (WININET.@)
1615 BOOL WINAPI GetUrlCacheEntryInfoExW(
1617 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1618 LPDWORD lpdwCacheEntryInfoBufSize,
1619 LPWSTR lpszReserved,
1620 LPDWORD lpdwReserved,
1624 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1625 debugstr_w(lpszUrl),
1627 lpdwCacheEntryInfoBufSize,
1633 if ((lpszReserved != NULL) ||
1634 (lpdwReserved != NULL) ||
1635 (lpReserved != NULL))
1637 ERR("Reserved value was not 0\n");
1638 SetLastError(ERROR_INVALID_PARAMETER);
1642 FIXME("Undocumented flag(s): %x\n", dwFlags);
1643 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1646 /***********************************************************************
1647 * SetUrlCacheEntryInfoA (WININET.@)
1649 BOOL WINAPI SetUrlCacheEntryInfoA(
1651 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1652 DWORD dwFieldControl)
1654 LPURLCACHE_HEADER pHeader;
1655 struct _HASH_ENTRY * pHashEntry;
1656 CACHEFILE_ENTRY * pEntry;
1657 URLCACHECONTAINER * pContainer;
1659 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1661 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1664 if (!URLCacheContainer_OpenIndex(pContainer))
1667 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1670 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1672 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1673 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1674 SetLastError(ERROR_FILE_NOT_FOUND);
1678 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1679 if (pEntry->dwSignature != URL_SIGNATURE)
1681 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1682 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1683 SetLastError(ERROR_FILE_NOT_FOUND);
1687 URLCache_SetEntryInfo(
1688 (URL_CACHEFILE_ENTRY *)pEntry,
1689 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1692 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1697 /***********************************************************************
1698 * SetUrlCacheEntryInfoW (WININET.@)
1700 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1702 LPURLCACHE_HEADER pHeader;
1703 struct _HASH_ENTRY * pHashEntry;
1704 CACHEFILE_ENTRY * pEntry;
1705 URLCACHECONTAINER * pContainer;
1707 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1709 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1712 if (!URLCacheContainer_OpenIndex(pContainer))
1715 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1718 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1720 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1721 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1722 SetLastError(ERROR_FILE_NOT_FOUND);
1726 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1727 if (pEntry->dwSignature != URL_SIGNATURE)
1729 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1730 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1731 SetLastError(ERROR_FILE_NOT_FOUND);
1735 URLCache_SetEntryInfo(
1736 (URL_CACHEFILE_ENTRY *)pEntry,
1740 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1745 /***********************************************************************
1746 * RetrieveUrlCacheEntryFileA (WININET.@)
1749 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1750 IN LPCSTR lpszUrlName,
1751 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1752 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1756 LPURLCACHE_HEADER pHeader;
1757 struct _HASH_ENTRY * pHashEntry;
1758 CACHEFILE_ENTRY * pEntry;
1759 URL_CACHEFILE_ENTRY * pUrlEntry;
1760 URLCACHECONTAINER * pContainer;
1762 TRACE("(%s, %p, %p, 0x%08x)\n",
1763 debugstr_a(lpszUrlName),
1765 lpdwCacheEntryInfoBufferSize,
1768 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1771 if (!URLCacheContainer_OpenIndex(pContainer))
1774 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1777 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1779 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1780 TRACE("entry %s not found!\n", lpszUrlName);
1781 SetLastError(ERROR_FILE_NOT_FOUND);
1785 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1786 if (pEntry->dwSignature != URL_SIGNATURE)
1788 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1789 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1790 SetLastError(ERROR_FILE_NOT_FOUND);
1794 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1795 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1796 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1798 pUrlEntry->dwHitRate++;
1799 pUrlEntry->dwUseCount++;
1800 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1802 if (!URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize, pUrlEntry, FALSE))
1804 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1807 TRACE("Local File Name: %s\n", lpCacheEntryInfo->lpszLocalFileName);
1809 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1814 /***********************************************************************
1815 * RetrieveUrlCacheEntryFileW (WININET.@)
1818 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1819 IN LPCWSTR lpszUrlName,
1820 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1821 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1825 LPURLCACHE_HEADER pHeader;
1826 struct _HASH_ENTRY * pHashEntry;
1827 CACHEFILE_ENTRY * pEntry;
1828 URL_CACHEFILE_ENTRY * pUrlEntry;
1829 URLCACHECONTAINER * pContainer;
1831 TRACE("(%s, %p, %p, 0x%08x)\n",
1832 debugstr_w(lpszUrlName),
1834 lpdwCacheEntryInfoBufferSize,
1837 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
1840 if (!URLCacheContainer_OpenIndex(pContainer))
1843 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1846 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1848 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1849 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1850 SetLastError(ERROR_FILE_NOT_FOUND);
1854 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1855 if (pEntry->dwSignature != URL_SIGNATURE)
1857 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1858 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1859 SetLastError(ERROR_FILE_NOT_FOUND);
1863 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1864 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1865 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1867 pUrlEntry->dwHitRate++;
1868 pUrlEntry->dwUseCount++;
1869 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1871 if (!URLCache_CopyEntry(
1874 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1875 lpdwCacheEntryInfoBufferSize,
1877 TRUE /* UNICODE */))
1879 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1882 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1884 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1889 /***********************************************************************
1890 * UnlockUrlCacheEntryFileA (WININET.@)
1893 BOOL WINAPI UnlockUrlCacheEntryFileA(
1894 IN LPCSTR lpszUrlName,
1898 LPURLCACHE_HEADER pHeader;
1899 struct _HASH_ENTRY * pHashEntry;
1900 CACHEFILE_ENTRY * pEntry;
1901 URL_CACHEFILE_ENTRY * pUrlEntry;
1902 URLCACHECONTAINER * pContainer;
1904 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
1908 ERR("dwReserved != 0\n");
1909 SetLastError(ERROR_INVALID_PARAMETER);
1913 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1916 if (!URLCacheContainer_OpenIndex(pContainer))
1919 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1922 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1924 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1925 TRACE("entry %s not found!\n", lpszUrlName);
1926 SetLastError(ERROR_FILE_NOT_FOUND);
1930 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1931 if (pEntry->dwSignature != URL_SIGNATURE)
1933 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1934 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1935 SetLastError(ERROR_FILE_NOT_FOUND);
1939 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1941 if (pUrlEntry->dwUseCount == 0)
1943 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1946 pUrlEntry->dwUseCount--;
1947 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1949 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1954 /***********************************************************************
1955 * UnlockUrlCacheEntryFileW (WININET.@)
1958 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
1960 LPURLCACHE_HEADER pHeader;
1961 struct _HASH_ENTRY * pHashEntry;
1962 CACHEFILE_ENTRY * pEntry;
1963 URL_CACHEFILE_ENTRY * pUrlEntry;
1964 URLCACHECONTAINER * pContainer;
1966 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
1970 ERR("dwReserved != 0\n");
1971 SetLastError(ERROR_INVALID_PARAMETER);
1975 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
1978 if (!URLCacheContainer_OpenIndex(pContainer))
1981 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1984 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1986 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1987 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1988 SetLastError(ERROR_FILE_NOT_FOUND);
1992 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1993 if (pEntry->dwSignature != URL_SIGNATURE)
1995 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1996 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1997 SetLastError(ERROR_FILE_NOT_FOUND);
2001 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2003 if (pUrlEntry->dwUseCount == 0)
2005 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2008 pUrlEntry->dwUseCount--;
2009 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2011 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2016 /***********************************************************************
2017 * CreateUrlCacheEntryA (WININET.@)
2020 BOOL WINAPI CreateUrlCacheEntryA(
2021 IN LPCSTR lpszUrlName,
2022 IN DWORD dwExpectedFileSize,
2023 IN LPCSTR lpszFileExtension,
2024 OUT LPSTR lpszFileName,
2030 WCHAR *file_extension;
2031 WCHAR file_name[MAX_PATH];
2032 BOOL bSuccess = FALSE;
2035 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
2036 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2038 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2039 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 &&
2040 (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2042 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2043 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
2045 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
2051 dwError = GetLastError();
2056 dwError = GetLastError();
2058 HeapFree(GetProcessHeap(), 0, file_extension);
2062 dwError = GetLastError();
2064 HeapFree(GetProcessHeap(), 0, url_name);
2066 SetLastError(dwError);
2070 /***********************************************************************
2071 * CreateUrlCacheEntryW (WININET.@)
2074 BOOL WINAPI CreateUrlCacheEntryW(
2075 IN LPCWSTR lpszUrlName,
2076 IN DWORD dwExpectedFileSize,
2077 IN LPCWSTR lpszFileExtension,
2078 OUT LPWSTR lpszFileName,
2082 URLCACHECONTAINER * pContainer;
2083 LPURLCACHE_HEADER pHeader;
2084 CHAR szFile[MAX_PATH];
2085 WCHAR szExtension[MAX_PATH];
2086 LPCWSTR lpszUrlPart;
2088 LPCWSTR lpszFileNameExtension;
2089 LPWSTR lpszFileNameNoPath;
2091 int countnoextension;
2094 BOOL bFound = FALSE;
2096 static const WCHAR szWWW[] = {'w','w','w',0};
2098 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2099 debugstr_w(lpszUrlName),
2101 debugstr_w(lpszFileExtension),
2107 ERR("dwReserved != 0\n");
2108 SetLastError(ERROR_INVALID_PARAMETER);
2112 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2114 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2117 for (lpszUrlPart = lpszUrlEnd;
2118 (lpszUrlPart >= lpszUrlName);
2121 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2127 else if(*lpszUrlPart == '?' || *lpszUrlPart == '#')
2129 lpszUrlEnd = lpszUrlPart;
2132 if (!lstrcmpW(lpszUrlPart, szWWW))
2134 lpszUrlPart += lstrlenW(szWWW);
2137 count = lpszUrlEnd - lpszUrlPart;
2139 if (bFound && (count < MAX_PATH))
2141 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2145 /* FIXME: get rid of illegal characters like \, / and : */
2149 FIXME("need to generate a random filename\n");
2152 TRACE("File name: %s\n", debugstr_a(szFile));
2154 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
2157 if (!URLCacheContainer_OpenIndex(pContainer))
2160 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2163 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2165 lBufferSize = MAX_PATH * sizeof(WCHAR);
2166 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
2168 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2170 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2171 lpszFileNameNoPath >= lpszFileName;
2172 --lpszFileNameNoPath)
2174 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2178 countnoextension = lstrlenW(lpszFileNameNoPath);
2179 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2180 if (lpszFileNameExtension)
2181 countnoextension -= lstrlenW(lpszFileNameExtension);
2182 *szExtension = '\0';
2184 if (lpszFileExtension)
2186 szExtension[0] = '.';
2187 lstrcpyW(szExtension+1, lpszFileExtension);
2190 for (i = 0; i < 255; i++)
2192 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2194 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2195 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2196 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2197 if (hFile != INVALID_HANDLE_VALUE)
2208 /***********************************************************************
2209 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2211 * The bug we are compensating for is that some drongo at Microsoft
2212 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2213 * As a consequence, CommitUrlCacheEntryA has been effectively
2214 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2215 * is still defined as LPCWSTR. The result (other than madness) is
2216 * that we always need to store lpHeaderInfo in CP_ACP rather than
2217 * in UTF16, and we need to avoid converting lpHeaderInfo in
2218 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2219 * result will lose data for arbitrary binary data.
2222 static BOOL WINAPI CommitUrlCacheEntryInternal(
2223 IN LPCWSTR lpszUrlName,
2224 IN LPCWSTR lpszLocalFileName,
2225 IN FILETIME ExpireTime,
2226 IN FILETIME LastModifiedTime,
2227 IN DWORD CacheEntryType,
2228 IN LPBYTE lpHeaderInfo,
2229 IN DWORD dwHeaderSize,
2230 IN LPCWSTR lpszFileExtension,
2231 IN LPCWSTR lpszOriginalUrl
2234 URLCACHECONTAINER * pContainer;
2235 LPURLCACHE_HEADER pHeader;
2236 struct _HASH_ENTRY * pHashEntry;
2237 CACHEFILE_ENTRY * pEntry;
2238 URL_CACHEFILE_ENTRY * pUrlEntry;
2239 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2240 DWORD dwOffsetLocalFileName = 0;
2241 DWORD dwOffsetHeader = 0;
2242 DWORD dwOffsetFileExtension = 0;
2243 DWORD dwFileSizeLow = 0;
2244 DWORD dwFileSizeHigh = 0;
2245 BYTE cDirectory = 0;
2247 char achFile[MAX_PATH];
2248 LPSTR lpszUrlNameA = NULL;
2249 LPSTR lpszFileExtensionA = NULL;
2250 char *pchLocalFileName = 0;
2251 DWORD error = ERROR_SUCCESS;
2253 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2254 debugstr_w(lpszUrlName),
2255 debugstr_w(lpszLocalFileName),
2259 debugstr_w(lpszFileExtension),
2260 debugstr_w(lpszOriginalUrl));
2262 if (lpszOriginalUrl)
2263 WARN(": lpszOriginalUrl ignored\n");
2265 if (lpszLocalFileName)
2269 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2270 if (hFile == INVALID_HANDLE_VALUE)
2272 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2277 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2278 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2280 ERR("couldn't get file size (error is %d)\n", GetLastError());
2288 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
2291 if (!URLCacheContainer_OpenIndex(pContainer))
2294 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2297 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2298 lpszUrlNameA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2301 error = GetLastError();
2304 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, lpszUrlNameA, len, NULL, NULL);
2306 if (lpszFileExtension)
2308 len = WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, NULL, 0, NULL, NULL);
2309 lpszFileExtensionA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
2310 if (!lpszFileExtensionA)
2312 error = GetLastError();
2315 WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, lpszFileExtensionA, len, NULL, NULL);
2318 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2320 FIXME("entry already in cache - don't know what to do!\n");
2322 * SetLastError(ERROR_FILE_NOT_FOUND);
2328 if (lpszLocalFileName)
2330 BOOL bFound = FALSE;
2332 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2334 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2335 error = ERROR_INVALID_PARAMETER;
2339 /* skip container path prefix */
2340 lpszLocalFileName += lstrlenW(pContainer->path);
2342 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, -1, NULL, NULL);
2343 pchLocalFileName = achFile;
2345 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2347 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2356 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2357 error = ERROR_INVALID_PARAMETER;
2361 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2364 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2365 if (lpszLocalFileName)
2367 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2368 dwOffsetLocalFileName = dwBytesNeeded;
2369 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2373 dwOffsetHeader = dwBytesNeeded;
2374 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2376 if (lpszFileExtensionA)
2378 dwOffsetFileExtension = dwBytesNeeded;
2379 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2382 /* round up to next block */
2383 if (dwBytesNeeded % BLOCKSIZE)
2385 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2386 dwBytesNeeded += BLOCKSIZE;
2389 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2391 ERR("no free entries\n");
2392 error = ERROR_DISK_FULL;
2396 /* FindFirstFreeEntry fills in blocks used */
2397 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2398 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2399 pUrlEntry->CacheDir = cDirectory;
2400 pUrlEntry->CacheEntryType = CacheEntryType;
2401 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2402 pUrlEntry->dwExemptDelta = 0;
2403 pUrlEntry->dwHitRate = 0;
2404 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2405 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2406 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2407 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2408 pUrlEntry->dwSizeHigh = 0;
2409 pUrlEntry->dwSizeLow = dwFileSizeLow;
2410 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2411 pUrlEntry->dwUseCount = 0;
2412 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2413 pUrlEntry->LastModifiedTime = LastModifiedTime;
2414 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2415 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2416 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2417 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2420 pUrlEntry->dwUnknown1 = 0;
2421 pUrlEntry->dwUnknown2 = 0;
2422 pUrlEntry->dwUnknown3 = 0x60;
2423 pUrlEntry->Unknown4 = 0;
2424 pUrlEntry->wUnknown5 = 0x1010;
2425 pUrlEntry->dwUnknown7 = 0;
2426 pUrlEntry->dwUnknown8 = 0;
2429 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2430 if (dwOffsetLocalFileName)
2431 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2433 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2434 if (dwOffsetFileExtension)
2435 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2437 if (!URLCache_AddEntryToHash(pHeader, lpszUrlNameA, (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader)))
2439 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2440 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2441 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2446 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2447 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2448 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2450 if (error == ERROR_SUCCESS)
2454 SetLastError(error);
2459 /***********************************************************************
2460 * CommitUrlCacheEntryA (WININET.@)
2463 BOOL WINAPI CommitUrlCacheEntryA(
2464 IN LPCSTR lpszUrlName,
2465 IN LPCSTR lpszLocalFileName,
2466 IN FILETIME ExpireTime,
2467 IN FILETIME LastModifiedTime,
2468 IN DWORD CacheEntryType,
2469 IN LPBYTE lpHeaderInfo,
2470 IN DWORD dwHeaderSize,
2471 IN LPCSTR lpszFileExtension,
2472 IN LPCSTR lpszOriginalUrl
2476 WCHAR *url_name = NULL;
2477 WCHAR *local_file_name = NULL;
2478 WCHAR *original_url = NULL;
2479 WCHAR *file_extension = NULL;
2480 BOOL bSuccess = FALSE;
2482 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2483 debugstr_a(lpszUrlName),
2484 debugstr_a(lpszLocalFileName),
2488 debugstr_a(lpszFileExtension),
2489 debugstr_a(lpszOriginalUrl));
2491 len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0);
2492 url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2495 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2497 if (lpszLocalFileName)
2499 len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0);
2500 local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2501 if (!local_file_name)
2503 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2505 if (lpszFileExtension)
2507 len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0);
2508 file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2509 if (!file_extension)
2511 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
2513 if (lpszOriginalUrl)
2515 len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0);
2516 original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2519 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2522 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2523 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2524 file_extension, original_url);
2527 HeapFree(GetProcessHeap(), 0, original_url);
2528 HeapFree(GetProcessHeap(), 0, file_extension);
2529 HeapFree(GetProcessHeap(), 0, local_file_name);
2530 HeapFree(GetProcessHeap(), 0, url_name);
2535 /***********************************************************************
2536 * CommitUrlCacheEntryW (WININET.@)
2539 BOOL WINAPI CommitUrlCacheEntryW(
2540 IN LPCWSTR lpszUrlName,
2541 IN LPCWSTR lpszLocalFileName,
2542 IN FILETIME ExpireTime,
2543 IN FILETIME LastModifiedTime,
2544 IN DWORD CacheEntryType,
2545 IN LPWSTR lpHeaderInfo,
2546 IN DWORD dwHeaderSize,
2547 IN LPCWSTR lpszFileExtension,
2548 IN LPCWSTR lpszOriginalUrl
2552 BOOL bSuccess = FALSE;
2554 CHAR *header_info = NULL;
2556 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2557 debugstr_w(lpszUrlName),
2558 debugstr_w(lpszLocalFileName),
2562 debugstr_w(lpszFileExtension),
2563 debugstr_w(lpszOriginalUrl));
2565 if (!lpHeaderInfo ||
2566 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2567 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2570 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2571 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2572 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2578 dwError = GetLastError();
2582 HeapFree(GetProcessHeap(), 0, header_info);
2584 SetLastError(dwError);
2590 /***********************************************************************
2591 * ReadUrlCacheEntryStream (WININET.@)
2594 BOOL WINAPI ReadUrlCacheEntryStream(
2595 IN HANDLE hUrlCacheStream,
2596 IN DWORD dwLocation,
2597 IN OUT LPVOID lpBuffer,
2598 IN OUT LPDWORD lpdwLen,
2602 /* Get handle to file from 'stream' */
2603 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2605 if (dwReserved != 0)
2607 ERR("dwReserved != 0\n");
2608 SetLastError(ERROR_INVALID_PARAMETER);
2612 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2614 SetLastError(ERROR_INVALID_HANDLE);
2618 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2620 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2623 /***********************************************************************
2624 * RetrieveUrlCacheEntryStreamA (WININET.@)
2627 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2628 IN LPCSTR lpszUrlName,
2629 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2630 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2631 IN BOOL fRandomRead,
2635 /* NOTE: this is not the same as the way that the native
2636 * version allocates 'stream' handles. I did it this way
2637 * as it is much easier and no applications should depend
2638 * on this behaviour. (Native version appears to allocate
2639 * indices into a table)
2641 STREAM_HANDLE * pStream;
2644 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2645 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2647 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2649 lpdwCacheEntryInfoBufferSize,
2655 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2660 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2662 if (hFile == INVALID_HANDLE_VALUE)
2665 /* allocate handle storage space */
2666 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2670 SetLastError(ERROR_OUTOFMEMORY);
2674 pStream->hFile = hFile;
2675 strcpy(pStream->lpszUrl, lpszUrlName);
2676 return (HANDLE)pStream;
2679 /***********************************************************************
2680 * RetrieveUrlCacheEntryStreamW (WININET.@)
2683 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2684 IN LPCWSTR lpszUrlName,
2685 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2686 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2687 IN BOOL fRandomRead,
2691 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2692 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2696 /***********************************************************************
2697 * UnlockUrlCacheEntryStream (WININET.@)
2700 BOOL WINAPI UnlockUrlCacheEntryStream(
2701 IN HANDLE hUrlCacheStream,
2705 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2707 if (dwReserved != 0)
2709 ERR("dwReserved != 0\n");
2710 SetLastError(ERROR_INVALID_PARAMETER);
2714 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2716 SetLastError(ERROR_INVALID_HANDLE);
2720 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2723 /* close file handle */
2724 CloseHandle(pStream->hFile);
2726 /* free allocated space */
2727 HeapFree(GetProcessHeap(), 0, pStream);
2733 /***********************************************************************
2734 * DeleteUrlCacheEntryA (WININET.@)
2737 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2739 URLCACHECONTAINER * pContainer;
2740 LPURLCACHE_HEADER pHeader;
2741 struct _HASH_ENTRY * pHashEntry;
2742 CACHEFILE_ENTRY * pEntry;
2744 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2746 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
2749 if (!URLCacheContainer_OpenIndex(pContainer))
2752 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2755 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2757 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2758 TRACE("entry %s not found!\n", lpszUrlName);
2759 SetLastError(ERROR_FILE_NOT_FOUND);
2763 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2764 URLCache_DeleteEntry(pHeader, pEntry);
2766 URLCache_DeleteEntryFromHash(pHashEntry);
2768 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2773 /***********************************************************************
2774 * DeleteUrlCacheEntryW (WININET.@)
2777 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2779 URLCACHECONTAINER * pContainer;
2780 LPURLCACHE_HEADER pHeader;
2781 struct _HASH_ENTRY * pHashEntry;
2782 CACHEFILE_ENTRY * pEntry;
2786 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2788 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2789 urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
2792 SetLastError(ERROR_OUTOFMEMORY);
2795 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, urlA, url_len, NULL, NULL);
2797 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
2799 HeapFree(GetProcessHeap(), 0, urlA);
2802 if (!URLCacheContainer_OpenIndex(pContainer))
2804 HeapFree(GetProcessHeap(), 0, urlA);
2807 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2809 HeapFree(GetProcessHeap(), 0, urlA);
2813 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
2815 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2816 TRACE("entry %s not found!\n", debugstr_a(urlA));
2817 HeapFree(GetProcessHeap(), 0, urlA);
2818 SetLastError(ERROR_FILE_NOT_FOUND);
2822 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2823 URLCache_DeleteEntry(pHeader, pEntry);
2825 URLCache_DeleteEntryFromHash(pHashEntry);
2827 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2829 HeapFree(GetProcessHeap(), 0, urlA);
2833 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2835 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2839 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2841 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2845 /***********************************************************************
2846 * CreateCacheContainerA (WININET.@)
2848 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2849 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2851 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2852 d1, d2, d3, d4, d5, d6, d7, d8);
2856 /***********************************************************************
2857 * CreateCacheContainerW (WININET.@)
2859 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2860 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2862 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2863 d1, d2, d3, d4, d5, d6, d7, d8);
2867 /***********************************************************************
2868 * FindFirstUrlCacheContainerA (WININET.@)
2870 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2872 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
2876 /***********************************************************************
2877 * FindFirstUrlCacheContainerW (WININET.@)
2879 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2881 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
2885 /***********************************************************************
2886 * FindNextUrlCacheContainerA (WININET.@)
2888 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
2890 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2894 /***********************************************************************
2895 * FindNextUrlCacheContainerW (WININET.@)
2897 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
2899 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2903 HANDLE WINAPI FindFirstUrlCacheEntryExA(
2904 LPCSTR lpszUrlSearchPattern,
2908 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2909 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2911 LPDWORD pcbReserved2,
2915 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
2916 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2917 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2918 SetLastError(ERROR_FILE_NOT_FOUND);
2922 HANDLE WINAPI FindFirstUrlCacheEntryExW(
2923 LPCWSTR lpszUrlSearchPattern,
2927 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2928 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2930 LPDWORD pcbReserved2,
2934 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
2935 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2936 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2937 SetLastError(ERROR_FILE_NOT_FOUND);
2941 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
2943 typedef struct URLCacheFindEntryHandle
2946 LPWSTR lpszUrlSearchPattern;
2947 DWORD dwContainerIndex;
2948 DWORD dwHashTableIndex;
2949 DWORD dwHashEntryIndex;
2950 } URLCacheFindEntryHandle;
2952 /***********************************************************************
2953 * FindFirstUrlCacheEntryA (WININET.@)
2956 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
2957 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2959 URLCacheFindEntryHandle *pEntryHandle;
2961 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2963 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
2967 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
2968 if (lpszUrlSearchPattern)
2970 int len = MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, NULL, 0);
2971 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2972 if (!pEntryHandle->lpszUrlSearchPattern)
2974 HeapFree(GetProcessHeap(), 0, pEntryHandle);
2977 MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, pEntryHandle->lpszUrlSearchPattern, len);
2980 pEntryHandle->lpszUrlSearchPattern = NULL;
2981 pEntryHandle->dwContainerIndex = 0;
2982 pEntryHandle->dwHashTableIndex = 0;
2983 pEntryHandle->dwHashEntryIndex = 0;
2985 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
2987 HeapFree(GetProcessHeap(), 0, pEntryHandle);
2990 return pEntryHandle;
2993 /***********************************************************************
2994 * FindFirstUrlCacheEntryW (WININET.@)
2997 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
2998 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3000 URLCacheFindEntryHandle *pEntryHandle;
3002 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3004 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3008 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3009 if (lpszUrlSearchPattern)
3011 int len = strlenW(lpszUrlSearchPattern);
3012 pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
3013 if (!pEntryHandle->lpszUrlSearchPattern)
3015 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3018 memcpy(pEntryHandle->lpszUrlSearchPattern, lpszUrlSearchPattern, (len + 1) * sizeof(WCHAR));
3021 pEntryHandle->lpszUrlSearchPattern = NULL;
3022 pEntryHandle->dwContainerIndex = 0;
3023 pEntryHandle->dwHashTableIndex = 0;
3024 pEntryHandle->dwHashEntryIndex = 0;
3026 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3028 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3031 return pEntryHandle;
3034 /***********************************************************************
3035 * FindNextUrlCacheEntryA (WININET.@)
3037 BOOL WINAPI FindNextUrlCacheEntryA(
3039 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3040 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3042 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3043 URLCACHECONTAINER * pContainer;
3045 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3047 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3049 SetLastError(ERROR_INVALID_HANDLE);
3053 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3054 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3056 LPURLCACHE_HEADER pHeader;
3057 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3059 if (!URLCacheContainer_OpenIndex(pContainer))
3062 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3065 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3066 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3068 const struct _HASH_ENTRY *pHashEntry = NULL;
3069 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3070 pEntryHandle->dwHashEntryIndex++)
3072 const URL_CACHEFILE_ENTRY *pUrlEntry;
3073 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3075 if (pEntry->dwSignature != URL_SIGNATURE)
3078 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3079 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3080 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3082 if (!URLCache_CopyEntry(
3085 lpNextCacheEntryInfo,
3086 lpdwNextCacheEntryInfoBufferSize,
3088 FALSE /* not UNICODE */))
3090 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3093 TRACE("Local File Name: %s\n", debugstr_a(lpNextCacheEntryInfo->lpszLocalFileName));
3095 /* increment the current index so that next time the function
3096 * is called the next entry is returned */
3097 pEntryHandle->dwHashEntryIndex++;
3098 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3103 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3106 SetLastError(ERROR_NO_MORE_ITEMS);
3110 BOOL WINAPI FindNextUrlCacheEntryW(
3112 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3113 LPDWORD lpdwNextCacheEntryInfoBufferSize
3116 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3117 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3121 /***********************************************************************
3122 * FindCloseUrlCache (WININET.@)
3124 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3126 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3128 TRACE("(%p)\n", hEnumHandle);
3130 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3132 SetLastError(ERROR_INVALID_HANDLE);
3136 pEntryHandle->dwMagic = 0;
3137 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3138 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3143 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3144 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3146 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3147 dwSearchCondition, lpGroupId, lpReserved);
3151 BOOL WINAPI FindNextUrlCacheEntryExA(
3153 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3154 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3156 LPDWORD pcbReserved2,
3160 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3161 lpReserved, pcbReserved2, lpReserved3);
3165 BOOL WINAPI FindNextUrlCacheEntryExW(
3167 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3168 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3170 LPDWORD pcbReserved2,
3174 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3175 lpReserved, pcbReserved2, lpReserved3);
3179 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3181 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3185 /***********************************************************************
3186 * CreateUrlCacheGroup (WININET.@)
3189 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3191 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3195 /***********************************************************************
3196 * DeleteUrlCacheGroup (WININET.@)
3199 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3201 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3202 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3206 /***********************************************************************
3207 * SetUrlCacheEntryGroupA (WININET.@)
3210 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3211 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3214 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3215 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3216 pbGroupAttributes, cbGroupAttributes, lpReserved);
3217 SetLastError(ERROR_FILE_NOT_FOUND);
3221 /***********************************************************************
3222 * SetUrlCacheEntryGroupW (WININET.@)
3225 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3226 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3229 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3230 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3231 pbGroupAttributes, cbGroupAttributes, lpReserved);
3232 SetLastError(ERROR_FILE_NOT_FOUND);
3236 /***********************************************************************
3237 * GetUrlCacheConfigInfoW (WININET.@)
3239 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3241 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3242 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3246 /***********************************************************************
3247 * GetUrlCacheConfigInfoA (WININET.@)
3249 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3251 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3253 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3254 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3258 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3259 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3260 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3262 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3263 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3264 lpdwGroupInfo, lpReserved);
3268 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3269 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3270 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3272 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3273 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3274 lpdwGroupInfo, lpReserved);
3278 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3279 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3281 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3282 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3286 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3287 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3289 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3290 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3294 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3296 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3300 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3302 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3306 /***********************************************************************
3307 * DeleteIE3Cache (WININET.@)
3309 * Deletes the files used by the IE3 URL caching system.
3312 * hWnd [I] A dummy window.
3313 * hInst [I] Instance of process calling the function.
3314 * lpszCmdLine [I] Options used by function.
3315 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3317 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3319 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3323 /***********************************************************************
3324 * IsUrlCacheEntryExpiredA (WININET.@)
3328 * dwFlags [I] Unknown
3329 * pftLastModified [O] Last modified time
3331 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3333 LPURLCACHE_HEADER pHeader;
3334 struct _HASH_ENTRY * pHashEntry;
3335 const CACHEFILE_ENTRY * pEntry;
3336 const URL_CACHEFILE_ENTRY * pUrlEntry;
3337 URLCACHECONTAINER * pContainer;
3339 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3341 if (!URLCacheContainers_FindContainerA(url, &pContainer))
3344 if (!URLCacheContainer_OpenIndex(pContainer))
3347 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3350 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3352 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3353 TRACE("entry %s not found!\n", url);
3354 SetLastError(ERROR_FILE_NOT_FOUND);
3358 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3359 if (pEntry->dwSignature != URL_SIGNATURE)
3361 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3362 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3363 SetLastError(ERROR_FILE_NOT_FOUND);
3367 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3369 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3371 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3376 /***********************************************************************
3377 * IsUrlCacheEntryExpiredW (WININET.@)
3381 * dwFlags [I] Unknown
3382 * pftLastModified [O] Last modified time
3384 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3386 LPURLCACHE_HEADER pHeader;
3387 struct _HASH_ENTRY * pHashEntry;
3388 const CACHEFILE_ENTRY * pEntry;
3389 const URL_CACHEFILE_ENTRY * pUrlEntry;
3390 URLCACHECONTAINER * pContainer;
3392 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3394 if (!URLCacheContainers_FindContainerW(url, &pContainer))
3397 if (!URLCacheContainer_OpenIndex(pContainer))
3400 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3403 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3405 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3406 TRACE("entry %s not found!\n", debugstr_w(url));
3407 SetLastError(ERROR_FILE_NOT_FOUND);
3411 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3412 if (pEntry->dwSignature != URL_SIGNATURE)
3414 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3415 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3416 SetLastError(ERROR_FILE_NOT_FOUND);
3420 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3422 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3424 URLCacheContainer_UnlockIndex(pContainer, pHeader);