2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003 Robert Shearman
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #define COM_NO_WINDOWS_H
27 #include "wine/port.h"
46 #include "wine/unicode.h"
47 #include "wine/list.h"
48 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
52 #define ENTRY_START_OFFSET 0x4000
55 #define HASHTABLE_SIZE 448
56 #define HASHTABLE_BLOCKSIZE 7
57 #define HASHTABLE_FREE 3
58 #define ALLOCATION_TABLE_OFFSET 0x250
59 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
60 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
62 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
63 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
64 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
65 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
66 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
68 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
70 typedef struct _CACHEFILE_ENTRY
74 DWORD dwSignature; /* e.g. "URL " */
75 /* CHAR szSignature[4];
77 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
80 typedef struct _URL_CACHEFILE_ENTRY
82 CACHEFILE_ENTRY CacheFileEntry;
83 FILETIME LastModifiedTime;
84 FILETIME LastAccessTime;
85 WORD wExpiredDate; /* expire date in dos format */
86 WORD wExpiredTime; /* expire time in dos format */
87 DWORD dwUnknown1; /* usually zero */
88 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
89 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
90 DWORD dwUnknown2; /* usually zero */
91 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
92 DWORD dwUnknown3; /* usually 0x60 */
93 DWORD dwOffsetUrl; /* usually 0x68 */
94 BYTE CacheDir; /* index of cache directory this url is stored in */
95 BYTE Unknown4; /* usually zero */
96 WORD wUnknown5; /* usually 0x1010 */
97 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
98 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
99 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
100 DWORD dwHeaderInfoSize;
101 DWORD dwUnknown6; /* usually zero */
102 WORD wLastSyncDate; /* last sync date in dos format */
103 WORD wLastSyncTime; /* last sync time in dos format */
104 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
105 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
106 WORD wUnknownDate; /* usually same as wLastSyncDate */
107 WORD wUnknownTime; /* usually same as wLastSyncTime */
108 DWORD dwUnknown7; /* usually zero */
109 DWORD dwUnknown8; /* usually zero */
110 CHAR szSourceUrlName[1]; /* start of url */
111 /* packing to dword align start of next field */
112 /* CHAR szLocalFileName[]; (local file name exluding path) */
113 /* packing to dword align start of next field */
114 /* CHAR szHeaderInfo[]; (header info) */
115 } URL_CACHEFILE_ENTRY;
123 typedef struct _HASH_CACHEFILE_ENTRY
125 CACHEFILE_ENTRY CacheFileEntry;
127 DWORD dwHashTableNumber;
128 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
129 } HASH_CACHEFILE_ENTRY;
131 typedef struct _DIRECTORY_DATA
134 char filename[DIR_LENGTH];
137 typedef struct _URLCACHE_HEADER
139 char szSignature[28];
141 DWORD dwOffsetFirstHashTable;
142 DWORD dwIndexCapacityInBlocks;
143 DWORD dwBlocksInUse; /* is this right? */
145 DWORD dwCacheLimitLow; /* disk space limit for cache */
146 DWORD dwCacheLimitHigh; /* disk space limit for cache */
147 DWORD dwUnknown4; /* current disk space usage for cache? */
148 DWORD dwUnknown5; /* current disk space usage for cache? */
149 DWORD dwUnknown6; /* possibly a flag? */
151 BYTE DirectoryCount; /* number of directory_data's */
152 BYTE Unknown8[3]; /* just padding? */
153 DIRECTORY_DATA directory_data[1]; /* first directory entry */
154 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
155 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
157 typedef struct _STREAM_HANDLE
163 typedef struct _URLCACHECONTAINER
165 struct list entry; /* part of a list */
166 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
167 LPWSTR path; /* path to url container directory */
168 HANDLE hMapping; /* handle of file mapping */
169 DWORD file_size; /* size of file when mapping was opened */
170 HANDLE hMutex; /* hande of mutex */
174 /* List of all containers available */
175 static struct list UrlContainers = LIST_INIT(UrlContainers);
178 /***********************************************************************
179 * URLCache_PathToObjectName (Internal)
181 * Converts a path to a name suitable for use as a Win32 object name.
182 * Replaces '\\' characters in-place with the specified character
183 * (usually '_' or '!')
189 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
191 for (; *lpszPath; lpszPath++)
193 if (*lpszPath == '\\')
198 /***********************************************************************
199 * URLCacheContainer_OpenIndex (Internal)
201 * Opens the index file and saves mapping handle in hCacheIndexMapping
208 static BOOL URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
211 WCHAR wszFilePath[MAX_PATH];
214 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
215 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
217 if (pContainer->hMapping)
220 strcpyW(wszFilePath, pContainer->path);
221 strcatW(wszFilePath, wszIndex);
223 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
224 if (hFile == INVALID_HANDLE_VALUE)
226 FIXME("need to create cache index file\n");
230 dwFileSize = GetFileSize(hFile, NULL);
231 if (dwFileSize == INVALID_FILE_SIZE)
236 FIXME("need to create cache index file\n");
240 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
241 URLCache_PathToObjectName(wszFilePath, '_');
242 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
243 if (!pContainer->hMapping)
244 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
246 if (!pContainer->hMapping)
248 ERR("Couldn't create file mapping (error is %ld)\n", GetLastError());
255 /***********************************************************************
256 * URLCacheContainer_CloseIndex (Internal)
264 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
266 CloseHandle(pContainer->hMapping);
267 pContainer->hMapping = NULL;
270 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
272 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
273 int path_len = strlenW(path);
274 int cache_prefix_len = strlenW(cache_prefix);
281 pContainer->hMapping = NULL;
282 pContainer->file_size = 0;
284 pContainer->path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR));
285 if (!pContainer->path)
287 HeapFree(GetProcessHeap(), 0, pContainer);
291 memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR));
293 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
294 if (!pContainer->cache_prefix)
296 HeapFree(GetProcessHeap(), 0, pContainer->path);
297 HeapFree(GetProcessHeap(), 0, pContainer);
301 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
303 CharLowerW(mutex_name);
304 URLCache_PathToObjectName(mutex_name, '!');
306 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
308 ERR("couldn't create mutex (error is %ld)\n", GetLastError());
309 HeapFree(GetProcessHeap(), 0, pContainer->path);
310 HeapFree(GetProcessHeap(), 0, pContainer);
314 list_add_head(&UrlContainers, &pContainer->entry);
319 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
321 list_remove(&pContainer->entry);
323 URLCacheContainer_CloseIndex(pContainer);
324 CloseHandle(pContainer->hMutex);
325 HeapFree(GetProcessHeap(), 0, pContainer->path);
326 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
327 HeapFree(GetProcessHeap(), 0, pContainer);
330 void URLCacheContainers_CreateDefaults()
332 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
333 static const WCHAR UrlPrefix[] = {0};
334 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
335 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
336 static const WCHAR CookieSuffix[] = {0};
337 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
340 int nFolder; /* CSIDL_* constant */
341 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
342 const WCHAR * cache_prefix; /* prefix used to reference the container */
343 } DefaultContainerData[] =
345 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
346 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
347 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
351 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
353 WCHAR wszCachePath[MAX_PATH];
354 WCHAR wszMutexName[MAX_PATH];
355 int path_len, suffix_len;
357 if (FAILED(SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE)))
359 ERR("Couldn't get path for default container %lu\n", i);
362 path_len = strlenW(wszCachePath);
363 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
365 if (path_len + suffix_len + 2 > MAX_PATH)
367 ERR("Path too long\n");
371 wszCachePath[path_len] = '\\';
373 strcpyW(wszMutexName, wszCachePath);
377 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
378 wszCachePath[path_len + suffix_len + 1] = '\\';
379 wszCachePath[path_len + suffix_len + 2] = '\0';
382 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
386 void URLCacheContainers_DeleteAll()
388 while(!list_empty(&UrlContainers))
389 URLCacheContainer_DeleteContainer(
390 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
394 static BOOL URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
396 struct list * cursor;
398 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
400 LIST_FOR_EACH(cursor, &UrlContainers)
402 URLCACHECONTAINER * pContainer = LIST_ENTRY(cursor, URLCACHECONTAINER, entry);
403 int prefix_len = strlenW(pContainer->cache_prefix);
404 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
406 TRACE("found container with prefx %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
407 *ppContainer = pContainer;
411 ERR("no container found\n");
412 SetLastError(ERROR_FILE_NOT_FOUND);
416 static BOOL URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
420 int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
421 if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR))))
423 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len);
424 ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer);
425 HeapFree(GetProcessHeap(), 0, lpwszUrl);
431 /***********************************************************************
432 * URLCacheContainer_LockIndex (Internal)
435 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
439 URLCACHE_HEADER * pHeader;
442 WaitForSingleObject(pContainer->hMutex, INFINITE);
444 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
448 ReleaseMutex(pContainer->hMutex);
449 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
452 pHeader = (URLCACHE_HEADER *)pIndexData;
454 /* file has grown - we need to remap to prevent us getting
455 * access violations when we try and access beyond the end
456 * of the memory mapped file */
457 if (pHeader->dwFileSize != pContainer->file_size)
459 URLCacheContainer_CloseIndex(pContainer);
460 if (!URLCacheContainer_OpenIndex(pContainer))
462 ReleaseMutex(pContainer->hMutex);
465 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
469 ReleaseMutex(pContainer->hMutex);
470 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
473 pHeader = (URLCACHE_HEADER *)pIndexData;
476 TRACE("Signature: %s, file size: %ld bytes\n", pHeader->szSignature, pHeader->dwFileSize);
478 for (index = 0; index < pHeader->DirectoryCount; index++)
480 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
486 /***********************************************************************
487 * URLCacheContainer_UnlockIndex (Internal)
490 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
493 ReleaseMutex(pContainer->hMutex);
494 return UnmapViewOfFile(pHeader);
499 #define CHAR_BIT (8 * sizeof(CHAR))
502 /***********************************************************************
503 * URLCache_Allocation_BlockIsFree (Internal)
505 * Is the specified block number free?
512 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
514 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
515 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
518 /***********************************************************************
519 * URLCache_Allocation_BlockFree (Internal)
521 * Marks the specified block as free
527 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
529 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
530 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
533 /***********************************************************************
534 * URLCache_Allocation_BlockAllocate (Internal)
536 * Marks the specified block as allocated
542 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
544 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
545 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
548 /***********************************************************************
549 * URLCache_FindFirstFreeEntry (Internal)
551 * Finds and allocates the first block of free space big enough and
552 * sets ppEntry to point to it.
555 * TRUE if it had enough space
556 * FALSE if it couldn't find enough space
559 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
561 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
564 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
566 for (dwFreeCounter = 0;
567 dwFreeCounter < dwBlocksNeeded &&
568 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
569 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
571 TRACE("Found free block at no. %ld (0x%lx)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
573 if (dwFreeCounter == dwBlocksNeeded)
576 TRACE("Found free blocks starting at no. %ld (0x%lx)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
577 for (index = 0; index < dwBlocksNeeded; index++)
578 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
579 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
580 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
584 FIXME("Grow file\n");
588 /***********************************************************************
589 * URLCache_DeleteEntry (Internal)
591 * Deletes the specified entry and frees the space allocated to it
594 * TRUE if it succeeded
598 static BOOL URLCache_DeleteEntry(CACHEFILE_ENTRY * pEntry)
600 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
604 /***********************************************************************
605 * URLCache_LocalFileNameToPathW (Internal)
607 * Copies the full path to the specified buffer given the local file
608 * name and the index of the directory it is in. Always sets value in
609 * lpBufferSize to the required buffer size (in bytes).
612 * TRUE if the buffer was big enough
613 * FALSE if the buffer was too small
616 static BOOL URLCache_LocalFileNameToPathW(
617 const URLCACHECONTAINER * pContainer,
618 LPCURLCACHE_HEADER pHeader,
619 LPCSTR szLocalFileName,
625 int path_len = strlenW(pContainer->path);
626 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
627 if (Directory >= pHeader->DirectoryCount)
633 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
634 if (nRequired < *lpBufferSize)
638 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
639 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
640 wszPath[dir_len + path_len] = '\\';
641 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
642 *lpBufferSize = nRequired;
645 *lpBufferSize = nRequired;
649 /***********************************************************************
650 * URLCache_LocalFileNameToPathA (Internal)
652 * Copies the full path to the specified buffer given the local file
653 * name and the index of the directory it is in. Always sets value in
654 * lpBufferSize to the required buffer size.
657 * TRUE if the buffer was big enough
658 * FALSE if the buffer was too small
661 static BOOL URLCache_LocalFileNameToPathA(
662 const URLCACHECONTAINER * pContainer,
663 LPCURLCACHE_HEADER pHeader,
664 LPCSTR szLocalFileName,
670 int path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL);
671 int file_name_len = strlen(szLocalFileName);
672 int dir_len = DIR_LENGTH;
673 if (Directory >= pHeader->DirectoryCount)
679 nRequired = (path_len + dir_len + file_name_len + 1) * sizeof(WCHAR);
680 if (nRequired < *lpBufferSize)
682 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, -1, NULL, NULL);
683 strncpy(szPath, pHeader->directory_data[Directory].filename, DIR_LENGTH);
684 szPath[dir_len + path_len] = '\\';
685 strcpy(szPath + dir_len + path_len + 1, szLocalFileName);
686 *lpBufferSize = nRequired;
689 *lpBufferSize = nRequired;
693 /***********************************************************************
694 * URLCache_CopyEntry (Internal)
696 * Copies an entry from the cache index file to the Win32 structure
699 * TRUE if the buffer was big enough
700 * FALSE if the buffer was too small
703 static BOOL URLCache_CopyEntry(
704 URLCACHECONTAINER * pContainer,
705 LPCURLCACHE_HEADER pHeader,
706 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
707 LPDWORD lpdwBufferSize,
708 URL_CACHEFILE_ENTRY * pUrlEntry,
712 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
714 if (*lpdwBufferSize >= dwRequiredSize)
716 lpCacheEntryInfo->lpHeaderInfo = NULL;
717 lpCacheEntryInfo->lpszFileExtension = NULL;
718 lpCacheEntryInfo->lpszLocalFileName = NULL;
719 lpCacheEntryInfo->lpszSourceUrlName = NULL;
720 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
721 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
722 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
723 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
724 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
725 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
726 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
727 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
728 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
729 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
730 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
731 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
732 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
733 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
736 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
737 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
738 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
740 lenUrl = MultiByteToWideChar(CP_ACP, 0, pUrlEntry->szSourceUrlName, -1, NULL, 0);
742 lenUrl = strlen(pUrlEntry->szSourceUrlName);
743 dwRequiredSize += lenUrl + 1;
745 /* FIXME: is source url optional? */
746 if (*lpdwBufferSize >= dwRequiredSize)
748 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrl - 1;
750 MultiByteToWideChar(CP_ACP, 0, pUrlEntry->szSourceUrlName, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
752 memcpy(lpCacheEntryInfo->lpszSourceUrlName, pUrlEntry->szSourceUrlName, (lenUrl + 1) * sizeof(CHAR));
755 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
756 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
757 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
759 if (pUrlEntry->dwOffsetLocalName)
761 LONG nLocalFilePathSize;
762 LPSTR lpszLocalFileName;
763 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
764 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
765 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
766 URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize))
768 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
770 dwRequiredSize += nLocalFilePathSize;
772 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
773 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
774 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
776 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
778 if (*lpdwBufferSize >= dwRequiredSize)
780 lpCacheEntryInfo->lpHeaderInfo = (LPSTR)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
781 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
782 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
784 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
785 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
786 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
788 if (dwRequiredSize > *lpdwBufferSize)
790 *lpdwBufferSize = dwRequiredSize;
791 SetLastError(ERROR_INSUFFICIENT_BUFFER);
794 *lpdwBufferSize = dwRequiredSize;
799 /***********************************************************************
800 * URLCache_SetEntryInfo (Internal)
802 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
803 * according the the flags set by dwFieldControl.
806 * TRUE if the buffer was big enough
807 * FALSE if the buffer was too small
810 static BOOL URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
812 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
813 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
814 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
815 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
816 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
817 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
818 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
819 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
820 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
821 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
822 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
823 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
824 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
825 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
826 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
827 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
832 /***********************************************************************
833 * URLCache_HashKey (Internal)
835 * Returns the hash key for a given string
838 * hash key for the string
841 static DWORD URLCache_HashKey(LPCSTR lpszKey)
843 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
844 * but the algorithm and result are not the same!
846 static const unsigned char lookupTable[256] =
848 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
849 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
850 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
851 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
852 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
853 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
854 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
855 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
856 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
857 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
858 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
859 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
860 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
861 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
862 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
863 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
864 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
865 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
866 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
867 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
868 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
869 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
870 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
871 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
872 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
873 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
874 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
875 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
876 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
877 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
878 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
879 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
883 int subscript[sizeof(key) / sizeof(key[0])];
885 subscript[0] = *lpszKey;
886 subscript[1] = (char)(*lpszKey + 1);
887 subscript[2] = (char)(*lpszKey + 2);
888 subscript[3] = (char)(*lpszKey + 3);
890 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
891 key[i] = lookupTable[i];
893 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
895 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
896 key[i] = lookupTable[*lpszKey ^ key[i]];
899 return *(DWORD *)key;
902 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
904 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
907 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
909 /* structure of hash table:
910 * 448 entries divided into 64 blocks
911 * each block therefore contains a chain of 7 key/offset pairs
912 * how position in table is calculated:
913 * 1. the url is hashed in helper function
914 * 2. the key % 64 * 8 is the offset
915 * 3. the key in the hash table is the hash key aligned to 64
918 * there can be multiple hash tables in the file and the offset to
919 * the next one is stored in the header of the hash table
921 DWORD key = URLCache_HashKey(lpszUrl);
922 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
923 HASH_CACHEFILE_ENTRY * pHashEntry;
924 DWORD dwHashTableNumber = 0;
926 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
928 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
929 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
930 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
933 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
935 ERR("Error: not right hash table number (%ld) expected %ld\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
938 /* make sure that it is in fact a hash entry */
939 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
941 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
945 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
947 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
948 if (key == (DWORD)(pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
950 /* FIXME: we should make sure that this is the right element
951 * before returning and claiming that it is. We can do this
952 * by doing a simple compare between the URL we were given
953 * and the URL stored in the entry. However, this assumes
954 * we know the format of all the entries stored in the
956 *ppHashEntry = pHashElement;
964 /***********************************************************************
965 * URLCache_FindEntryInHash (Internal)
967 * Searches all the hash tables in the index for the given URL and
968 * returns the entry, if it was found, in ppEntry
971 * TRUE if the entry was found
972 * FALSE if the entry could not be found
975 static BOOL URLCache_FindEntryInHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, CACHEFILE_ENTRY ** ppEntry)
977 struct _HASH_ENTRY * pHashEntry;
978 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
980 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
986 /***********************************************************************
987 * URLCache_HashEntrySetUse (Internal)
989 * Searches all the hash tables in the index for the given URL and
990 * sets the use count (stored or'ed with key)
993 * TRUE if the entry was found
994 * FALSE if the entry could not be found
997 static BOOL URLCache_HashEntrySetUse(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwUseCount)
999 struct _HASH_ENTRY * pHashEntry;
1000 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1002 pHashEntry->dwHashKey = dwUseCount | (DWORD)(pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1008 /***********************************************************************
1009 * URLCache_DeleteEntryFromHash (Internal)
1011 * Searches all the hash tables in the index for the given URL and
1012 * then if found deletes the entry.
1015 * TRUE if the entry was found
1016 * FALSE if the entry could not be found
1019 static BOOL URLCache_DeleteEntryFromHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl)
1021 struct _HASH_ENTRY * pHashEntry;
1022 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1024 pHashEntry->dwHashKey = HASHTABLE_FREE;
1025 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1031 /***********************************************************************
1032 * URLCache_AddEntryToHash (Internal)
1034 * Searches all the hash tables for a free slot based on the offset
1035 * generated from the hash key. If a free slot is found, the offset and
1036 * key are entered into the hash table.
1039 * TRUE if the entry was added
1040 * FALSE if the entry could not be added
1043 static BOOL URLCache_AddEntryToHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1045 /* see URLCache_FindEntryInHash for structure of hash tables */
1047 DWORD key = URLCache_HashKey(lpszUrl);
1048 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1049 HASH_CACHEFILE_ENTRY * pHashEntry;
1050 DWORD dwHashTableNumber = 0;
1052 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1054 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1055 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1056 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1059 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1061 ERR("not right hash table number (%ld) expected %ld\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1064 /* make sure that it is in fact a hash entry */
1065 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1067 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1071 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1073 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1074 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1076 pHashElement->dwHashKey = key;
1077 pHashElement->dwOffsetEntry = dwOffsetEntry;
1082 FIXME("need to create another hash table\n");
1086 /***********************************************************************
1087 * GetUrlCacheEntryInfoExA (WININET.@)
1090 BOOL WINAPI GetUrlCacheEntryInfoExA(
1092 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1093 LPDWORD lpdwCacheEntryInfoBufSize,
1095 LPDWORD lpdwReserved,
1099 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1100 debugstr_a(lpszUrl),
1102 lpdwCacheEntryInfoBufSize,
1108 if ((lpszReserved != NULL) ||
1109 (lpdwReserved != NULL) ||
1110 (lpReserved != NULL))
1112 ERR("Reserved value was not 0\n");
1113 SetLastError(ERROR_INVALID_PARAMETER);
1117 FIXME("Undocumented flag(s): %lx\n", dwFlags);
1118 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1121 /***********************************************************************
1122 * GetUrlCacheEntryInfoA (WININET.@)
1125 BOOL WINAPI GetUrlCacheEntryInfoA(
1126 IN LPCSTR lpszUrlName,
1127 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1128 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1131 LPURLCACHE_HEADER pHeader;
1132 CACHEFILE_ENTRY * pEntry;
1133 URL_CACHEFILE_ENTRY * pUrlEntry;
1134 URLCACHECONTAINER * pContainer;
1136 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1138 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1141 if (!URLCacheContainer_OpenIndex(pContainer))
1144 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1147 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1149 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1150 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1151 SetLastError(ERROR_FILE_NOT_FOUND);
1155 if (pEntry->dwSignature != URL_SIGNATURE)
1157 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1158 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1159 SetLastError(ERROR_FILE_NOT_FOUND);
1163 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1164 TRACE("Found URL: %s\n", debugstr_a(pUrlEntry->szSourceUrlName));
1165 if (pUrlEntry->dwOffsetHeaderInfo)
1166 TRACE("Header info: %s\n", debugstr_a((LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1168 if (!URLCache_CopyEntry(
1172 lpdwCacheEntryInfoBufferSize,
1176 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1179 TRACE("Local File Name: %s\n", debugstr_a(lpCacheEntryInfo->lpszLocalFileName));
1181 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1186 /***********************************************************************
1187 * GetUrlCacheEntryInfoW (WININET.@)
1190 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1191 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1192 LPDWORD lpdwCacheEntryInfoBufferSize)
1194 LPURLCACHE_HEADER pHeader;
1195 CACHEFILE_ENTRY * pEntry;
1196 URL_CACHEFILE_ENTRY * pUrlEntry;
1197 URLCACHECONTAINER * pContainer;
1201 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1203 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1204 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1207 SetLastError(ERROR_OUTOFMEMORY);
1210 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1212 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1214 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1218 if (!URLCacheContainer_OpenIndex(pContainer))
1220 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1224 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1226 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1230 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1232 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1233 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1234 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1235 SetLastError(ERROR_FILE_NOT_FOUND);
1238 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1240 if (pEntry->dwSignature != URL_SIGNATURE)
1242 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1243 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1244 SetLastError(ERROR_FILE_NOT_FOUND);
1248 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1249 TRACE("Found URL: %s\n", debugstr_a(pUrlEntry->szSourceUrlName));
1250 TRACE("Header info: %s\n", debugstr_a((LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1252 if (!URLCache_CopyEntry(
1255 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1256 lpdwCacheEntryInfoBufferSize,
1258 TRUE /* UNICODE */))
1260 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1263 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1265 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1270 /***********************************************************************
1271 * GetUrlCacheEntryInfoExW (WININET.@)
1274 BOOL WINAPI GetUrlCacheEntryInfoExW(
1276 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1277 LPDWORD lpdwCacheEntryInfoBufSize,
1278 LPWSTR lpszReserved,
1279 LPDWORD lpdwReserved,
1283 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1284 debugstr_w(lpszUrl),
1286 lpdwCacheEntryInfoBufSize,
1292 if ((lpszReserved != NULL) ||
1293 (lpdwReserved != NULL) ||
1294 (lpReserved != NULL))
1296 ERR("Reserved value was not 0\n");
1297 SetLastError(ERROR_INVALID_PARAMETER);
1301 FIXME("Undocumented flag(s): %lx\n", dwFlags);
1302 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1305 /***********************************************************************
1306 * SetUrlCacheEntryInfoA (WININET.@)
1308 BOOL WINAPI SetUrlCacheEntryInfoA(
1310 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1311 DWORD dwFieldControl)
1313 LPURLCACHE_HEADER pHeader;
1314 CACHEFILE_ENTRY * pEntry;
1315 URLCACHECONTAINER * pContainer;
1317 TRACE("(%s, %p, 0x%08lx)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1319 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1322 if (!URLCacheContainer_OpenIndex(pContainer))
1325 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1328 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1330 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1331 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1332 SetLastError(ERROR_FILE_NOT_FOUND);
1336 if (pEntry->dwSignature != URL_SIGNATURE)
1338 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1339 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1340 SetLastError(ERROR_FILE_NOT_FOUND);
1344 URLCache_SetEntryInfo(
1345 (URL_CACHEFILE_ENTRY *)pEntry,
1346 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1349 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1354 /***********************************************************************
1355 * SetUrlCacheEntryInfoW (WININET.@)
1357 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1359 LPURLCACHE_HEADER pHeader;
1360 CACHEFILE_ENTRY * pEntry;
1361 URLCACHECONTAINER * pContainer;
1365 TRACE("(%s, %p, 0x%08lx)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1367 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1368 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1371 SetLastError(ERROR_OUTOFMEMORY);
1374 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1376 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1378 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1382 if (!URLCacheContainer_OpenIndex(pContainer))
1384 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1388 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1390 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1394 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1396 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1397 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1398 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1399 SetLastError(ERROR_FILE_NOT_FOUND);
1402 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1404 if (pEntry->dwSignature != URL_SIGNATURE)
1406 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1407 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1408 SetLastError(ERROR_FILE_NOT_FOUND);
1412 URLCache_SetEntryInfo(
1413 (URL_CACHEFILE_ENTRY *)pEntry,
1417 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1422 /***********************************************************************
1423 * RetrieveUrlCacheEntryFileA (WININET.@)
1426 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1427 IN LPCSTR lpszUrlName,
1428 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1429 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1433 LPURLCACHE_HEADER pHeader;
1434 CACHEFILE_ENTRY * pEntry;
1435 URL_CACHEFILE_ENTRY * pUrlEntry;
1436 URLCACHECONTAINER * pContainer;
1438 TRACE("(%s, %p, %p, 0x%08lx)\n",
1439 debugstr_a(lpszUrlName),
1441 lpdwCacheEntryInfoBufferSize,
1444 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1447 if (!URLCacheContainer_OpenIndex(pContainer))
1450 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1453 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1455 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1456 TRACE("entry %s not found!\n", lpszUrlName);
1457 SetLastError(ERROR_FILE_NOT_FOUND);
1461 if (pEntry->dwSignature != URL_SIGNATURE)
1463 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1464 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1465 SetLastError(ERROR_FILE_NOT_FOUND);
1469 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1470 TRACE("Found URL: %s\n", pUrlEntry->szSourceUrlName);
1471 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1473 pUrlEntry->dwHitRate++;
1474 pUrlEntry->dwUseCount++;
1475 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1477 if (!URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize, pUrlEntry, FALSE))
1479 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1482 TRACE("Local File Name: %s\n", lpCacheEntryInfo->lpszLocalFileName);
1484 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1489 /***********************************************************************
1490 * UnlockUrlCacheEntryFileA (WININET.@)
1493 BOOL WINAPI UnlockUrlCacheEntryFileA(
1494 IN LPCSTR lpszUrlName,
1498 LPURLCACHE_HEADER pHeader;
1499 CACHEFILE_ENTRY * pEntry;
1500 URL_CACHEFILE_ENTRY * pUrlEntry;
1501 URLCACHECONTAINER * pContainer;
1503 TRACE("(%s, 0x%08lx)\n", debugstr_a(lpszUrlName), dwReserved);
1507 ERR("dwReserved != 0\n");
1508 SetLastError(ERROR_INVALID_PARAMETER);
1512 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1515 if (!URLCacheContainer_OpenIndex(pContainer))
1518 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1521 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1523 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1524 TRACE("entry %s not found!\n", lpszUrlName);
1525 SetLastError(ERROR_FILE_NOT_FOUND);
1529 if (pEntry->dwSignature != URL_SIGNATURE)
1531 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1532 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1533 SetLastError(ERROR_FILE_NOT_FOUND);
1537 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1539 if (pUrlEntry->dwUseCount == 0)
1541 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1544 pUrlEntry->dwUseCount--;
1545 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1547 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1552 /***********************************************************************
1553 * CreateUrlCacheEntryA (WININET.@)
1556 BOOL WINAPI CreateUrlCacheEntryA(
1557 IN LPCSTR lpszUrlName,
1558 IN DWORD dwExpectedFileSize,
1559 IN LPCSTR lpszFileExtension,
1560 OUT LPSTR lpszFileName,
1564 URLCACHECONTAINER * pContainer;
1565 LPURLCACHE_HEADER pHeader;
1566 CHAR szFile[MAX_PATH];
1567 CHAR szExtension[MAX_PATH];
1570 LPCSTR lpszFileNameExtension;
1571 LPSTR lpszFileNameNoPath;
1573 int countnoextension;
1576 BOOL bFound = FALSE;
1579 TRACE("(%s, 0x%08lx, %s, %p, 0x%08lx)\n",
1580 debugstr_a(lpszUrlName),
1582 debugstr_a(lpszFileExtension),
1588 ERR("dwReserved != 0\n");
1589 SetLastError(ERROR_INVALID_PARAMETER);
1593 for (lpszUrlEnd = lpszUrlName; *lpszUrlEnd; lpszUrlEnd++)
1596 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/'))
1599 for (lpszUrlPart = lpszUrlEnd;
1600 (lpszUrlPart >= lpszUrlName);
1603 if ((*lpszUrlPart == '/') && ((lpszUrlEnd - lpszUrlPart) > 1))
1610 if (!strcmp(lpszUrlPart, "www"))
1612 lpszUrlPart += strlen("www");
1615 count = lpszUrlEnd - lpszUrlPart;
1617 if (bFound && (count < MAX_PATH))
1619 memcpy(szFile, lpszUrlPart, count * sizeof(CHAR));
1620 szFile[count] = '\0';
1621 /* FIXME: get rid of illegal characters like \, / and : */
1625 FIXME("need to generate a random filename\n");
1628 TRACE("File name: %s\n", szFile);
1630 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1633 if (!URLCacheContainer_OpenIndex(pContainer))
1636 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1639 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
1641 lBufferSize = MAX_PATH * sizeof(CHAR);
1642 URLCache_LocalFileNameToPathA(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
1644 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1646 lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(CHAR) + DIR_LENGTH + 1;
1648 countnoextension = strlen(lpszFileNameNoPath);
1649 lpszFileNameExtension = PathFindExtensionA(lpszFileNameNoPath);
1650 if (lpszFileNameExtension)
1651 countnoextension -= strlen(lpszFileNameExtension);
1652 *szExtension = '\0';
1654 if (lpszFileExtension)
1656 szExtension[0] = '.';
1657 strcpy(szExtension+1, lpszFileExtension);
1660 for (i = 0; i < 255; i++)
1663 strncpy(lpszFileNameNoPath, szFile, countnoextension);
1664 sprintf(lpszFileNameNoPath + countnoextension, "[%u]%s", i, szExtension);
1665 TRACE("Trying: %s\n", lpszFileName);
1666 hFile = CreateFileA(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
1667 if (hFile != INVALID_HANDLE_VALUE)
1677 /***********************************************************************
1678 * CommitUrlCacheEntryA (WININET.@)
1681 BOOL WINAPI CommitUrlCacheEntryA(
1682 IN LPCSTR lpszUrlName,
1683 IN LPCSTR lpszLocalFileName,
1684 IN FILETIME ExpireTime,
1685 IN FILETIME LastModifiedTime,
1686 IN DWORD CacheEntryType,
1687 IN LPBYTE lpHeaderInfo,
1688 IN DWORD dwHeaderSize,
1689 IN LPCSTR lpszFileExtension,
1690 IN LPCSTR dwReserved
1693 URLCACHECONTAINER * pContainer;
1694 LPURLCACHE_HEADER pHeader;
1695 CACHEFILE_ENTRY * pEntry;
1696 URL_CACHEFILE_ENTRY * pUrlEntry;
1697 DWORD dwBytesNeeded = sizeof(*pUrlEntry) - sizeof(pUrlEntry->szSourceUrlName);
1698 DWORD dwOffsetLocalFileName = 0;
1699 DWORD dwOffsetHeader = 0;
1700 DWORD dwFileSizeLow = 0;
1701 DWORD dwFileSizeHigh = 0;
1702 BYTE cDirectory = 0;
1704 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %p)\n",
1705 debugstr_a(lpszUrlName),
1706 debugstr_a(lpszLocalFileName),
1715 ERR("dwReserved != 0\n");
1716 SetLastError(ERROR_INVALID_PARAMETER);
1719 if (lpHeaderInfo == NULL)
1721 FIXME("lpHeaderInfo == NULL - will crash at the moment\n");
1724 if (lpszLocalFileName)
1727 hFile = CreateFileA(lpszLocalFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
1728 if (hFile == INVALID_HANDLE_VALUE)
1730 ERR("couldn't open file %s (error is %ld)\n", debugstr_a(lpszLocalFileName), GetLastError());
1735 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
1736 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
1738 ERR("couldn't get file size (error is %ld)\n", GetLastError());
1746 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1749 if (!URLCacheContainer_OpenIndex(pContainer))
1752 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1755 if (URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1757 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1758 FIXME("entry already in cache - don't know what to do!\n");
1760 * SetLastError(ERROR_FILE_NOT_FOUND);
1766 if (lpszLocalFileName)
1768 BOOL bFound = FALSE;
1769 char szContainerPath[MAX_PATH];
1770 int container_path_len;
1771 container_path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szContainerPath, sizeof(szContainerPath), NULL, NULL);
1772 if (!container_path_len)
1774 /* WideCharToMultiByte should have called SetLastError */
1778 if (strncmp(lpszLocalFileName, szContainerPath, container_path_len))
1780 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1781 ERR("path %s must begin with cache content path %s\n", debugstr_a(lpszLocalFileName), debugstr_a(szContainerPath));
1782 SetLastError(ERROR_INVALID_PARAMETER);
1786 /* skip container path prefix */
1787 lpszLocalFileName += container_path_len;
1789 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
1791 if (!strncmp(pHeader->directory_data[cDirectory].filename, lpszLocalFileName, DIR_LENGTH))
1800 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1801 ERR("cache directory not found in path %s\n", lpszLocalFileName);
1802 SetLastError(ERROR_INVALID_PARAMETER);
1806 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
1809 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlName) + 1);
1810 if (lpszLocalFileName)
1812 dwOffsetLocalFileName = dwBytesNeeded;
1813 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszLocalFileName) + 1);
1817 dwOffsetHeader = dwBytesNeeded;
1818 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
1821 /* round up to next block */
1822 if (dwBytesNeeded % BLOCKSIZE)
1824 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
1825 dwBytesNeeded += BLOCKSIZE;
1828 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
1830 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1831 ERR("no free entries\n");
1835 /* FindFirstFreeEntry fills in blocks used */
1836 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1837 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
1838 pUrlEntry->CacheDir = cDirectory;
1839 pUrlEntry->CacheEntryType = CacheEntryType;
1840 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
1841 pUrlEntry->dwExemptDelta = 0;
1842 pUrlEntry->dwHitRate = 0;
1843 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
1844 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
1845 pUrlEntry->dwOffsetUrl = sizeof(*pUrlEntry) - sizeof(pUrlEntry->szSourceUrlName);
1846 pUrlEntry->dwSizeHigh = 0;
1847 pUrlEntry->dwSizeLow = dwFileSizeLow;
1848 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
1849 pUrlEntry->dwUseCount = 0;
1850 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
1851 pUrlEntry->LastModifiedTime = LastModifiedTime;
1852 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1853 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
1854 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
1855 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
1858 pUrlEntry->dwUnknown1 = 0;
1859 pUrlEntry->dwUnknown2 = 0;
1860 pUrlEntry->dwUnknown3 = 0x60;
1861 pUrlEntry->Unknown4 = 0;
1862 pUrlEntry->wUnknown5 = 0x1010;
1863 pUrlEntry->dwUnknown6 = 0;
1864 pUrlEntry->dwUnknown7 = 0;
1865 pUrlEntry->dwUnknown8 = 0;
1867 strcpy(pUrlEntry->szSourceUrlName, lpszUrlName);
1868 if (dwOffsetLocalFileName)
1869 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), lpszLocalFileName);
1871 memcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetHeader), lpHeaderInfo, dwHeaderSize);
1873 if (!URLCache_AddEntryToHash(pHeader, lpszUrlName, (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader)))
1875 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1879 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1884 BOOL WINAPI ReadUrlCacheEntryStream(
1885 IN HANDLE hUrlCacheStream,
1886 IN DWORD dwLocation,
1887 IN OUT LPVOID lpBuffer,
1888 IN OUT LPDWORD lpdwLen,
1892 /* Get handle to file from 'stream' */
1893 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
1895 if (dwReserved != 0)
1897 ERR("dwReserved != 0\n");
1898 SetLastError(ERROR_INVALID_PARAMETER);
1902 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
1904 SetLastError(ERROR_INVALID_HANDLE);
1908 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
1910 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
1913 /***********************************************************************
1914 * RetrieveUrlCacheEntryStreamA (WININET.@)
1917 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
1918 IN LPCSTR lpszUrlName,
1919 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1920 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1921 IN BOOL fRandomRead,
1925 /* NOTE: this is not the same as the way that the native
1926 * version allocates 'stream' handles. I did it this way
1927 * as it is much easier and no applications should depend
1928 * on this behaviour. (Native version appears to allocate
1929 * indices into a table)
1931 STREAM_HANDLE * pStream;
1934 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
1936 lpdwCacheEntryInfoBufferSize,
1942 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
1947 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
1949 if (hFile == INVALID_HANDLE_VALUE)
1952 /* allocate handle storage space */
1953 pStream = (STREAM_HANDLE *)HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
1957 SetLastError(ERROR_OUTOFMEMORY);
1961 pStream->hFile = hFile;
1962 strcpy(pStream->lpszUrl, lpszUrlName);
1963 return (HANDLE)pStream;
1966 /***********************************************************************
1967 * UnlockUrlCacheEntryStream (WININET.@)
1970 BOOL WINAPI UnlockUrlCacheEntryStream(
1971 IN HANDLE hUrlCacheStream,
1975 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
1977 if (dwReserved != 0)
1979 ERR("dwReserved != 0\n");
1980 SetLastError(ERROR_INVALID_PARAMETER);
1984 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
1986 SetLastError(ERROR_INVALID_HANDLE);
1990 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
1993 /* close file handle */
1994 CloseHandle(pStream->hFile);
1996 /* free allocated space */
1997 HeapFree(GetProcessHeap(), 0, pStream);
2003 /***********************************************************************
2004 * DeleteUrlCacheEntryA (WININET.@)
2007 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2009 URLCACHECONTAINER * pContainer;
2010 LPURLCACHE_HEADER pHeader;
2011 CACHEFILE_ENTRY * pEntry;
2014 BYTE * AllocationTable;
2016 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2018 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
2021 if (!URLCacheContainer_OpenIndex(pContainer))
2024 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2027 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
2029 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2030 TRACE("entry %s not found!\n", lpszUrlName);
2031 SetLastError(ERROR_FILE_NOT_FOUND);
2035 AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
2037 /* update allocation table */
2038 dwStartBlock = ((DWORD)pEntry - (DWORD)pHeader) / BLOCKSIZE;
2039 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
2040 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
2042 URLCache_DeleteEntry(pEntry);
2044 URLCache_DeleteEntryFromHash(pHeader, lpszUrlName);
2046 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2051 /***********************************************************************
2052 * FindFirstUrlCacheEntryA (WININET.@)
2055 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
2056 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2058 FIXME("(%s, %p, %p): stub\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2059 SetLastError(ERROR_FILE_NOT_FOUND);
2063 /***********************************************************************
2064 * FindFirstUrlCacheEntryW (WININET.@)
2067 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
2068 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2070 FIXME("(%s, %p, %p): stub\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2074 /***********************************************************************
2075 * CreateUrlCacheGroup (WININET.@)
2078 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID
2081 FIXME("(%lx, %p): stub\n", dwFlags, lpReserved);
2085 /***********************************************************************
2086 * DeleteUrlCacheGroup (WININET.@)
2089 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
2095 /***********************************************************************
2096 * SetUrlCacheEntryGroup (WININET.@)
2099 BOOL WINAPI SetUrlCacheEntryGroup(LPCSTR lpszUrlName, DWORD dwFlags,
2100 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2104 SetLastError(ERROR_FILE_NOT_FOUND);
2108 /***********************************************************************
2109 * GetUrlCacheConfigInfoW (WININET.@)
2111 BOOL WINAPI GetUrlCacheConfigInfoW(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2113 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2114 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2118 /***********************************************************************
2119 * GetUrlCacheConfigInfoA (WININET.@)
2121 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
2123 BOOL WINAPI GetUrlCacheConfigInfoA(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2125 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2126 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2130 /***********************************************************************
2131 * DeleteIE3Cache (WININET.@)
2133 * Deletes the files used by the IE3 URL caching system.
2136 * hWnd [I] A dummy window.
2137 * hInst [I] Instance of process calling the function.
2138 * lpszCmdLine [I] Options used by function.
2139 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
2144 void WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
2146 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);