2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003-2008 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"
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
31 #if defined(__MINGW32__) || defined (_MSC_VER)
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
56 #include "wine/unicode.h"
57 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
61 #define ENTRY_START_OFFSET 0x4000
64 #define HASHTABLE_SIZE 448
65 #define HASHTABLE_BLOCKSIZE 7
66 #define HASHTABLE_FREE 3
67 #define ALLOCATION_TABLE_OFFSET 0x250
68 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
69 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
70 #define NEWFILE_NUM_BLOCKS 0xd80
71 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
73 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
74 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
75 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
76 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
77 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
79 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
81 typedef struct _CACHEFILE_ENTRY
85 DWORD dwSignature; /* e.g. "URL " */
86 /* CHAR szSignature[4];
88 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
91 typedef struct _URL_CACHEFILE_ENTRY
93 CACHEFILE_ENTRY CacheFileEntry;
94 FILETIME LastModifiedTime;
95 FILETIME LastAccessTime;
96 WORD wExpiredDate; /* expire date in dos format */
97 WORD wExpiredTime; /* expire time in dos format */
98 DWORD dwUnknown1; /* usually zero */
99 ULARGE_INTEGER size; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow/High */
100 DWORD dwUnknown2; /* usually zero */
101 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
102 DWORD dwUnknown3; /* usually 0x60 */
103 DWORD dwOffsetUrl; /* offset of start of url from start of entry */
104 BYTE CacheDir; /* index of cache directory this url is stored in */
105 BYTE Unknown4; /* usually zero */
106 WORD wUnknown5; /* usually 0x1010 */
107 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
108 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
109 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
110 DWORD dwHeaderInfoSize;
111 DWORD dwOffsetFileExtension; /* offset of start of file extension from start of entry */
112 WORD wLastSyncDate; /* last sync date in dos format */
113 WORD wLastSyncTime; /* last sync time in dos format */
114 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
115 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
116 WORD wUnknownDate; /* usually same as wLastSyncDate */
117 WORD wUnknownTime; /* usually same as wLastSyncTime */
118 DWORD dwUnknown7; /* usually zero */
119 DWORD dwUnknown8; /* usually zero */
120 /* packing to dword align start of next field */
121 /* CHAR szSourceUrlName[]; (url) */
122 /* packing to dword align start of next field */
123 /* CHAR szLocalFileName[]; (local file name excluding path) */
124 /* packing to dword align start of next field */
125 /* CHAR szHeaderInfo[]; (header info) */
126 } URL_CACHEFILE_ENTRY;
134 typedef struct _HASH_CACHEFILE_ENTRY
136 CACHEFILE_ENTRY CacheFileEntry;
138 DWORD dwHashTableNumber;
139 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
140 } HASH_CACHEFILE_ENTRY;
142 typedef struct _DIRECTORY_DATA
145 char filename[DIR_LENGTH];
148 typedef struct _URLCACHE_HEADER
150 char szSignature[28];
152 DWORD dwOffsetFirstHashTable;
153 DWORD dwIndexCapacityInBlocks;
156 ULARGE_INTEGER CacheLimit;
157 ULARGE_INTEGER CacheUsage;
158 ULARGE_INTEGER ExemptUsage;
159 DWORD DirectoryCount; /* number of directory_data's */
160 DIRECTORY_DATA directory_data[1]; /* first directory entry */
161 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
162 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
164 typedef struct _STREAM_HANDLE
170 typedef struct _URLCACHECONTAINER
172 struct list entry; /* part of a list */
173 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
174 LPWSTR path; /* path to url container directory */
175 HANDLE hMapping; /* handle of file mapping */
176 DWORD file_size; /* size of file when mapping was opened */
177 HANDLE hMutex; /* handle of mutex */
181 /* List of all containers available */
182 static struct list UrlContainers = LIST_INIT(UrlContainers);
184 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash);
186 /***********************************************************************
187 * URLCache_PathToObjectName (Internal)
189 * Converts a path to a name suitable for use as a Win32 object name.
190 * Replaces '\\' characters in-place with the specified character
191 * (usually '_' or '!')
197 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
199 for (; *lpszPath; lpszPath++)
201 if (*lpszPath == '\\')
206 /***********************************************************************
207 * URLCacheContainer_OpenIndex (Internal)
209 * Opens the index file and saves mapping handle in hCacheIndexMapping
212 * ERROR_SUCCESS if succeeded
213 * Any other Win32 error code if failed
216 static DWORD URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
219 WCHAR wszFilePath[MAX_PATH];
222 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
223 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
225 if (pContainer->hMapping)
226 return ERROR_SUCCESS;
228 strcpyW(wszFilePath, pContainer->path);
229 strcatW(wszFilePath, wszIndex);
231 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
232 if (hFile == INVALID_HANDLE_VALUE)
234 /* Maybe the directory wasn't there? Try to create it */
235 if (CreateDirectoryW(pContainer->path, 0))
236 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
238 if (hFile == INVALID_HANDLE_VALUE)
240 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath));
241 return GetLastError();
244 /* At this stage we need the mutex because we may be about to create the
247 WaitForSingleObject(pContainer->hMutex, INFINITE);
249 dwFileSize = GetFileSize(hFile, NULL);
250 if (dwFileSize == INVALID_FILE_SIZE)
252 ReleaseMutex(pContainer->hMutex);
253 return GetLastError();
258 static const CHAR szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content";
260 char achZeroes[0x1000];
262 DWORD dwError = ERROR_SUCCESS;
264 /* Write zeroes to the entire file so we can safely map it without
265 * fear of getting a SEGV because the disk is full.
267 memset(achZeroes, 0, sizeof(achZeroes));
268 for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes))
270 DWORD dwWrite = sizeof(achZeroes);
273 if (NEWFILE_SIZE - dwOffset < dwWrite)
274 dwWrite = NEWFILE_SIZE - dwOffset;
275 if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) ||
276 dwWritten != dwWrite)
278 /* If we fail to write, we need to return the error that
279 * cause the problem and also make sure the file is no
280 * longer there, if possible.
282 dwError = GetLastError();
288 if (dwError == ERROR_SUCCESS)
290 HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL);
294 URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE);
299 WCHAR wszDirPath[MAX_PATH];
302 HASH_CACHEFILE_ENTRY *pHashEntry;
304 dwFileSize = NEWFILE_SIZE;
306 /* First set some constants and defaults in the header */
307 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
308 pHeader->dwFileSize = dwFileSize;
309 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
310 /* 127MB - taken from default for Windows 2000 */
311 pHeader->CacheLimit.QuadPart = 0x07ff5400;
312 /* Copied from a Windows 2000 cache index */
313 pHeader->DirectoryCount = 4;
315 /* If the registry has a cache size set, use the registry value */
316 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
319 DWORD len = sizeof(dw);
322 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
323 (BYTE *) &dw, &len) == ERROR_SUCCESS &&
324 keytype == REG_DWORD)
326 pHeader->CacheLimit.QuadPart = (ULONGLONG)dw * 1024;
331 URLCache_CreateHashTable(pHeader, NULL, &pHashEntry);
333 /* Last step - create the directories */
335 strcpyW(wszDirPath, pContainer->path);
336 pwchDir = wszDirPath + strlenW(wszDirPath);
339 GetSystemTimeAsFileTime(&ft);
341 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
343 pHeader->directory_data[i].dwNumFiles = 0;
347 ULONGLONG n = ft.dwHighDateTime;
349 /* Generate a file name to attempt to create.
350 * This algorithm will create what will appear
351 * to be random and unrelated directory names
352 * of up to 9 characters in length.
355 n += ft.dwLowDateTime;
356 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
358 for (k = 0; k < 8; ++k)
362 /* Dividing by a prime greater than 36 helps
363 * with the appearance of randomness
368 pwchDir[k] = '0' + r;
370 pwchDir[k] = 'A' + (r - 10);
373 if (CreateDirectoryW(wszDirPath, 0))
375 /* The following is OK because we generated an
376 * 8 character directory name made from characters
377 * [A-Z0-9], which are equivalent for all code
378 * pages and for UTF-16
380 for (k = 0; k < 8; ++k)
381 pHeader->directory_data[i].filename[k] = pwchDir[k];
386 /* Give up. The most likely cause of this
387 * is a full disk, but whatever the cause
388 * is, it should be more than apparent that
391 dwError = GetLastError();
397 UnmapViewOfFile(pHeader);
401 dwError = GetLastError();
403 CloseHandle(hMapping);
407 dwError = GetLastError();
414 DeleteFileW(wszFilePath);
415 ReleaseMutex(pContainer->hMutex);
421 ReleaseMutex(pContainer->hMutex);
423 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
424 URLCache_PathToObjectName(wszFilePath, '_');
425 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
426 if (!pContainer->hMapping)
427 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
429 if (!pContainer->hMapping)
431 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
432 return GetLastError();
435 return ERROR_SUCCESS;
438 /***********************************************************************
439 * URLCacheContainer_CloseIndex (Internal)
447 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
449 CloseHandle(pContainer->hMapping);
450 pContainer->hMapping = NULL;
453 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
455 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
456 int cache_prefix_len = strlenW(cache_prefix);
463 pContainer->hMapping = NULL;
464 pContainer->file_size = 0;
466 pContainer->path = heap_strdupW(path);
467 if (!pContainer->path)
469 HeapFree(GetProcessHeap(), 0, pContainer);
473 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
474 if (!pContainer->cache_prefix)
476 HeapFree(GetProcessHeap(), 0, pContainer->path);
477 HeapFree(GetProcessHeap(), 0, pContainer);
481 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
483 CharLowerW(mutex_name);
484 URLCache_PathToObjectName(mutex_name, '!');
486 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
488 ERR("couldn't create mutex (error is %d)\n", GetLastError());
489 HeapFree(GetProcessHeap(), 0, pContainer->path);
490 HeapFree(GetProcessHeap(), 0, pContainer);
494 list_add_head(&UrlContainers, &pContainer->entry);
499 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
501 list_remove(&pContainer->entry);
503 URLCacheContainer_CloseIndex(pContainer);
504 CloseHandle(pContainer->hMutex);
505 HeapFree(GetProcessHeap(), 0, pContainer->path);
506 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
507 HeapFree(GetProcessHeap(), 0, pContainer);
510 void URLCacheContainers_CreateDefaults(void)
512 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
513 static const WCHAR UrlPrefix[] = {0};
514 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
515 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
516 static const WCHAR CookieSuffix[] = {0};
517 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
520 int nFolder; /* CSIDL_* constant */
521 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
522 const WCHAR * cache_prefix; /* prefix used to reference the container */
523 } DefaultContainerData[] =
525 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
526 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
527 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
531 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
533 WCHAR wszCachePath[MAX_PATH];
534 WCHAR wszMutexName[MAX_PATH];
535 int path_len, suffix_len;
537 if (!SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE))
539 ERR("Couldn't get path for default container %u\n", i);
542 path_len = strlenW(wszCachePath);
543 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
545 if (path_len + suffix_len + 2 > MAX_PATH)
547 ERR("Path too long\n");
551 wszCachePath[path_len] = '\\';
552 wszCachePath[path_len+1] = 0;
554 strcpyW(wszMutexName, wszCachePath);
558 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
559 wszCachePath[path_len + suffix_len + 1] = '\\';
560 wszCachePath[path_len + suffix_len + 2] = '\0';
563 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
567 void URLCacheContainers_DeleteAll(void)
569 while(!list_empty(&UrlContainers))
570 URLCacheContainer_DeleteContainer(
571 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
575 static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
577 URLCACHECONTAINER * pContainer;
579 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
582 return ERROR_INVALID_PARAMETER;
584 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
586 int prefix_len = strlenW(pContainer->cache_prefix);
587 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
589 TRACE("found container with prefix %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
590 *ppContainer = pContainer;
591 return ERROR_SUCCESS;
594 ERR("no container found\n");
595 return ERROR_FILE_NOT_FOUND;
598 static DWORD URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
603 if (lpszUrl && !(url = heap_strdupAtoW(lpszUrl)))
604 return ERROR_OUTOFMEMORY;
606 ret = URLCacheContainers_FindContainerW(url, ppContainer);
607 HeapFree(GetProcessHeap(), 0, url);
611 static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, URLCACHECONTAINER ** ppContainer)
614 URLCACHECONTAINER * pContainer;
616 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern));
618 /* non-NULL search pattern only returns one container ever */
619 if (lpwszSearchPattern && dwIndex > 0)
622 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
624 if (lpwszSearchPattern)
626 if (!strcmpW(pContainer->cache_prefix, lpwszSearchPattern))
628 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
629 *ppContainer = pContainer;
637 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
638 *ppContainer = pContainer;
647 /***********************************************************************
648 * URLCacheContainer_LockIndex (Internal)
650 * Locks the index for system-wide exclusive access.
653 * Cache file header if successful
654 * NULL if failed and calls SetLastError.
656 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
660 URLCACHE_HEADER * pHeader;
664 WaitForSingleObject(pContainer->hMutex, INFINITE);
666 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
670 ReleaseMutex(pContainer->hMutex);
671 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
674 pHeader = (URLCACHE_HEADER *)pIndexData;
676 /* file has grown - we need to remap to prevent us getting
677 * access violations when we try and access beyond the end
678 * of the memory mapped file */
679 if (pHeader->dwFileSize != pContainer->file_size)
681 UnmapViewOfFile( pHeader );
682 URLCacheContainer_CloseIndex(pContainer);
683 error = URLCacheContainer_OpenIndex(pContainer);
684 if (error != ERROR_SUCCESS)
686 ReleaseMutex(pContainer->hMutex);
690 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
694 ReleaseMutex(pContainer->hMutex);
695 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
698 pHeader = (URLCACHE_HEADER *)pIndexData;
701 TRACE("Signature: %s, file size: %d bytes\n", pHeader->szSignature, pHeader->dwFileSize);
703 for (index = 0; index < pHeader->DirectoryCount; index++)
705 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
711 /***********************************************************************
712 * URLCacheContainer_UnlockIndex (Internal)
715 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
718 ReleaseMutex(pContainer->hMutex);
719 return UnmapViewOfFile(pHeader);
724 #define CHAR_BIT (8 * sizeof(CHAR))
727 /***********************************************************************
728 * URLCache_Allocation_BlockIsFree (Internal)
730 * Is the specified block number free?
737 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
739 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
740 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
743 /***********************************************************************
744 * URLCache_Allocation_BlockFree (Internal)
746 * Marks the specified block as free
752 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
754 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
755 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
758 /***********************************************************************
759 * URLCache_Allocation_BlockAllocate (Internal)
761 * Marks the specified block as allocated
767 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
769 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
770 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
773 /***********************************************************************
774 * URLCache_FindFirstFreeEntry (Internal)
776 * Finds and allocates the first block of free space big enough and
777 * sets ppEntry to point to it.
780 * TRUE if it had enough space
781 * FALSE if it couldn't find enough space
784 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
786 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
789 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
791 for (dwFreeCounter = 0;
792 dwFreeCounter < dwBlocksNeeded &&
793 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
794 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
796 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
798 if (dwFreeCounter == dwBlocksNeeded)
801 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
802 for (index = 0; index < dwBlocksNeeded; index++)
803 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
804 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
805 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
809 FIXME("Grow file\n");
813 /***********************************************************************
814 * URLCache_DeleteEntry (Internal)
816 * Deletes the specified entry and frees the space allocated to it
819 * TRUE if it succeeded
823 static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, CACHEFILE_ENTRY * pEntry)
827 BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
829 /* update allocation table */
830 dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE;
831 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
832 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
834 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
838 /***********************************************************************
839 * URLCache_LocalFileNameToPathW (Internal)
841 * Copies the full path to the specified buffer given the local file
842 * name and the index of the directory it is in. Always sets value in
843 * lpBufferSize to the required buffer size (in bytes).
846 * TRUE if the buffer was big enough
847 * FALSE if the buffer was too small
850 static BOOL URLCache_LocalFileNameToPathW(
851 const URLCACHECONTAINER * pContainer,
852 LPCURLCACHE_HEADER pHeader,
853 LPCSTR szLocalFileName,
859 int path_len = strlenW(pContainer->path);
860 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
861 if (Directory >= pHeader->DirectoryCount)
867 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
868 if (nRequired <= *lpBufferSize)
872 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
873 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
874 wszPath[dir_len + path_len] = '\\';
875 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
876 *lpBufferSize = nRequired;
879 *lpBufferSize = nRequired;
883 /***********************************************************************
884 * URLCache_LocalFileNameToPathA (Internal)
886 * Copies the full path to the specified buffer given the local file
887 * name and the index of the directory it is in. Always sets value in
888 * lpBufferSize to the required buffer size.
891 * TRUE if the buffer was big enough
892 * FALSE if the buffer was too small
895 static BOOL URLCache_LocalFileNameToPathA(
896 const URLCACHECONTAINER * pContainer,
897 LPCURLCACHE_HEADER pHeader,
898 LPCSTR szLocalFileName,
904 int path_len, file_name_len, dir_len;
906 if (Directory >= pHeader->DirectoryCount)
912 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL) - 1;
913 file_name_len = strlen(szLocalFileName) + 1 /* for nul-terminator */;
914 dir_len = DIR_LENGTH;
916 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(char);
917 if (nRequired < *lpBufferSize)
919 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, path_len, NULL, NULL);
920 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
921 szPath[path_len + dir_len] = '\\';
922 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
923 *lpBufferSize = nRequired;
926 *lpBufferSize = nRequired;
930 /***********************************************************************
931 * URLCache_CopyEntry (Internal)
933 * Copies an entry from the cache index file to the Win32 structure
936 * ERROR_SUCCESS if the buffer was big enough
937 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
940 static DWORD URLCache_CopyEntry(
941 URLCACHECONTAINER * pContainer,
942 LPCURLCACHE_HEADER pHeader,
943 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
944 LPDWORD lpdwBufferSize,
945 const URL_CACHEFILE_ENTRY * pUrlEntry,
949 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
951 if (*lpdwBufferSize >= dwRequiredSize)
953 lpCacheEntryInfo->lpHeaderInfo = NULL;
954 lpCacheEntryInfo->lpszFileExtension = NULL;
955 lpCacheEntryInfo->lpszLocalFileName = NULL;
956 lpCacheEntryInfo->lpszSourceUrlName = NULL;
957 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
958 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
959 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
960 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
961 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->size.u.HighPart;
962 lpCacheEntryInfo->dwSizeLow = pUrlEntry->size.u.LowPart;
963 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
964 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
965 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
966 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
967 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
968 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
969 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
970 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
973 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
974 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
975 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
977 lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0);
979 lenUrl = strlen((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
980 dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
982 /* FIXME: is source url optional? */
983 if (*lpdwBufferSize >= dwRequiredSize)
985 DWORD lenUrlBytes = (lenUrl+1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
987 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrlBytes;
989 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
991 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lenUrlBytes);
994 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
995 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
996 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
998 if (pUrlEntry->dwOffsetLocalName)
1000 LONG nLocalFilePathSize;
1001 LPSTR lpszLocalFileName;
1002 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
1003 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
1004 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
1005 (!bUnicode && URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize)))
1007 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
1009 dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ;
1011 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1012 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1013 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1015 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
1017 if (*lpdwBufferSize >= dwRequiredSize)
1019 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
1020 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
1021 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
1023 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1024 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1025 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1027 if (pUrlEntry->dwOffsetFileExtension)
1032 lenExtension = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, NULL, 0);
1034 lenExtension = strlen((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension) + 1;
1035 dwRequiredSize += lenExtension * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
1037 if (*lpdwBufferSize >= dwRequiredSize)
1039 lpCacheEntryInfo->lpszFileExtension = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenExtension;
1041 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenExtension);
1043 memcpy(lpCacheEntryInfo->lpszFileExtension, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, lenExtension * sizeof(CHAR));
1046 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1047 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1048 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1051 if (dwRequiredSize > *lpdwBufferSize)
1053 *lpdwBufferSize = dwRequiredSize;
1054 return ERROR_INSUFFICIENT_BUFFER;
1056 *lpdwBufferSize = dwRequiredSize;
1057 return ERROR_SUCCESS;
1061 /***********************************************************************
1062 * URLCache_SetEntryInfo (Internal)
1064 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1065 * according to the flags set by dwFieldControl.
1068 * ERROR_SUCCESS if the buffer was big enough
1069 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1072 static DWORD URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1074 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1075 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1076 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1077 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1078 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1079 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1080 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1081 FileTimeToDosDateTime(&lpCacheEntryInfo->ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
1082 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1083 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1084 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1085 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1086 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1087 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1088 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1089 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1091 return ERROR_SUCCESS;
1094 /***********************************************************************
1095 * URLCache_HashKey (Internal)
1097 * Returns the hash key for a given string
1100 * hash key for the string
1103 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1105 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1106 * but the algorithm and result are not the same!
1108 static const unsigned char lookupTable[256] =
1110 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1111 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1112 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1113 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1114 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1115 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1116 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1117 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1118 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1119 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1120 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1121 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1122 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1123 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1124 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1125 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1126 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1127 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1128 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1129 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1130 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1131 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1132 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1133 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1134 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1135 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1136 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1137 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1138 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1139 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1140 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1141 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1146 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1147 key[i] = lookupTable[i];
1149 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
1151 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1152 key[i] = lookupTable[*lpszKey ^ key[i]];
1155 return *(DWORD *)key;
1158 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
1160 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
1163 static inline BOOL URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY *pHashEntry)
1165 /* check pHashEntry located within acceptable bounds in the URL cache mapping */
1166 return ((DWORD)((const BYTE*)pHashEntry - (const BYTE*)pHeader) >= ENTRY_START_OFFSET) &&
1167 ((DWORD)((const BYTE*)pHashEntry - (const BYTE*)pHeader) < pHeader->dwFileSize);
1170 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1172 /* structure of hash table:
1173 * 448 entries divided into 64 blocks
1174 * each block therefore contains a chain of 7 key/offset pairs
1175 * how position in table is calculated:
1176 * 1. the url is hashed in helper function
1177 * 2. the key % 64 * 8 is the offset
1178 * 3. the key in the hash table is the hash key aligned to 64
1181 * there can be multiple hash tables in the file and the offset to
1182 * the next one is stored in the header of the hash table
1184 DWORD key = URLCache_HashKey(lpszUrl);
1185 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1186 HASH_CACHEFILE_ENTRY * pHashEntry;
1187 DWORD dwHashTableNumber = 0;
1189 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1191 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1192 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1193 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1196 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1198 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1201 /* make sure that it is in fact a hash entry */
1202 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1204 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1208 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1210 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1211 if (key == (pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
1213 /* FIXME: we should make sure that this is the right element
1214 * before returning and claiming that it is. We can do this
1215 * by doing a simple compare between the URL we were given
1216 * and the URL stored in the entry. However, this assumes
1217 * we know the format of all the entries stored in the
1219 *ppHashEntry = pHashElement;
1227 static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1232 urlA = heap_strdupWtoA(lpszUrl);
1235 SetLastError(ERROR_OUTOFMEMORY);
1239 ret = URLCache_FindHash(pHeader, urlA, ppHashEntry);
1240 HeapFree(GetProcessHeap(), 0, urlA);
1244 /***********************************************************************
1245 * URLCache_HashEntrySetUse (Internal)
1247 * Searches all the hash tables in the index for the given URL and
1248 * sets the use count (stored or'ed with key)
1251 * TRUE if the entry was found
1252 * FALSE if the entry could not be found
1255 static BOOL URLCache_HashEntrySetUse(struct _HASH_ENTRY * pHashEntry, DWORD dwUseCount)
1257 pHashEntry->dwHashKey = dwUseCount | (pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1261 /***********************************************************************
1262 * URLCache_DeleteEntryFromHash (Internal)
1264 * Searches all the hash tables in the index for the given URL and
1265 * then if found deletes the entry.
1268 * TRUE if the entry was found
1269 * FALSE if the entry could not be found
1272 static BOOL URLCache_DeleteEntryFromHash(struct _HASH_ENTRY * pHashEntry)
1274 pHashEntry->dwHashKey = HASHTABLE_FREE;
1275 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1279 /***********************************************************************
1280 * URLCache_AddEntryToHash (Internal)
1282 * Searches all the hash tables for a free slot based on the offset
1283 * generated from the hash key. If a free slot is found, the offset and
1284 * key are entered into the hash table.
1287 * ERROR_SUCCESS if the entry was added
1288 * Any other Win32 error code if the entry could not be added
1291 static DWORD URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1293 /* see URLCache_FindEntryInHash for structure of hash tables */
1295 DWORD key = URLCache_HashKey(lpszUrl);
1296 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1297 HASH_CACHEFILE_ENTRY * pHashEntry;
1298 DWORD dwHashTableNumber = 0;
1301 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1303 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1304 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1305 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1308 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1310 ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1313 /* make sure that it is in fact a hash entry */
1314 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1316 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1320 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1322 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1323 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1325 pHashElement->dwHashKey = key;
1326 pHashElement->dwOffsetEntry = dwOffsetEntry;
1327 return ERROR_SUCCESS;
1331 error = URLCache_CreateHashTable(pHeader, pHashEntry, &pHashEntry);
1332 if (error != ERROR_SUCCESS)
1335 pHashEntry->HashTable[offset].dwHashKey = key;
1336 pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry;
1337 return ERROR_SUCCESS;
1340 /***********************************************************************
1341 * URLCache_CreateHashTable (Internal)
1343 * Creates a new hash table in free space and adds it to the chain of existing
1347 * ERROR_SUCCESS if the hash table was created
1348 * ERROR_DISK_FULL if the hash table could not be created
1351 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash)
1356 if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)ppHash))
1358 FIXME("no free space for hash table\n");
1359 return ERROR_DISK_FULL;
1362 dwOffset = (BYTE *)*ppHash - (BYTE *)pHeader;
1365 pPrevHash->dwAddressNext = dwOffset;
1367 pHeader->dwOffsetFirstHashTable = dwOffset;
1368 (*ppHash)->CacheFileEntry.dwSignature = HASH_SIGNATURE;
1369 (*ppHash)->CacheFileEntry.dwBlocksUsed = 0x20;
1370 (*ppHash)->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0;
1371 for (i = 0; i < HASHTABLE_SIZE; i++)
1373 (*ppHash)->HashTable[i].dwOffsetEntry = 0;
1374 (*ppHash)->HashTable[i].dwHashKey = HASHTABLE_FREE;
1376 return ERROR_SUCCESS;
1379 /***********************************************************************
1380 * URLCache_EnumHashTables (Internal)
1382 * Enumerates the hash tables in a container.
1385 * TRUE if an entry was found
1386 * FALSE if there are no more tables to enumerate.
1389 static BOOL URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader, DWORD *pdwHashTableNumber, HASH_CACHEFILE_ENTRY ** ppHashEntry)
1391 for (*ppHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1392 URLCache_IsHashEntryValid(pHeader, *ppHashEntry);
1393 *ppHashEntry = URLCache_HashEntryFromOffset(pHeader, (*ppHashEntry)->dwAddressNext))
1395 TRACE("looking at hash table number %d\n", (*ppHashEntry)->dwHashTableNumber);
1396 if ((*ppHashEntry)->dwHashTableNumber != *pdwHashTableNumber)
1398 /* make sure that it is in fact a hash entry */
1399 if ((*ppHashEntry)->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1401 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&(*ppHashEntry)->CacheFileEntry.dwSignature);
1402 (*pdwHashTableNumber)++;
1406 TRACE("hash table number %d found\n", *pdwHashTableNumber);
1412 /***********************************************************************
1413 * URLCache_EnumHashTableEntries (Internal)
1415 * Enumerates entries in a hash table and returns the next non-free entry.
1418 * TRUE if an entry was found
1419 * FALSE if the hash table is empty or there are no more entries to
1423 static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY * pHashEntry,
1424 DWORD * index, const struct _HASH_ENTRY ** ppHashEntry)
1426 for (; *index < HASHTABLE_SIZE ; (*index)++)
1428 if (pHashEntry->HashTable[*index].dwHashKey == HASHTABLE_FREE)
1431 *ppHashEntry = &pHashEntry->HashTable[*index];
1432 TRACE("entry found %d\n", *index);
1435 TRACE("no more entries (%d)\n", *index);
1439 /***********************************************************************
1440 * FreeUrlCacheSpaceA (WININET.@)
1443 BOOL WINAPI FreeUrlCacheSpaceA(LPCSTR lpszCachePath, DWORD dwSize, DWORD dwFilter)
1446 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1450 /***********************************************************************
1451 * FreeUrlCacheSpaceW (WININET.@)
1454 BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR lpszCachePath, DWORD dwSize, DWORD dwFilter)
1457 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1461 /***********************************************************************
1462 * GetUrlCacheEntryInfoExA (WININET.@)
1465 BOOL WINAPI GetUrlCacheEntryInfoExA(
1467 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1468 LPDWORD lpdwCacheEntryInfoBufSize,
1470 LPDWORD lpdwReserved,
1474 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1475 debugstr_a(lpszUrl),
1477 lpdwCacheEntryInfoBufSize,
1483 if ((lpszReserved != NULL) ||
1484 (lpdwReserved != NULL) ||
1485 (lpReserved != NULL))
1487 ERR("Reserved value was not 0\n");
1488 SetLastError(ERROR_INVALID_PARAMETER);
1493 FIXME("Undocumented flag(s): %x\n", dwFlags);
1494 SetLastError(ERROR_FILE_NOT_FOUND);
1497 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1500 /***********************************************************************
1501 * GetUrlCacheEntryInfoA (WININET.@)
1504 BOOL WINAPI GetUrlCacheEntryInfoA(
1505 IN LPCSTR lpszUrlName,
1506 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1507 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1510 LPURLCACHE_HEADER pHeader;
1511 struct _HASH_ENTRY * pHashEntry;
1512 const CACHEFILE_ENTRY * pEntry;
1513 const URL_CACHEFILE_ENTRY * pUrlEntry;
1514 URLCACHECONTAINER * pContainer;
1517 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1519 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1520 if (error != ERROR_SUCCESS)
1522 SetLastError(error);
1526 error = URLCacheContainer_OpenIndex(pContainer);
1527 if (error != ERROR_SUCCESS)
1529 SetLastError(error);
1533 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1536 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1538 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1539 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1540 SetLastError(ERROR_FILE_NOT_FOUND);
1544 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1545 if (pEntry->dwSignature != URL_SIGNATURE)
1547 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1548 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD)));
1549 SetLastError(ERROR_FILE_NOT_FOUND);
1553 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1554 TRACE("Found URL: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1555 if (pUrlEntry->dwOffsetHeaderInfo)
1556 TRACE("Header info: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1558 if (lpdwCacheEntryInfoBufferSize)
1560 if (!lpCacheEntryInfo)
1561 *lpdwCacheEntryInfoBufferSize = 0;
1563 error = URLCache_CopyEntry(
1567 lpdwCacheEntryInfoBufferSize,
1570 if (error != ERROR_SUCCESS)
1572 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1573 SetLastError(error);
1576 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1579 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1584 /***********************************************************************
1585 * GetUrlCacheEntryInfoW (WININET.@)
1588 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1589 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1590 LPDWORD lpdwCacheEntryInfoBufferSize)
1592 LPURLCACHE_HEADER pHeader;
1593 struct _HASH_ENTRY * pHashEntry;
1594 const CACHEFILE_ENTRY * pEntry;
1595 const URL_CACHEFILE_ENTRY * pUrlEntry;
1596 URLCACHECONTAINER * pContainer;
1599 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1601 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1602 if (error != ERROR_SUCCESS)
1604 SetLastError(error);
1608 error = URLCacheContainer_OpenIndex(pContainer);
1609 if (error != ERROR_SUCCESS)
1611 SetLastError(error);
1615 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1618 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1620 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1621 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1622 SetLastError(ERROR_FILE_NOT_FOUND);
1626 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1627 if (pEntry->dwSignature != URL_SIGNATURE)
1629 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1630 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD)));
1631 SetLastError(ERROR_FILE_NOT_FOUND);
1635 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1636 TRACE("Found URL: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1637 TRACE("Header info: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1639 if (lpdwCacheEntryInfoBufferSize)
1641 if (!lpCacheEntryInfo)
1642 *lpdwCacheEntryInfoBufferSize = 0;
1644 error = URLCache_CopyEntry(
1647 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1648 lpdwCacheEntryInfoBufferSize,
1650 TRUE /* UNICODE */);
1651 if (error != ERROR_SUCCESS)
1653 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1654 SetLastError(error);
1657 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1660 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1665 /***********************************************************************
1666 * GetUrlCacheEntryInfoExW (WININET.@)
1669 BOOL WINAPI GetUrlCacheEntryInfoExW(
1671 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1672 LPDWORD lpdwCacheEntryInfoBufSize,
1673 LPWSTR lpszReserved,
1674 LPDWORD lpdwReserved,
1678 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1679 debugstr_w(lpszUrl),
1681 lpdwCacheEntryInfoBufSize,
1687 if ((lpszReserved != NULL) ||
1688 (lpdwReserved != NULL) ||
1689 (lpReserved != NULL))
1691 ERR("Reserved value was not 0\n");
1692 SetLastError(ERROR_INVALID_PARAMETER);
1697 FIXME("Undocumented flag(s): %x\n", dwFlags);
1698 SetLastError(ERROR_FILE_NOT_FOUND);
1701 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1704 /***********************************************************************
1705 * SetUrlCacheEntryInfoA (WININET.@)
1707 BOOL WINAPI SetUrlCacheEntryInfoA(
1709 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1710 DWORD dwFieldControl)
1712 LPURLCACHE_HEADER pHeader;
1713 struct _HASH_ENTRY * pHashEntry;
1714 CACHEFILE_ENTRY * pEntry;
1715 URLCACHECONTAINER * pContainer;
1718 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1720 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1721 if (error != ERROR_SUCCESS)
1723 SetLastError(error);
1727 error = URLCacheContainer_OpenIndex(pContainer);
1728 if (error != ERROR_SUCCESS)
1730 SetLastError(error);
1734 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1737 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1739 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1740 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1741 SetLastError(ERROR_FILE_NOT_FOUND);
1745 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1746 if (pEntry->dwSignature != URL_SIGNATURE)
1748 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1749 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1750 SetLastError(ERROR_FILE_NOT_FOUND);
1754 URLCache_SetEntryInfo(
1755 (URL_CACHEFILE_ENTRY *)pEntry,
1756 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1759 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1764 /***********************************************************************
1765 * SetUrlCacheEntryInfoW (WININET.@)
1767 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1769 LPURLCACHE_HEADER pHeader;
1770 struct _HASH_ENTRY * pHashEntry;
1771 CACHEFILE_ENTRY * pEntry;
1772 URLCACHECONTAINER * pContainer;
1775 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1777 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1778 if (error != ERROR_SUCCESS)
1780 SetLastError(error);
1784 error = URLCacheContainer_OpenIndex(pContainer);
1785 if (error != ERROR_SUCCESS)
1787 SetLastError(error);
1791 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1794 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1796 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1797 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1798 SetLastError(ERROR_FILE_NOT_FOUND);
1802 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1803 if (pEntry->dwSignature != URL_SIGNATURE)
1805 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1806 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1807 SetLastError(ERROR_FILE_NOT_FOUND);
1811 URLCache_SetEntryInfo(
1812 (URL_CACHEFILE_ENTRY *)pEntry,
1816 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1821 /***********************************************************************
1822 * RetrieveUrlCacheEntryFileA (WININET.@)
1825 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1826 IN LPCSTR lpszUrlName,
1827 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1828 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1832 LPURLCACHE_HEADER pHeader;
1833 struct _HASH_ENTRY * pHashEntry;
1834 CACHEFILE_ENTRY * pEntry;
1835 URL_CACHEFILE_ENTRY * pUrlEntry;
1836 URLCACHECONTAINER * pContainer;
1839 TRACE("(%s, %p, %p, 0x%08x)\n",
1840 debugstr_a(lpszUrlName),
1842 lpdwCacheEntryInfoBufferSize,
1845 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1846 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1848 SetLastError(ERROR_INVALID_PARAMETER);
1852 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1853 if (error != ERROR_SUCCESS)
1855 SetLastError(error);
1859 error = URLCacheContainer_OpenIndex(pContainer);
1860 if (error != ERROR_SUCCESS)
1862 SetLastError(error);
1866 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1869 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1871 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1872 TRACE("entry %s not found!\n", lpszUrlName);
1873 SetLastError(ERROR_FILE_NOT_FOUND);
1877 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1878 if (pEntry->dwSignature != URL_SIGNATURE)
1880 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1881 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1882 SetLastError(ERROR_FILE_NOT_FOUND);
1886 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1887 if (!pUrlEntry->dwOffsetLocalName)
1889 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1890 SetLastError(ERROR_INVALID_DATA);
1894 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1895 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1897 pUrlEntry->dwHitRate++;
1898 pUrlEntry->dwUseCount++;
1899 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
1900 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1902 error = URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo,
1903 lpdwCacheEntryInfoBufferSize, pUrlEntry,
1905 if (error != ERROR_SUCCESS)
1907 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1908 SetLastError(error);
1911 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1913 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1918 /***********************************************************************
1919 * RetrieveUrlCacheEntryFileW (WININET.@)
1922 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1923 IN LPCWSTR lpszUrlName,
1924 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1925 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1929 LPURLCACHE_HEADER pHeader;
1930 struct _HASH_ENTRY * pHashEntry;
1931 CACHEFILE_ENTRY * pEntry;
1932 URL_CACHEFILE_ENTRY * pUrlEntry;
1933 URLCACHECONTAINER * pContainer;
1936 TRACE("(%s, %p, %p, 0x%08x)\n",
1937 debugstr_w(lpszUrlName),
1939 lpdwCacheEntryInfoBufferSize,
1942 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1943 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1945 SetLastError(ERROR_INVALID_PARAMETER);
1949 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
1950 if (error != ERROR_SUCCESS)
1952 SetLastError(error);
1956 error = URLCacheContainer_OpenIndex(pContainer);
1957 if (error != ERROR_SUCCESS)
1959 SetLastError(error);
1963 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1966 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1968 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1969 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1970 SetLastError(ERROR_FILE_NOT_FOUND);
1974 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1975 if (pEntry->dwSignature != URL_SIGNATURE)
1977 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1978 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1979 SetLastError(ERROR_FILE_NOT_FOUND);
1983 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1984 if (!pUrlEntry->dwOffsetLocalName)
1986 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1987 SetLastError(ERROR_INVALID_DATA);
1991 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1992 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1994 pUrlEntry->dwHitRate++;
1995 pUrlEntry->dwUseCount++;
1996 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
1997 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1999 error = URLCache_CopyEntry(
2002 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
2003 lpdwCacheEntryInfoBufferSize,
2005 TRUE /* UNICODE */);
2006 if (error != ERROR_SUCCESS)
2008 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2009 SetLastError(error);
2012 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
2014 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2019 /***********************************************************************
2020 * UnlockUrlCacheEntryFileA (WININET.@)
2023 BOOL WINAPI UnlockUrlCacheEntryFileA(
2024 IN LPCSTR lpszUrlName,
2028 LPURLCACHE_HEADER pHeader;
2029 struct _HASH_ENTRY * pHashEntry;
2030 CACHEFILE_ENTRY * pEntry;
2031 URL_CACHEFILE_ENTRY * pUrlEntry;
2032 URLCACHECONTAINER * pContainer;
2035 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
2039 ERR("dwReserved != 0\n");
2040 SetLastError(ERROR_INVALID_PARAMETER);
2044 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2045 if (error != ERROR_SUCCESS)
2047 SetLastError(error);
2051 error = URLCacheContainer_OpenIndex(pContainer);
2052 if (error != ERROR_SUCCESS)
2054 SetLastError(error);
2058 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2061 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2063 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2064 TRACE("entry %s not found!\n", lpszUrlName);
2065 SetLastError(ERROR_FILE_NOT_FOUND);
2069 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2070 if (pEntry->dwSignature != URL_SIGNATURE)
2072 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2073 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2074 SetLastError(ERROR_FILE_NOT_FOUND);
2078 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2080 if (pUrlEntry->dwUseCount == 0)
2082 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2085 pUrlEntry->dwUseCount--;
2086 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2088 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2093 /***********************************************************************
2094 * UnlockUrlCacheEntryFileW (WININET.@)
2097 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
2099 LPURLCACHE_HEADER pHeader;
2100 struct _HASH_ENTRY * pHashEntry;
2101 CACHEFILE_ENTRY * pEntry;
2102 URL_CACHEFILE_ENTRY * pUrlEntry;
2103 URLCACHECONTAINER * pContainer;
2106 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
2110 ERR("dwReserved != 0\n");
2111 SetLastError(ERROR_INVALID_PARAMETER);
2115 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2116 if (error != ERROR_SUCCESS)
2118 SetLastError(error);
2122 error = URLCacheContainer_OpenIndex(pContainer);
2123 if (error != ERROR_SUCCESS)
2125 SetLastError(error);
2129 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2132 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
2134 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2135 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
2136 SetLastError(ERROR_FILE_NOT_FOUND);
2140 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2141 if (pEntry->dwSignature != URL_SIGNATURE)
2143 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2144 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2145 SetLastError(ERROR_FILE_NOT_FOUND);
2149 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2151 if (pUrlEntry->dwUseCount == 0)
2153 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2156 pUrlEntry->dwUseCount--;
2157 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2159 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2164 /***********************************************************************
2165 * CreateUrlCacheEntryA (WININET.@)
2168 BOOL WINAPI CreateUrlCacheEntryA(
2169 IN LPCSTR lpszUrlName,
2170 IN DWORD dwExpectedFileSize,
2171 IN LPCSTR lpszFileExtension,
2172 OUT LPSTR lpszFileName,
2177 WCHAR *file_extension = NULL;
2178 WCHAR file_name[MAX_PATH];
2179 BOOL bSuccess = FALSE;
2182 TRACE("(%s %d %s %p %d)\n", debugstr_a(lpszUrlName), dwExpectedFileSize,
2183 debugstr_a(lpszFileExtension), lpszFileName, dwReserved);
2185 if (lpszUrlName && (url_name = heap_strdupAtoW(lpszUrlName)))
2187 if (!lpszFileExtension || (file_extension = heap_strdupAtoW(lpszFileExtension)))
2189 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
2191 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
2197 dwError = GetLastError();
2202 dwError = GetLastError();
2204 HeapFree(GetProcessHeap(), 0, file_extension);
2208 dwError = GetLastError();
2210 HeapFree(GetProcessHeap(), 0, url_name);
2212 SetLastError(dwError);
2216 /***********************************************************************
2217 * CreateUrlCacheEntryW (WININET.@)
2220 BOOL WINAPI CreateUrlCacheEntryW(
2221 IN LPCWSTR lpszUrlName,
2222 IN DWORD dwExpectedFileSize,
2223 IN LPCWSTR lpszFileExtension,
2224 OUT LPWSTR lpszFileName,
2228 URLCACHECONTAINER * pContainer;
2229 LPURLCACHE_HEADER pHeader;
2230 CHAR szFile[MAX_PATH];
2231 WCHAR szExtension[MAX_PATH];
2232 LPCWSTR lpszUrlPart;
2234 LPCWSTR lpszFileNameExtension;
2235 LPWSTR lpszFileNameNoPath;
2237 int countnoextension;
2240 BOOL bFound = FALSE;
2246 static const WCHAR szWWW[] = {'w','w','w',0};
2247 static const WCHAR fmt[] = {'%','0','8','X','%','s',0};
2249 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2250 debugstr_w(lpszUrlName),
2252 debugstr_w(lpszFileExtension),
2257 FIXME("dwReserved 0x%08x\n", dwReserved);
2259 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2261 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2264 lpszUrlPart = memchrW(lpszUrlName, '?', lpszUrlEnd - lpszUrlName);
2266 lpszUrlPart = memchrW(lpszUrlName, '#', lpszUrlEnd - lpszUrlName);
2268 lpszUrlEnd = lpszUrlPart;
2270 for (lpszUrlPart = lpszUrlEnd;
2271 (lpszUrlPart >= lpszUrlName);
2274 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2281 if (!lstrcmpW(lpszUrlPart, szWWW))
2283 lpszUrlPart += lstrlenW(szWWW);
2286 count = lpszUrlEnd - lpszUrlPart;
2288 if (bFound && (count < MAX_PATH))
2290 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2294 while(len && szFile[--len] == '/') szFile[len] = '\0';
2296 /* FIXME: get rid of illegal characters like \, / and : */
2300 FIXME("need to generate a random filename\n");
2303 TRACE("File name: %s\n", debugstr_a(szFile));
2305 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2306 if (error != ERROR_SUCCESS)
2308 SetLastError(error);
2312 error = URLCacheContainer_OpenIndex(pContainer);
2313 if (error != ERROR_SUCCESS)
2315 SetLastError(error);
2319 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2322 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2324 lBufferSize = MAX_PATH * sizeof(WCHAR);
2325 if (!URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize))
2327 WARN("Failed to get full path for filename %s, needed %u bytes.\n",
2328 debugstr_a(szFile), lBufferSize);
2329 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2333 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2335 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2336 lpszFileNameNoPath >= lpszFileName;
2337 --lpszFileNameNoPath)
2339 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2343 countnoextension = lstrlenW(lpszFileNameNoPath);
2344 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2345 if (lpszFileNameExtension)
2346 countnoextension -= lstrlenW(lpszFileNameExtension);
2347 *szExtension = '\0';
2349 if (lpszFileExtension)
2351 szExtension[0] = '.';
2352 lstrcpyW(szExtension+1, lpszFileExtension);
2355 for (i = 0; i < 255; i++)
2357 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2360 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2361 for (p = lpszFileNameNoPath + 1; *p; p++)
2367 case '/': case '\\':
2374 if (p[-1] == ' ' || p[-1] == '.') p[-1] = '_';
2376 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2377 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2378 if (hFile != INVALID_HANDLE_VALUE)
2385 GetSystemTimeAsFileTime(&ft);
2386 wsprintfW(lpszFileNameNoPath + countnoextension, fmt, ft.dwLowDateTime, szExtension);
2388 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2389 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2390 if (hFile != INVALID_HANDLE_VALUE)
2396 WARN("Could not find a unique filename\n");
2401 /***********************************************************************
2402 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2404 * The bug we are compensating for is that some drongo at Microsoft
2405 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2406 * As a consequence, CommitUrlCacheEntryA has been effectively
2407 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2408 * is still defined as LPCWSTR. The result (other than madness) is
2409 * that we always need to store lpHeaderInfo in CP_ACP rather than
2410 * in UTF16, and we need to avoid converting lpHeaderInfo in
2411 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2412 * result will lose data for arbitrary binary data.
2415 static BOOL CommitUrlCacheEntryInternal(
2416 IN LPCWSTR lpszUrlName,
2417 IN LPCWSTR lpszLocalFileName,
2418 IN FILETIME ExpireTime,
2419 IN FILETIME LastModifiedTime,
2420 IN DWORD CacheEntryType,
2421 IN LPBYTE lpHeaderInfo,
2422 IN DWORD dwHeaderSize,
2423 IN LPCWSTR lpszFileExtension,
2424 IN LPCWSTR lpszOriginalUrl
2427 URLCACHECONTAINER * pContainer;
2428 LPURLCACHE_HEADER pHeader;
2429 struct _HASH_ENTRY * pHashEntry;
2430 CACHEFILE_ENTRY * pEntry;
2431 URL_CACHEFILE_ENTRY * pUrlEntry;
2432 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2433 DWORD dwOffsetLocalFileName = 0;
2434 DWORD dwOffsetHeader = 0;
2435 DWORD dwOffsetFileExtension = 0;
2436 LARGE_INTEGER file_size;
2437 BYTE cDirectory = 0;
2438 char achFile[MAX_PATH];
2439 LPSTR lpszUrlNameA = NULL;
2440 LPSTR lpszFileExtensionA = NULL;
2441 char *pchLocalFileName = 0;
2444 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2445 debugstr_w(lpszUrlName),
2446 debugstr_w(lpszLocalFileName),
2450 debugstr_w(lpszFileExtension),
2451 debugstr_w(lpszOriginalUrl));
2453 if (lpszOriginalUrl)
2454 WARN(": lpszOriginalUrl ignored\n");
2456 file_size.QuadPart = 0;
2457 if (lpszLocalFileName)
2461 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2462 if (hFile == INVALID_HANDLE_VALUE)
2464 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2469 if (!GetFileSizeEx(hFile, &file_size))
2471 ERR("couldn't get file size (error is %d)\n", GetLastError());
2479 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2480 if (error != ERROR_SUCCESS)
2482 SetLastError(error);
2486 error = URLCacheContainer_OpenIndex(pContainer);
2487 if (error != ERROR_SUCCESS)
2489 SetLastError(error);
2493 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2496 lpszUrlNameA = heap_strdupWtoA(lpszUrlName);
2499 error = GetLastError();
2503 if (lpszFileExtension && !(lpszFileExtensionA = heap_strdupWtoA(lpszFileExtension)))
2505 error = GetLastError();
2509 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2511 FIXME("entry already in cache - don't know what to do!\n");
2513 * SetLastError(ERROR_FILE_NOT_FOUND);
2519 if (lpszLocalFileName)
2521 BOOL bFound = FALSE;
2523 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2525 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2526 error = ERROR_INVALID_PARAMETER;
2530 /* skip container path prefix */
2531 lpszLocalFileName += lstrlenW(pContainer->path);
2533 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL);
2534 pchLocalFileName = achFile;
2536 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2538 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2547 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2548 error = ERROR_INVALID_PARAMETER;
2552 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2555 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2556 if (lpszLocalFileName)
2558 dwOffsetLocalFileName = dwBytesNeeded;
2559 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2563 dwOffsetHeader = dwBytesNeeded;
2564 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2566 if (lpszFileExtensionA)
2568 dwOffsetFileExtension = dwBytesNeeded;
2569 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2572 /* round up to next block */
2573 if (dwBytesNeeded % BLOCKSIZE)
2575 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2576 dwBytesNeeded += BLOCKSIZE;
2579 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2581 ERR("no free entries\n");
2582 error = ERROR_DISK_FULL;
2586 /* FindFirstFreeEntry fills in blocks used */
2587 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2588 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2589 pUrlEntry->CacheDir = cDirectory;
2590 pUrlEntry->CacheEntryType = CacheEntryType;
2591 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2592 pUrlEntry->dwExemptDelta = 0;
2593 pUrlEntry->dwHitRate = 0;
2594 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2595 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2596 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2597 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2598 pUrlEntry->size.QuadPart = file_size.QuadPart;
2599 pUrlEntry->dwUseCount = 0;
2600 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2601 pUrlEntry->LastModifiedTime = LastModifiedTime;
2602 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2603 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2604 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2605 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2608 pUrlEntry->dwUnknown1 = 0;
2609 pUrlEntry->dwUnknown2 = 0;
2610 pUrlEntry->dwUnknown3 = 0x60;
2611 pUrlEntry->Unknown4 = 0;
2612 pUrlEntry->wUnknown5 = 0x1010;
2613 pUrlEntry->dwUnknown7 = 0;
2614 pUrlEntry->dwUnknown8 = 0;
2617 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2618 if (dwOffsetLocalFileName)
2619 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2621 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2622 if (dwOffsetFileExtension)
2623 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2625 error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA,
2626 (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader));
2627 if (error != ERROR_SUCCESS)
2628 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2631 if (pUrlEntry->CacheDir < pHeader->DirectoryCount)
2632 pHeader->directory_data[pUrlEntry->CacheDir].dwNumFiles++;
2633 pHeader->CacheUsage.QuadPart += file_size.QuadPart;
2634 if (pHeader->CacheUsage.QuadPart > pHeader->CacheLimit.QuadPart)
2635 FIXME("file of size %s bytes fills cache\n", wine_dbgstr_longlong(file_size.QuadPart));
2639 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2640 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2641 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2643 if (error == ERROR_SUCCESS)
2647 SetLastError(error);
2652 /***********************************************************************
2653 * CommitUrlCacheEntryA (WININET.@)
2656 BOOL WINAPI CommitUrlCacheEntryA(
2657 IN LPCSTR lpszUrlName,
2658 IN LPCSTR lpszLocalFileName,
2659 IN FILETIME ExpireTime,
2660 IN FILETIME LastModifiedTime,
2661 IN DWORD CacheEntryType,
2662 IN LPBYTE lpHeaderInfo,
2663 IN DWORD dwHeaderSize,
2664 IN LPCSTR lpszFileExtension,
2665 IN LPCSTR lpszOriginalUrl
2668 WCHAR *url_name = NULL;
2669 WCHAR *local_file_name = NULL;
2670 WCHAR *original_url = NULL;
2671 WCHAR *file_extension = NULL;
2672 BOOL bSuccess = FALSE;
2674 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2675 debugstr_a(lpszUrlName),
2676 debugstr_a(lpszLocalFileName),
2680 debugstr_a(lpszFileExtension),
2681 debugstr_a(lpszOriginalUrl));
2683 url_name = heap_strdupAtoW(lpszUrlName);
2687 if (lpszLocalFileName)
2689 local_file_name = heap_strdupAtoW(lpszLocalFileName);
2690 if (!local_file_name)
2693 if (lpszFileExtension)
2695 file_extension = heap_strdupAtoW(lpszFileExtension);
2696 if (!file_extension)
2699 if (lpszOriginalUrl)
2701 original_url = heap_strdupAtoW(lpszOriginalUrl);
2706 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2707 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2708 file_extension, original_url);
2711 HeapFree(GetProcessHeap(), 0, original_url);
2712 HeapFree(GetProcessHeap(), 0, file_extension);
2713 HeapFree(GetProcessHeap(), 0, local_file_name);
2714 HeapFree(GetProcessHeap(), 0, url_name);
2719 /***********************************************************************
2720 * CommitUrlCacheEntryW (WININET.@)
2723 BOOL WINAPI CommitUrlCacheEntryW(
2724 IN LPCWSTR lpszUrlName,
2725 IN LPCWSTR lpszLocalFileName,
2726 IN FILETIME ExpireTime,
2727 IN FILETIME LastModifiedTime,
2728 IN DWORD CacheEntryType,
2729 IN LPWSTR lpHeaderInfo,
2730 IN DWORD dwHeaderSize,
2731 IN LPCWSTR lpszFileExtension,
2732 IN LPCWSTR lpszOriginalUrl
2736 BOOL bSuccess = FALSE;
2738 CHAR *header_info = NULL;
2740 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2741 debugstr_w(lpszUrlName),
2742 debugstr_w(lpszLocalFileName),
2746 debugstr_w(lpszFileExtension),
2747 debugstr_w(lpszOriginalUrl));
2749 if (!lpHeaderInfo || (header_info = heap_strdupWtoA(lpHeaderInfo)))
2751 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2752 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2758 dwError = GetLastError();
2762 HeapFree(GetProcessHeap(), 0, header_info);
2764 SetLastError(dwError);
2770 /***********************************************************************
2771 * ReadUrlCacheEntryStream (WININET.@)
2774 BOOL WINAPI ReadUrlCacheEntryStream(
2775 IN HANDLE hUrlCacheStream,
2776 IN DWORD dwLocation,
2777 IN OUT LPVOID lpBuffer,
2778 IN OUT LPDWORD lpdwLen,
2782 /* Get handle to file from 'stream' */
2783 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2785 if (dwReserved != 0)
2787 ERR("dwReserved != 0\n");
2788 SetLastError(ERROR_INVALID_PARAMETER);
2792 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2794 SetLastError(ERROR_INVALID_HANDLE);
2798 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2800 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2803 /***********************************************************************
2804 * RetrieveUrlCacheEntryStreamA (WININET.@)
2807 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2808 IN LPCSTR lpszUrlName,
2809 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2810 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2811 IN BOOL fRandomRead,
2815 /* NOTE: this is not the same as the way that the native
2816 * version allocates 'stream' handles. I did it this way
2817 * as it is much easier and no applications should depend
2818 * on this behaviour. (Native version appears to allocate
2819 * indices into a table)
2821 STREAM_HANDLE * pStream;
2824 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2825 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2827 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2829 lpdwCacheEntryInfoBufferSize,
2835 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2840 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2842 if (hFile == INVALID_HANDLE_VALUE)
2845 /* allocate handle storage space */
2846 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2850 SetLastError(ERROR_OUTOFMEMORY);
2854 pStream->hFile = hFile;
2855 strcpy(pStream->lpszUrl, lpszUrlName);
2859 /***********************************************************************
2860 * RetrieveUrlCacheEntryStreamW (WININET.@)
2863 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2864 IN LPCWSTR lpszUrlName,
2865 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2866 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2867 IN BOOL fRandomRead,
2871 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2872 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2876 /***********************************************************************
2877 * UnlockUrlCacheEntryStream (WININET.@)
2880 BOOL WINAPI UnlockUrlCacheEntryStream(
2881 IN HANDLE hUrlCacheStream,
2885 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2887 if (dwReserved != 0)
2889 ERR("dwReserved != 0\n");
2890 SetLastError(ERROR_INVALID_PARAMETER);
2894 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2896 SetLastError(ERROR_INVALID_HANDLE);
2900 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2903 /* close file handle */
2904 CloseHandle(pStream->hFile);
2906 /* free allocated space */
2907 HeapFree(GetProcessHeap(), 0, pStream);
2913 /***********************************************************************
2914 * DeleteUrlCacheEntryA (WININET.@)
2917 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2919 URLCACHECONTAINER * pContainer;
2920 LPURLCACHE_HEADER pHeader;
2921 struct _HASH_ENTRY * pHashEntry;
2922 CACHEFILE_ENTRY * pEntry;
2923 const URL_CACHEFILE_ENTRY * pUrlEntry;
2926 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2928 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2929 if (error != ERROR_SUCCESS)
2931 SetLastError(error);
2935 error = URLCacheContainer_OpenIndex(pContainer);
2936 if (error != ERROR_SUCCESS)
2938 SetLastError(error);
2942 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2945 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2947 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2948 TRACE("entry %s not found!\n", lpszUrlName);
2949 SetLastError(ERROR_FILE_NOT_FOUND);
2953 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2954 if (pEntry->dwSignature != URL_SIGNATURE)
2956 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2957 FIXME("Trying to delete entry of unknown format %s\n",
2958 debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD)));
2959 SetLastError(ERROR_FILE_NOT_FOUND);
2962 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
2963 if (pUrlEntry->CacheDir < pHeader->DirectoryCount)
2965 if (pHeader->directory_data[pUrlEntry->CacheDir].dwNumFiles)
2966 pHeader->directory_data[pUrlEntry->CacheDir].dwNumFiles--;
2968 if (pUrlEntry->size.QuadPart < pHeader->CacheUsage.QuadPart)
2969 pHeader->CacheUsage.QuadPart -= pUrlEntry->size.QuadPart;
2971 pHeader->CacheUsage.QuadPart = 0;
2973 URLCache_DeleteEntry(pHeader, pEntry);
2975 URLCache_DeleteEntryFromHash(pHashEntry);
2977 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2982 /***********************************************************************
2983 * DeleteUrlCacheEntryW (WININET.@)
2986 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2988 URLCACHECONTAINER * pContainer;
2989 LPURLCACHE_HEADER pHeader;
2990 struct _HASH_ENTRY * pHashEntry;
2991 CACHEFILE_ENTRY * pEntry;
2992 const URL_CACHEFILE_ENTRY * pUrlEntry;
2996 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2998 urlA = heap_strdupWtoA(lpszUrlName);
3001 SetLastError(ERROR_OUTOFMEMORY);
3005 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
3006 if (error != ERROR_SUCCESS)
3008 HeapFree(GetProcessHeap(), 0, urlA);
3009 SetLastError(error);
3013 error = URLCacheContainer_OpenIndex(pContainer);
3014 if (error != ERROR_SUCCESS)
3016 HeapFree(GetProcessHeap(), 0, urlA);
3017 SetLastError(error);
3021 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3023 HeapFree(GetProcessHeap(), 0, urlA);
3027 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
3029 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3030 TRACE("entry %s not found!\n", debugstr_a(urlA));
3031 HeapFree(GetProcessHeap(), 0, urlA);
3032 SetLastError(ERROR_FILE_NOT_FOUND);
3036 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3037 if (pEntry->dwSignature != URL_SIGNATURE)
3039 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3040 FIXME("Trying to delete entry of unknown format %s\n",
3041 debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD)));
3042 SetLastError(ERROR_FILE_NOT_FOUND);
3045 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3046 if (pUrlEntry->CacheDir < pHeader->DirectoryCount)
3048 if (pHeader->directory_data[pUrlEntry->CacheDir].dwNumFiles)
3049 pHeader->directory_data[pUrlEntry->CacheDir].dwNumFiles--;
3051 if (pUrlEntry->size.QuadPart < pHeader->CacheUsage.QuadPart)
3052 pHeader->CacheUsage.QuadPart -= pUrlEntry->size.QuadPart;
3054 pHeader->CacheUsage.QuadPart = 0;
3056 URLCache_DeleteEntry(pHeader, pEntry);
3058 URLCache_DeleteEntryFromHash(pHashEntry);
3060 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3062 HeapFree(GetProcessHeap(), 0, urlA);
3066 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
3068 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3072 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
3074 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3078 /***********************************************************************
3079 * CreateCacheContainerA (WININET.@)
3081 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3082 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3084 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3085 d1, d2, d3, d4, d5, d6, d7, d8);
3089 /***********************************************************************
3090 * CreateCacheContainerW (WININET.@)
3092 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3093 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3095 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3096 d1, d2, d3, d4, d5, d6, d7, d8);
3100 /***********************************************************************
3101 * FindFirstUrlCacheContainerA (WININET.@)
3103 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3105 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3109 /***********************************************************************
3110 * FindFirstUrlCacheContainerW (WININET.@)
3112 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3114 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3118 /***********************************************************************
3119 * FindNextUrlCacheContainerA (WININET.@)
3121 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
3123 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3127 /***********************************************************************
3128 * FindNextUrlCacheContainerW (WININET.@)
3130 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
3132 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3136 HANDLE WINAPI FindFirstUrlCacheEntryExA(
3137 LPCSTR lpszUrlSearchPattern,
3141 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3142 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3144 LPDWORD pcbReserved2,
3148 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
3149 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3150 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3151 SetLastError(ERROR_FILE_NOT_FOUND);
3155 HANDLE WINAPI FindFirstUrlCacheEntryExW(
3156 LPCWSTR lpszUrlSearchPattern,
3160 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3161 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3163 LPDWORD pcbReserved2,
3167 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
3168 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3169 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3170 SetLastError(ERROR_FILE_NOT_FOUND);
3174 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3176 typedef struct URLCacheFindEntryHandle
3179 LPWSTR lpszUrlSearchPattern;
3180 DWORD dwContainerIndex;
3181 DWORD dwHashTableIndex;
3182 DWORD dwHashEntryIndex;
3183 } URLCacheFindEntryHandle;
3185 /***********************************************************************
3186 * FindFirstUrlCacheEntryA (WININET.@)
3189 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
3190 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3192 URLCacheFindEntryHandle *pEntryHandle;
3194 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3196 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3200 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3201 if (lpszUrlSearchPattern)
3203 pEntryHandle->lpszUrlSearchPattern = heap_strdupAtoW(lpszUrlSearchPattern);
3204 if (!pEntryHandle->lpszUrlSearchPattern)
3206 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3211 pEntryHandle->lpszUrlSearchPattern = NULL;
3212 pEntryHandle->dwContainerIndex = 0;
3213 pEntryHandle->dwHashTableIndex = 0;
3214 pEntryHandle->dwHashEntryIndex = 0;
3216 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3218 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3221 return pEntryHandle;
3224 /***********************************************************************
3225 * FindFirstUrlCacheEntryW (WININET.@)
3228 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3229 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3231 URLCacheFindEntryHandle *pEntryHandle;
3233 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3235 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3239 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3240 if (lpszUrlSearchPattern)
3242 pEntryHandle->lpszUrlSearchPattern = heap_strdupW(lpszUrlSearchPattern);
3243 if (!pEntryHandle->lpszUrlSearchPattern)
3245 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3250 pEntryHandle->lpszUrlSearchPattern = NULL;
3251 pEntryHandle->dwContainerIndex = 0;
3252 pEntryHandle->dwHashTableIndex = 0;
3253 pEntryHandle->dwHashEntryIndex = 0;
3255 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3257 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3260 return pEntryHandle;
3263 /***********************************************************************
3264 * FindNextUrlCacheEntryA (WININET.@)
3266 BOOL WINAPI FindNextUrlCacheEntryA(
3268 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3269 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3271 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3272 URLCACHECONTAINER * pContainer;
3274 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3276 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3278 SetLastError(ERROR_INVALID_HANDLE);
3282 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3283 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3285 LPURLCACHE_HEADER pHeader;
3286 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3289 error = URLCacheContainer_OpenIndex(pContainer);
3290 if (error != ERROR_SUCCESS)
3292 SetLastError(error);
3296 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3299 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3300 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3302 const struct _HASH_ENTRY *pHashEntry = NULL;
3303 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3304 pEntryHandle->dwHashEntryIndex++)
3306 const URL_CACHEFILE_ENTRY *pUrlEntry;
3307 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3309 if (pEntry->dwSignature != URL_SIGNATURE)
3312 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3313 TRACE("Found URL: %s\n", (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3314 TRACE("Header info: %s\n", (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3316 error = URLCache_CopyEntry(
3319 lpNextCacheEntryInfo,
3320 lpdwNextCacheEntryInfoBufferSize,
3322 FALSE /* not UNICODE */);
3323 if (error != ERROR_SUCCESS)
3325 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3326 SetLastError(error);
3329 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
3331 /* increment the current index so that next time the function
3332 * is called the next entry is returned */
3333 pEntryHandle->dwHashEntryIndex++;
3334 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3339 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3342 SetLastError(ERROR_NO_MORE_ITEMS);
3346 /***********************************************************************
3347 * FindNextUrlCacheEntryW (WININET.@)
3349 BOOL WINAPI FindNextUrlCacheEntryW(
3351 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3352 LPDWORD lpdwNextCacheEntryInfoBufferSize
3355 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3356 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3360 /***********************************************************************
3361 * FindCloseUrlCache (WININET.@)
3363 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3365 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3367 TRACE("(%p)\n", hEnumHandle);
3369 if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3371 SetLastError(ERROR_INVALID_HANDLE);
3375 pEntryHandle->dwMagic = 0;
3376 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3377 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3382 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3383 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3385 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3386 dwSearchCondition, lpGroupId, lpReserved);
3390 BOOL WINAPI FindNextUrlCacheEntryExA(
3392 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3393 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3395 LPDWORD pcbReserved2,
3399 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3400 lpReserved, pcbReserved2, lpReserved3);
3404 BOOL WINAPI FindNextUrlCacheEntryExW(
3406 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3407 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3409 LPDWORD pcbReserved2,
3413 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3414 lpReserved, pcbReserved2, lpReserved3);
3418 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3420 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3424 /***********************************************************************
3425 * CreateUrlCacheGroup (WININET.@)
3428 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3430 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3434 /***********************************************************************
3435 * DeleteUrlCacheGroup (WININET.@)
3438 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3440 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3441 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3445 /***********************************************************************
3446 * SetUrlCacheEntryGroupA (WININET.@)
3449 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3450 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3453 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3454 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3455 pbGroupAttributes, cbGroupAttributes, lpReserved);
3456 SetLastError(ERROR_FILE_NOT_FOUND);
3460 /***********************************************************************
3461 * SetUrlCacheEntryGroupW (WININET.@)
3464 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3465 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3468 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3469 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3470 pbGroupAttributes, cbGroupAttributes, lpReserved);
3471 SetLastError(ERROR_FILE_NOT_FOUND);
3475 /***********************************************************************
3476 * GetUrlCacheConfigInfoW (WININET.@)
3478 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3480 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3481 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3485 /***********************************************************************
3486 * GetUrlCacheConfigInfoA (WININET.@)
3488 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3490 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3491 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3495 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3496 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3497 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3499 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3500 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3501 lpdwGroupInfo, lpReserved);
3505 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3506 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3507 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3509 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3510 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3511 lpdwGroupInfo, lpReserved);
3515 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3516 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3518 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3519 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3523 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3524 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3526 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3527 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3531 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3533 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3537 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3539 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3543 /***********************************************************************
3544 * DeleteIE3Cache (WININET.@)
3546 * Deletes the files used by the IE3 URL caching system.
3549 * hWnd [I] A dummy window.
3550 * hInst [I] Instance of process calling the function.
3551 * lpszCmdLine [I] Options used by function.
3552 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3554 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3556 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3560 /***********************************************************************
3561 * IsUrlCacheEntryExpiredA (WININET.@)
3565 * dwFlags [I] Unknown
3566 * pftLastModified [O] Last modified time
3568 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3570 LPURLCACHE_HEADER pHeader;
3571 struct _HASH_ENTRY * pHashEntry;
3572 const CACHEFILE_ENTRY * pEntry;
3573 const URL_CACHEFILE_ENTRY * pUrlEntry;
3574 URLCACHECONTAINER * pContainer;
3577 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3579 error = URLCacheContainers_FindContainerA(url, &pContainer);
3580 if (error != ERROR_SUCCESS)
3582 SetLastError(error);
3586 error = URLCacheContainer_OpenIndex(pContainer);
3587 if (error != ERROR_SUCCESS)
3589 SetLastError(error);
3593 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3596 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3598 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3599 TRACE("entry %s not found!\n", url);
3600 SetLastError(ERROR_FILE_NOT_FOUND);
3604 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3605 if (pEntry->dwSignature != URL_SIGNATURE)
3607 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3608 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD)));
3609 SetLastError(ERROR_FILE_NOT_FOUND);
3613 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3615 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3617 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3622 /***********************************************************************
3623 * IsUrlCacheEntryExpiredW (WININET.@)
3627 * dwFlags [I] Unknown
3628 * pftLastModified [O] Last modified time
3630 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3632 LPURLCACHE_HEADER pHeader;
3633 struct _HASH_ENTRY * pHashEntry;
3634 const CACHEFILE_ENTRY * pEntry;
3635 const URL_CACHEFILE_ENTRY * pUrlEntry;
3636 URLCACHECONTAINER * pContainer;
3639 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3641 error = URLCacheContainers_FindContainerW(url, &pContainer);
3642 if (error != ERROR_SUCCESS)
3644 SetLastError(error);
3648 error = URLCacheContainer_OpenIndex(pContainer);
3649 if (error != ERROR_SUCCESS)
3651 SetLastError(error);
3655 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3658 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3660 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3661 TRACE("entry %s not found!\n", debugstr_w(url));
3662 SetLastError(ERROR_FILE_NOT_FOUND);
3666 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3667 if (pEntry->dwSignature != URL_SIGNATURE)
3669 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3670 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD)));
3671 SetLastError(ERROR_FILE_NOT_FOUND);
3675 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3677 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3679 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3684 /***********************************************************************
3685 * GetDiskInfoA (WININET.@)
3687 BOOL WINAPI GetDiskInfoA(PCSTR path, PDWORD cluster_size, PDWORDLONG free, PDWORDLONG total)
3690 ULARGE_INTEGER bytes_free, bytes_total;
3692 TRACE("(%s, %p, %p, %p)\n", debugstr_a(path), cluster_size, free, total);
3696 SetLastError(ERROR_INVALID_PARAMETER);
3700 if ((ret = GetDiskFreeSpaceExA(path, NULL, &bytes_total, &bytes_free)))
3702 if (cluster_size) *cluster_size = 1;
3703 if (free) *free = bytes_free.QuadPart;
3704 if (total) *total = bytes_total.QuadPart;
3709 /***********************************************************************
3710 * RegisterUrlCacheNotification (WININET.@)
3712 DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
3714 FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f);
3718 /***********************************************************************
3719 * IncrementUrlCacheHeaderData (WININET.@)
3721 BOOL WINAPI IncrementUrlCacheHeaderData(DWORD index, LPDWORD data)
3723 FIXME("(%u, %p)\n", index, data);