2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003 Robert Shearman
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #define COM_NO_WINDOWS_H
27 #include "wine/port.h"
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
49 #include "wine/unicode.h"
50 #include "wine/list.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
55 #define ENTRY_START_OFFSET 0x4000
58 #define HASHTABLE_SIZE 448
59 #define HASHTABLE_BLOCKSIZE 7
60 #define HASHTABLE_FREE 3
61 #define ALLOCATION_TABLE_OFFSET 0x250
62 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
63 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
65 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
66 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
67 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
68 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
69 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
71 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
73 typedef struct _CACHEFILE_ENTRY
77 DWORD dwSignature; /* e.g. "URL " */
78 /* CHAR szSignature[4];
80 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
83 typedef struct _URL_CACHEFILE_ENTRY
85 CACHEFILE_ENTRY CacheFileEntry;
86 FILETIME LastModifiedTime;
87 FILETIME LastAccessTime;
88 WORD wExpiredDate; /* expire date in dos format */
89 WORD wExpiredTime; /* expire time in dos format */
90 DWORD dwUnknown1; /* usually zero */
91 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
92 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
93 DWORD dwUnknown2; /* usually zero */
94 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
95 DWORD dwUnknown3; /* usually 0x60 */
96 DWORD dwOffsetUrl; /* usually 0x68 */
97 BYTE CacheDir; /* index of cache directory this url is stored in */
98 BYTE Unknown4; /* usually zero */
99 WORD wUnknown5; /* usually 0x1010 */
100 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
101 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
102 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
103 DWORD dwHeaderInfoSize;
104 DWORD dwUnknown6; /* usually zero */
105 WORD wLastSyncDate; /* last sync date in dos format */
106 WORD wLastSyncTime; /* last sync time in dos format */
107 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
108 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
109 WORD wUnknownDate; /* usually same as wLastSyncDate */
110 WORD wUnknownTime; /* usually same as wLastSyncTime */
111 DWORD dwUnknown7; /* usually zero */
112 DWORD dwUnknown8; /* usually zero */
113 CHAR szSourceUrlName[1]; /* start of url */
114 /* packing to dword align start of next field */
115 /* CHAR szLocalFileName[]; (local file name exluding path) */
116 /* packing to dword align start of next field */
117 /* CHAR szHeaderInfo[]; (header info) */
118 } URL_CACHEFILE_ENTRY;
126 typedef struct _HASH_CACHEFILE_ENTRY
128 CACHEFILE_ENTRY CacheFileEntry;
130 DWORD dwHashTableNumber;
131 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
132 } HASH_CACHEFILE_ENTRY;
134 typedef struct _DIRECTORY_DATA
137 char filename[DIR_LENGTH];
140 typedef struct _URLCACHE_HEADER
142 char szSignature[28];
144 DWORD dwOffsetFirstHashTable;
145 DWORD dwIndexCapacityInBlocks;
146 DWORD dwBlocksInUse; /* is this right? */
148 DWORD dwCacheLimitLow; /* disk space limit for cache */
149 DWORD dwCacheLimitHigh; /* disk space limit for cache */
150 DWORD dwUnknown4; /* current disk space usage for cache? */
151 DWORD dwUnknown5; /* current disk space usage for cache? */
152 DWORD dwUnknown6; /* possibly a flag? */
154 BYTE DirectoryCount; /* number of directory_data's */
155 BYTE Unknown8[3]; /* just padding? */
156 DIRECTORY_DATA directory_data[1]; /* first directory entry */
157 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
158 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
160 typedef struct _STREAM_HANDLE
166 typedef struct _URLCACHECONTAINER
168 struct list entry; /* part of a list */
169 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
170 LPWSTR path; /* path to url container directory */
171 HANDLE hMapping; /* handle of file mapping */
172 DWORD file_size; /* size of file when mapping was opened */
173 HANDLE hMutex; /* hande of mutex */
177 /* List of all containers available */
178 static struct list UrlContainers = LIST_INIT(UrlContainers);
181 /***********************************************************************
182 * URLCache_PathToObjectName (Internal)
184 * Converts a path to a name suitable for use as a Win32 object name.
185 * Replaces '\\' characters in-place with the specified character
186 * (usually '_' or '!')
192 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
194 for (; *lpszPath; lpszPath++)
196 if (*lpszPath == '\\')
201 /***********************************************************************
202 * URLCacheContainer_OpenIndex (Internal)
204 * Opens the index file and saves mapping handle in hCacheIndexMapping
211 static BOOL URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
214 WCHAR wszFilePath[MAX_PATH];
217 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
218 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
220 if (pContainer->hMapping)
223 strcpyW(wszFilePath, pContainer->path);
224 strcatW(wszFilePath, wszIndex);
226 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
227 if (hFile == INVALID_HANDLE_VALUE)
229 FIXME("need to create cache index file\n");
233 dwFileSize = GetFileSize(hFile, NULL);
234 if (dwFileSize == INVALID_FILE_SIZE)
239 FIXME("need to create cache index file\n");
243 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
244 URLCache_PathToObjectName(wszFilePath, '_');
245 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
246 if (!pContainer->hMapping)
247 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
249 if (!pContainer->hMapping)
251 ERR("Couldn't create file mapping (error is %ld)\n", GetLastError());
258 /***********************************************************************
259 * URLCacheContainer_CloseIndex (Internal)
267 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
269 CloseHandle(pContainer->hMapping);
270 pContainer->hMapping = NULL;
273 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
275 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
276 int path_len = strlenW(path);
277 int cache_prefix_len = strlenW(cache_prefix);
284 pContainer->hMapping = NULL;
285 pContainer->file_size = 0;
287 pContainer->path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR));
288 if (!pContainer->path)
290 HeapFree(GetProcessHeap(), 0, pContainer);
294 memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR));
296 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
297 if (!pContainer->cache_prefix)
299 HeapFree(GetProcessHeap(), 0, pContainer->path);
300 HeapFree(GetProcessHeap(), 0, pContainer);
304 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
306 CharLowerW(mutex_name);
307 URLCache_PathToObjectName(mutex_name, '!');
309 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
311 ERR("couldn't create mutex (error is %ld)\n", GetLastError());
312 HeapFree(GetProcessHeap(), 0, pContainer->path);
313 HeapFree(GetProcessHeap(), 0, pContainer);
317 list_add_head(&UrlContainers, &pContainer->entry);
322 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
324 list_remove(&pContainer->entry);
326 URLCacheContainer_CloseIndex(pContainer);
327 CloseHandle(pContainer->hMutex);
328 HeapFree(GetProcessHeap(), 0, pContainer->path);
329 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
330 HeapFree(GetProcessHeap(), 0, pContainer);
333 void URLCacheContainers_CreateDefaults()
335 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
336 static const WCHAR UrlPrefix[] = {0};
337 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
338 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
339 static const WCHAR CookieSuffix[] = {0};
340 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
343 int nFolder; /* CSIDL_* constant */
344 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
345 const WCHAR * cache_prefix; /* prefix used to reference the container */
346 } DefaultContainerData[] =
348 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
349 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
350 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
354 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
356 WCHAR wszCachePath[MAX_PATH];
357 WCHAR wszMutexName[MAX_PATH];
358 int path_len, suffix_len;
360 if (FAILED(SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE)))
362 ERR("Couldn't get path for default container %lu\n", i);
365 path_len = strlenW(wszCachePath);
366 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
368 if (path_len + suffix_len + 2 > MAX_PATH)
370 ERR("Path too long\n");
374 wszCachePath[path_len] = '\\';
376 strcpyW(wszMutexName, wszCachePath);
380 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
381 wszCachePath[path_len + suffix_len + 1] = '\\';
382 wszCachePath[path_len + suffix_len + 2] = '\0';
385 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
389 void URLCacheContainers_DeleteAll()
391 while(!list_empty(&UrlContainers))
392 URLCacheContainer_DeleteContainer(
393 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
397 static BOOL URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
399 struct list * cursor;
401 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
403 LIST_FOR_EACH(cursor, &UrlContainers)
405 URLCACHECONTAINER * pContainer = LIST_ENTRY(cursor, URLCACHECONTAINER, entry);
406 int prefix_len = strlenW(pContainer->cache_prefix);
407 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
409 TRACE("found container with prefx %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
410 *ppContainer = pContainer;
414 ERR("no container found\n");
415 SetLastError(ERROR_FILE_NOT_FOUND);
419 static BOOL URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
423 int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
424 if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR))))
426 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len);
427 ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer);
428 HeapFree(GetProcessHeap(), 0, lpwszUrl);
434 /***********************************************************************
435 * URLCacheContainer_LockIndex (Internal)
438 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
442 URLCACHE_HEADER * pHeader;
445 WaitForSingleObject(pContainer->hMutex, INFINITE);
447 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
451 ReleaseMutex(pContainer->hMutex);
452 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
455 pHeader = (URLCACHE_HEADER *)pIndexData;
457 /* file has grown - we need to remap to prevent us getting
458 * access violations when we try and access beyond the end
459 * of the memory mapped file */
460 if (pHeader->dwFileSize != pContainer->file_size)
462 URLCacheContainer_CloseIndex(pContainer);
463 if (!URLCacheContainer_OpenIndex(pContainer))
465 ReleaseMutex(pContainer->hMutex);
468 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
472 ReleaseMutex(pContainer->hMutex);
473 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
476 pHeader = (URLCACHE_HEADER *)pIndexData;
479 TRACE("Signature: %s, file size: %ld bytes\n", pHeader->szSignature, pHeader->dwFileSize);
481 for (index = 0; index < pHeader->DirectoryCount; index++)
483 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
489 /***********************************************************************
490 * URLCacheContainer_UnlockIndex (Internal)
493 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
496 ReleaseMutex(pContainer->hMutex);
497 return UnmapViewOfFile(pHeader);
502 #define CHAR_BIT (8 * sizeof(CHAR))
505 /***********************************************************************
506 * URLCache_Allocation_BlockIsFree (Internal)
508 * Is the specified block number free?
515 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
517 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
518 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
521 /***********************************************************************
522 * URLCache_Allocation_BlockFree (Internal)
524 * Marks the specified block as free
530 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
532 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
533 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
536 /***********************************************************************
537 * URLCache_Allocation_BlockAllocate (Internal)
539 * Marks the specified block as allocated
545 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
547 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
548 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
551 /***********************************************************************
552 * URLCache_FindFirstFreeEntry (Internal)
554 * Finds and allocates the first block of free space big enough and
555 * sets ppEntry to point to it.
558 * TRUE if it had enough space
559 * FALSE if it couldn't find enough space
562 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
564 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
567 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
569 for (dwFreeCounter = 0;
570 dwFreeCounter < dwBlocksNeeded &&
571 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
572 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
574 TRACE("Found free block at no. %ld (0x%lx)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
576 if (dwFreeCounter == dwBlocksNeeded)
579 TRACE("Found free blocks starting at no. %ld (0x%lx)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
580 for (index = 0; index < dwBlocksNeeded; index++)
581 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
582 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
583 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
587 FIXME("Grow file\n");
591 /***********************************************************************
592 * URLCache_DeleteEntry (Internal)
594 * Deletes the specified entry and frees the space allocated to it
597 * TRUE if it succeeded
601 static BOOL URLCache_DeleteEntry(CACHEFILE_ENTRY * pEntry)
603 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
607 /***********************************************************************
608 * URLCache_LocalFileNameToPathW (Internal)
610 * Copies the full path to the specified buffer given the local file
611 * name and the index of the directory it is in. Always sets value in
612 * lpBufferSize to the required buffer size (in bytes).
615 * TRUE if the buffer was big enough
616 * FALSE if the buffer was too small
619 static BOOL URLCache_LocalFileNameToPathW(
620 const URLCACHECONTAINER * pContainer,
621 LPCURLCACHE_HEADER pHeader,
622 LPCSTR szLocalFileName,
628 int path_len = strlenW(pContainer->path);
629 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
630 if (Directory >= pHeader->DirectoryCount)
636 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
637 if (nRequired < *lpBufferSize)
641 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
642 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
643 wszPath[dir_len + path_len] = '\\';
644 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
645 *lpBufferSize = nRequired;
648 *lpBufferSize = nRequired;
652 /***********************************************************************
653 * URLCache_LocalFileNameToPathA (Internal)
655 * Copies the full path to the specified buffer given the local file
656 * name and the index of the directory it is in. Always sets value in
657 * lpBufferSize to the required buffer size.
660 * TRUE if the buffer was big enough
661 * FALSE if the buffer was too small
664 static BOOL URLCache_LocalFileNameToPathA(
665 const URLCACHECONTAINER * pContainer,
666 LPCURLCACHE_HEADER pHeader,
667 LPCSTR szLocalFileName,
673 int path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL);
674 int file_name_len = strlen(szLocalFileName);
675 int dir_len = DIR_LENGTH;
676 if (Directory >= pHeader->DirectoryCount)
682 nRequired = (path_len + dir_len + file_name_len + 1) * sizeof(WCHAR);
683 if (nRequired < *lpBufferSize)
685 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, -1, NULL, NULL);
686 strncpy(szPath, pHeader->directory_data[Directory].filename, DIR_LENGTH);
687 szPath[dir_len + path_len] = '\\';
688 strcpy(szPath + dir_len + path_len + 1, szLocalFileName);
689 *lpBufferSize = nRequired;
692 *lpBufferSize = nRequired;
696 /***********************************************************************
697 * URLCache_CopyEntry (Internal)
699 * Copies an entry from the cache index file to the Win32 structure
702 * TRUE if the buffer was big enough
703 * FALSE if the buffer was too small
706 static BOOL URLCache_CopyEntry(
707 URLCACHECONTAINER * pContainer,
708 LPCURLCACHE_HEADER pHeader,
709 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
710 LPDWORD lpdwBufferSize,
711 URL_CACHEFILE_ENTRY * pUrlEntry,
715 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
717 if (*lpdwBufferSize >= dwRequiredSize)
719 lpCacheEntryInfo->lpHeaderInfo = NULL;
720 lpCacheEntryInfo->lpszFileExtension = NULL;
721 lpCacheEntryInfo->lpszLocalFileName = NULL;
722 lpCacheEntryInfo->lpszSourceUrlName = NULL;
723 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
724 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
725 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
726 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
727 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
728 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
729 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
730 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
731 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
732 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
733 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
734 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
735 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
736 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
739 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
740 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
741 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
743 lenUrl = MultiByteToWideChar(CP_ACP, 0, pUrlEntry->szSourceUrlName, -1, NULL, 0);
745 lenUrl = strlen(pUrlEntry->szSourceUrlName);
746 dwRequiredSize += lenUrl + 1;
748 /* FIXME: is source url optional? */
749 if (*lpdwBufferSize >= dwRequiredSize)
751 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrl - 1;
753 MultiByteToWideChar(CP_ACP, 0, pUrlEntry->szSourceUrlName, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
755 memcpy(lpCacheEntryInfo->lpszSourceUrlName, pUrlEntry->szSourceUrlName, (lenUrl + 1) * sizeof(CHAR));
758 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
759 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
760 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
762 if (pUrlEntry->dwOffsetLocalName)
764 LONG nLocalFilePathSize;
765 LPSTR lpszLocalFileName;
766 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
767 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
768 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
769 URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize))
771 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
773 dwRequiredSize += nLocalFilePathSize;
775 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
776 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
777 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
779 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
781 if (*lpdwBufferSize >= dwRequiredSize)
783 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
784 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
785 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
787 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
788 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
789 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
791 if (dwRequiredSize > *lpdwBufferSize)
793 *lpdwBufferSize = dwRequiredSize;
794 SetLastError(ERROR_INSUFFICIENT_BUFFER);
797 *lpdwBufferSize = dwRequiredSize;
802 /***********************************************************************
803 * URLCache_SetEntryInfo (Internal)
805 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
806 * according the the flags set by dwFieldControl.
809 * TRUE if the buffer was big enough
810 * FALSE if the buffer was too small
813 static BOOL URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
815 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
816 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
817 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
818 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
819 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
820 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
821 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
822 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
823 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
824 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
825 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
826 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
827 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
828 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
829 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
830 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
835 /***********************************************************************
836 * URLCache_HashKey (Internal)
838 * Returns the hash key for a given string
841 * hash key for the string
844 static DWORD URLCache_HashKey(LPCSTR lpszKey)
846 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
847 * but the algorithm and result are not the same!
849 static const unsigned char lookupTable[256] =
851 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
852 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
853 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
854 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
855 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
856 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
857 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
858 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
859 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
860 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
861 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
862 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
863 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
864 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
865 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
866 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
867 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
868 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
869 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
870 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
871 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
872 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
873 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
874 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
875 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
876 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
877 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
878 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
879 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
880 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
881 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
882 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
886 int subscript[sizeof(key) / sizeof(key[0])];
888 subscript[0] = *lpszKey;
889 subscript[1] = (char)(*lpszKey + 1);
890 subscript[2] = (char)(*lpszKey + 2);
891 subscript[3] = (char)(*lpszKey + 3);
893 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
894 key[i] = lookupTable[i];
896 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
898 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
899 key[i] = lookupTable[*lpszKey ^ key[i]];
902 return *(DWORD *)key;
905 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
907 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
910 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
912 /* structure of hash table:
913 * 448 entries divided into 64 blocks
914 * each block therefore contains a chain of 7 key/offset pairs
915 * how position in table is calculated:
916 * 1. the url is hashed in helper function
917 * 2. the key % 64 * 8 is the offset
918 * 3. the key in the hash table is the hash key aligned to 64
921 * there can be multiple hash tables in the file and the offset to
922 * the next one is stored in the header of the hash table
924 DWORD key = URLCache_HashKey(lpszUrl);
925 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
926 HASH_CACHEFILE_ENTRY * pHashEntry;
927 DWORD dwHashTableNumber = 0;
929 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
931 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
932 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
933 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
936 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
938 ERR("Error: not right hash table number (%ld) expected %ld\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
941 /* make sure that it is in fact a hash entry */
942 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
944 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
948 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
950 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
951 if (key == (DWORD)(pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
953 /* FIXME: we should make sure that this is the right element
954 * before returning and claiming that it is. We can do this
955 * by doing a simple compare between the URL we were given
956 * and the URL stored in the entry. However, this assumes
957 * we know the format of all the entries stored in the
959 *ppHashEntry = pHashElement;
967 /***********************************************************************
968 * URLCache_FindEntryInHash (Internal)
970 * Searches all the hash tables in the index for the given URL and
971 * returns the entry, if it was found, in ppEntry
974 * TRUE if the entry was found
975 * FALSE if the entry could not be found
978 static BOOL URLCache_FindEntryInHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, CACHEFILE_ENTRY ** ppEntry)
980 struct _HASH_ENTRY * pHashEntry;
981 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
983 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
989 /***********************************************************************
990 * URLCache_HashEntrySetUse (Internal)
992 * Searches all the hash tables in the index for the given URL and
993 * sets the use count (stored or'ed with key)
996 * TRUE if the entry was found
997 * FALSE if the entry could not be found
1000 static BOOL URLCache_HashEntrySetUse(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwUseCount)
1002 struct _HASH_ENTRY * pHashEntry;
1003 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1005 pHashEntry->dwHashKey = dwUseCount | (DWORD)(pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1011 /***********************************************************************
1012 * URLCache_DeleteEntryFromHash (Internal)
1014 * Searches all the hash tables in the index for the given URL and
1015 * then if found deletes the entry.
1018 * TRUE if the entry was found
1019 * FALSE if the entry could not be found
1022 static BOOL URLCache_DeleteEntryFromHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl)
1024 struct _HASH_ENTRY * pHashEntry;
1025 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1027 pHashEntry->dwHashKey = HASHTABLE_FREE;
1028 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1034 /***********************************************************************
1035 * URLCache_AddEntryToHash (Internal)
1037 * Searches all the hash tables for a free slot based on the offset
1038 * generated from the hash key. If a free slot is found, the offset and
1039 * key are entered into the hash table.
1042 * TRUE if the entry was added
1043 * FALSE if the entry could not be added
1046 static BOOL URLCache_AddEntryToHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1048 /* see URLCache_FindEntryInHash for structure of hash tables */
1050 DWORD key = URLCache_HashKey(lpszUrl);
1051 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1052 HASH_CACHEFILE_ENTRY * pHashEntry;
1053 DWORD dwHashTableNumber = 0;
1055 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1057 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1058 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1059 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1062 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1064 ERR("not right hash table number (%ld) expected %ld\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1067 /* make sure that it is in fact a hash entry */
1068 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1070 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1074 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1076 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1077 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1079 pHashElement->dwHashKey = key;
1080 pHashElement->dwOffsetEntry = dwOffsetEntry;
1085 FIXME("need to create another hash table\n");
1089 /***********************************************************************
1090 * GetUrlCacheEntryInfoExA (WININET.@)
1093 BOOL WINAPI GetUrlCacheEntryInfoExA(
1095 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1096 LPDWORD lpdwCacheEntryInfoBufSize,
1098 LPDWORD lpdwReserved,
1102 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1103 debugstr_a(lpszUrl),
1105 lpdwCacheEntryInfoBufSize,
1111 if ((lpszReserved != NULL) ||
1112 (lpdwReserved != NULL) ||
1113 (lpReserved != NULL))
1115 ERR("Reserved value was not 0\n");
1116 SetLastError(ERROR_INVALID_PARAMETER);
1120 FIXME("Undocumented flag(s): %lx\n", dwFlags);
1121 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1124 /***********************************************************************
1125 * GetUrlCacheEntryInfoA (WININET.@)
1128 BOOL WINAPI GetUrlCacheEntryInfoA(
1129 IN LPCSTR lpszUrlName,
1130 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1131 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1134 LPURLCACHE_HEADER pHeader;
1135 CACHEFILE_ENTRY * pEntry;
1136 URL_CACHEFILE_ENTRY * pUrlEntry;
1137 URLCACHECONTAINER * pContainer;
1139 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1141 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1144 if (!URLCacheContainer_OpenIndex(pContainer))
1147 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1150 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1152 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1153 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1154 SetLastError(ERROR_FILE_NOT_FOUND);
1158 if (pEntry->dwSignature != URL_SIGNATURE)
1160 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1161 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1162 SetLastError(ERROR_FILE_NOT_FOUND);
1166 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1167 TRACE("Found URL: %s\n", debugstr_a(pUrlEntry->szSourceUrlName));
1168 if (pUrlEntry->dwOffsetHeaderInfo)
1169 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1171 if (!URLCache_CopyEntry(
1175 lpdwCacheEntryInfoBufferSize,
1179 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1182 TRACE("Local File Name: %s\n", debugstr_a(lpCacheEntryInfo->lpszLocalFileName));
1184 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1189 /***********************************************************************
1190 * GetUrlCacheEntryInfoW (WININET.@)
1193 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1194 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1195 LPDWORD lpdwCacheEntryInfoBufferSize)
1197 LPURLCACHE_HEADER pHeader;
1198 CACHEFILE_ENTRY * pEntry;
1199 URL_CACHEFILE_ENTRY * pUrlEntry;
1200 URLCACHECONTAINER * pContainer;
1204 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1206 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1207 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1210 SetLastError(ERROR_OUTOFMEMORY);
1213 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1215 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1217 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1221 if (!URLCacheContainer_OpenIndex(pContainer))
1223 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1227 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1229 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1233 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1235 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1236 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1237 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1238 SetLastError(ERROR_FILE_NOT_FOUND);
1241 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1243 if (pEntry->dwSignature != URL_SIGNATURE)
1245 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1246 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1247 SetLastError(ERROR_FILE_NOT_FOUND);
1251 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1252 TRACE("Found URL: %s\n", debugstr_a(pUrlEntry->szSourceUrlName));
1253 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1255 if (!URLCache_CopyEntry(
1258 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1259 lpdwCacheEntryInfoBufferSize,
1261 TRUE /* UNICODE */))
1263 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1266 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1268 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1273 /***********************************************************************
1274 * GetUrlCacheEntryInfoExW (WININET.@)
1277 BOOL WINAPI GetUrlCacheEntryInfoExW(
1279 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1280 LPDWORD lpdwCacheEntryInfoBufSize,
1281 LPWSTR lpszReserved,
1282 LPDWORD lpdwReserved,
1286 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1287 debugstr_w(lpszUrl),
1289 lpdwCacheEntryInfoBufSize,
1295 if ((lpszReserved != NULL) ||
1296 (lpdwReserved != NULL) ||
1297 (lpReserved != NULL))
1299 ERR("Reserved value was not 0\n");
1300 SetLastError(ERROR_INVALID_PARAMETER);
1304 FIXME("Undocumented flag(s): %lx\n", dwFlags);
1305 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1308 /***********************************************************************
1309 * SetUrlCacheEntryInfoA (WININET.@)
1311 BOOL WINAPI SetUrlCacheEntryInfoA(
1313 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1314 DWORD dwFieldControl)
1316 LPURLCACHE_HEADER pHeader;
1317 CACHEFILE_ENTRY * pEntry;
1318 URLCACHECONTAINER * pContainer;
1320 TRACE("(%s, %p, 0x%08lx)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1322 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1325 if (!URLCacheContainer_OpenIndex(pContainer))
1328 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1331 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1333 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1334 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1335 SetLastError(ERROR_FILE_NOT_FOUND);
1339 if (pEntry->dwSignature != URL_SIGNATURE)
1341 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1342 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1343 SetLastError(ERROR_FILE_NOT_FOUND);
1347 URLCache_SetEntryInfo(
1348 (URL_CACHEFILE_ENTRY *)pEntry,
1349 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1352 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1357 /***********************************************************************
1358 * SetUrlCacheEntryInfoW (WININET.@)
1360 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1362 LPURLCACHE_HEADER pHeader;
1363 CACHEFILE_ENTRY * pEntry;
1364 URLCACHECONTAINER * pContainer;
1368 TRACE("(%s, %p, 0x%08lx)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1370 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1371 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1374 SetLastError(ERROR_OUTOFMEMORY);
1377 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1379 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1381 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1385 if (!URLCacheContainer_OpenIndex(pContainer))
1387 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1391 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1393 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1397 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1399 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1400 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1401 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1402 SetLastError(ERROR_FILE_NOT_FOUND);
1405 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1407 if (pEntry->dwSignature != URL_SIGNATURE)
1409 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1410 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1411 SetLastError(ERROR_FILE_NOT_FOUND);
1415 URLCache_SetEntryInfo(
1416 (URL_CACHEFILE_ENTRY *)pEntry,
1420 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1425 /***********************************************************************
1426 * RetrieveUrlCacheEntryFileA (WININET.@)
1429 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1430 IN LPCSTR lpszUrlName,
1431 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1432 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1436 LPURLCACHE_HEADER pHeader;
1437 CACHEFILE_ENTRY * pEntry;
1438 URL_CACHEFILE_ENTRY * pUrlEntry;
1439 URLCACHECONTAINER * pContainer;
1441 TRACE("(%s, %p, %p, 0x%08lx)\n",
1442 debugstr_a(lpszUrlName),
1444 lpdwCacheEntryInfoBufferSize,
1447 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1450 if (!URLCacheContainer_OpenIndex(pContainer))
1453 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1456 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1458 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1459 TRACE("entry %s not found!\n", lpszUrlName);
1460 SetLastError(ERROR_FILE_NOT_FOUND);
1464 if (pEntry->dwSignature != URL_SIGNATURE)
1466 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1467 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1468 SetLastError(ERROR_FILE_NOT_FOUND);
1472 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1473 TRACE("Found URL: %s\n", pUrlEntry->szSourceUrlName);
1474 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1476 pUrlEntry->dwHitRate++;
1477 pUrlEntry->dwUseCount++;
1478 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1480 if (!URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize, pUrlEntry, FALSE))
1482 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1485 TRACE("Local File Name: %s\n", lpCacheEntryInfo->lpszLocalFileName);
1487 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1492 /***********************************************************************
1493 * RetrieveUrlCacheEntryFileW (WININET.@)
1496 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1497 IN LPCWSTR lpszUrlName,
1498 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1499 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1503 TRACE("(%s, %p, %p, 0x%08lx)\n",
1504 debugstr_w(lpszUrlName),
1506 lpdwCacheEntryInfoBufferSize,
1512 /***********************************************************************
1513 * UnlockUrlCacheEntryFileA (WININET.@)
1516 BOOL WINAPI UnlockUrlCacheEntryFileA(
1517 IN LPCSTR lpszUrlName,
1521 LPURLCACHE_HEADER pHeader;
1522 CACHEFILE_ENTRY * pEntry;
1523 URL_CACHEFILE_ENTRY * pUrlEntry;
1524 URLCACHECONTAINER * pContainer;
1526 TRACE("(%s, 0x%08lx)\n", debugstr_a(lpszUrlName), dwReserved);
1530 ERR("dwReserved != 0\n");
1531 SetLastError(ERROR_INVALID_PARAMETER);
1535 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1538 if (!URLCacheContainer_OpenIndex(pContainer))
1541 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1544 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1546 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1547 TRACE("entry %s not found!\n", lpszUrlName);
1548 SetLastError(ERROR_FILE_NOT_FOUND);
1552 if (pEntry->dwSignature != URL_SIGNATURE)
1554 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1555 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1556 SetLastError(ERROR_FILE_NOT_FOUND);
1560 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1562 if (pUrlEntry->dwUseCount == 0)
1564 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1567 pUrlEntry->dwUseCount--;
1568 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1570 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1575 /***********************************************************************
1576 * UnlockUrlCacheEntryFileW (WININET.@)
1579 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
1581 FIXME("(%s, 0x%08lx)\n", debugstr_w(lpszUrlName), dwReserved);
1585 /***********************************************************************
1586 * CreateUrlCacheEntryA (WININET.@)
1589 BOOL WINAPI CreateUrlCacheEntryA(
1590 IN LPCSTR lpszUrlName,
1591 IN DWORD dwExpectedFileSize,
1592 IN LPCSTR lpszFileExtension,
1593 OUT LPSTR lpszFileName,
1597 URLCACHECONTAINER * pContainer;
1598 LPURLCACHE_HEADER pHeader;
1599 CHAR szFile[MAX_PATH];
1600 CHAR szExtension[MAX_PATH];
1603 LPCSTR lpszFileNameExtension;
1604 LPSTR lpszFileNameNoPath;
1606 int countnoextension;
1609 BOOL bFound = FALSE;
1612 TRACE("(%s, 0x%08lx, %s, %p, 0x%08lx)\n",
1613 debugstr_a(lpszUrlName),
1615 debugstr_a(lpszFileExtension),
1621 ERR("dwReserved != 0\n");
1622 SetLastError(ERROR_INVALID_PARAMETER);
1626 for (lpszUrlEnd = lpszUrlName; *lpszUrlEnd; lpszUrlEnd++)
1629 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/'))
1632 for (lpszUrlPart = lpszUrlEnd;
1633 (lpszUrlPart >= lpszUrlName);
1636 if ((*lpszUrlPart == '/') && ((lpszUrlEnd - lpszUrlPart) > 1))
1643 if (!strcmp(lpszUrlPart, "www"))
1645 lpszUrlPart += strlen("www");
1648 count = lpszUrlEnd - lpszUrlPart;
1650 if (bFound && (count < MAX_PATH))
1652 memcpy(szFile, lpszUrlPart, count * sizeof(CHAR));
1653 szFile[count] = '\0';
1654 /* FIXME: get rid of illegal characters like \, / and : */
1658 FIXME("need to generate a random filename\n");
1661 TRACE("File name: %s\n", szFile);
1663 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1666 if (!URLCacheContainer_OpenIndex(pContainer))
1669 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1672 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
1674 lBufferSize = MAX_PATH * sizeof(CHAR);
1675 URLCache_LocalFileNameToPathA(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
1677 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1679 lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(CHAR) + DIR_LENGTH + 1;
1681 countnoextension = strlen(lpszFileNameNoPath);
1682 lpszFileNameExtension = PathFindExtensionA(lpszFileNameNoPath);
1683 if (lpszFileNameExtension)
1684 countnoextension -= strlen(lpszFileNameExtension);
1685 *szExtension = '\0';
1687 if (lpszFileExtension)
1689 szExtension[0] = '.';
1690 strcpy(szExtension+1, lpszFileExtension);
1693 for (i = 0; i < 255; i++)
1696 strncpy(lpszFileNameNoPath, szFile, countnoextension);
1697 sprintf(lpszFileNameNoPath + countnoextension, "[%u]%s", i, szExtension);
1698 TRACE("Trying: %s\n", lpszFileName);
1699 hFile = CreateFileA(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
1700 if (hFile != INVALID_HANDLE_VALUE)
1710 /***********************************************************************
1711 * CreateUrlCacheEntryW (WININET.@)
1714 BOOL WINAPI CreateUrlCacheEntryW(
1715 IN LPCWSTR lpszUrlName,
1716 IN DWORD dwExpectedFileSize,
1717 IN LPCWSTR lpszFileExtension,
1718 OUT LPWSTR lpszFileName,
1722 FIXME("(%s, 0x%08lx, %s, %p, 0x%08lx) stub\n",
1723 debugstr_w(lpszUrlName),
1725 debugstr_w(lpszFileExtension),
1732 /***********************************************************************
1733 * CommitUrlCacheEntryA (WININET.@)
1736 BOOL WINAPI CommitUrlCacheEntryA(
1737 IN LPCSTR lpszUrlName,
1738 IN LPCSTR lpszLocalFileName,
1739 IN FILETIME ExpireTime,
1740 IN FILETIME LastModifiedTime,
1741 IN DWORD CacheEntryType,
1742 IN LPBYTE lpHeaderInfo,
1743 IN DWORD dwHeaderSize,
1744 IN LPCSTR lpszFileExtension,
1745 IN LPCSTR dwReserved
1748 URLCACHECONTAINER * pContainer;
1749 LPURLCACHE_HEADER pHeader;
1750 CACHEFILE_ENTRY * pEntry;
1751 URL_CACHEFILE_ENTRY * pUrlEntry;
1752 DWORD dwBytesNeeded = sizeof(*pUrlEntry) - sizeof(pUrlEntry->szSourceUrlName);
1753 DWORD dwOffsetLocalFileName = 0;
1754 DWORD dwOffsetHeader = 0;
1755 DWORD dwFileSizeLow = 0;
1756 DWORD dwFileSizeHigh = 0;
1757 BYTE cDirectory = 0;
1759 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %p)\n",
1760 debugstr_a(lpszUrlName),
1761 debugstr_a(lpszLocalFileName),
1765 debugstr_a(lpszFileExtension),
1770 ERR("dwReserved != 0\n");
1771 SetLastError(ERROR_INVALID_PARAMETER);
1774 if (lpHeaderInfo == NULL)
1776 FIXME("lpHeaderInfo == NULL - will crash at the moment\n");
1779 if (lpszLocalFileName)
1782 hFile = CreateFileA(lpszLocalFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
1783 if (hFile == INVALID_HANDLE_VALUE)
1785 ERR("couldn't open file %s (error is %ld)\n", debugstr_a(lpszLocalFileName), GetLastError());
1790 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
1791 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
1793 ERR("couldn't get file size (error is %ld)\n", GetLastError());
1801 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1804 if (!URLCacheContainer_OpenIndex(pContainer))
1807 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1810 if (URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1812 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1813 FIXME("entry already in cache - don't know what to do!\n");
1815 * SetLastError(ERROR_FILE_NOT_FOUND);
1821 if (lpszLocalFileName)
1823 BOOL bFound = FALSE;
1824 char szContainerPath[MAX_PATH];
1825 int container_path_len;
1826 container_path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szContainerPath, sizeof(szContainerPath), NULL, NULL);
1827 if (!container_path_len)
1829 /* WideCharToMultiByte should have called SetLastError */
1833 if (strncmp(lpszLocalFileName, szContainerPath, container_path_len))
1835 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1836 ERR("path %s must begin with cache content path %s\n", debugstr_a(lpszLocalFileName), debugstr_a(szContainerPath));
1837 SetLastError(ERROR_INVALID_PARAMETER);
1841 /* skip container path prefix */
1842 lpszLocalFileName += container_path_len;
1844 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
1846 if (!strncmp(pHeader->directory_data[cDirectory].filename, lpszLocalFileName, DIR_LENGTH))
1855 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1856 ERR("cache directory not found in path %s\n", lpszLocalFileName);
1857 SetLastError(ERROR_INVALID_PARAMETER);
1861 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
1864 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlName) + 1);
1865 if (lpszLocalFileName)
1867 dwOffsetLocalFileName = dwBytesNeeded;
1868 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszLocalFileName) + 1);
1872 dwOffsetHeader = dwBytesNeeded;
1873 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
1876 /* round up to next block */
1877 if (dwBytesNeeded % BLOCKSIZE)
1879 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
1880 dwBytesNeeded += BLOCKSIZE;
1883 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
1885 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1886 ERR("no free entries\n");
1890 /* FindFirstFreeEntry fills in blocks used */
1891 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1892 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
1893 pUrlEntry->CacheDir = cDirectory;
1894 pUrlEntry->CacheEntryType = CacheEntryType;
1895 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
1896 pUrlEntry->dwExemptDelta = 0;
1897 pUrlEntry->dwHitRate = 0;
1898 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
1899 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
1900 pUrlEntry->dwOffsetUrl = sizeof(*pUrlEntry) - sizeof(pUrlEntry->szSourceUrlName);
1901 pUrlEntry->dwSizeHigh = 0;
1902 pUrlEntry->dwSizeLow = dwFileSizeLow;
1903 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
1904 pUrlEntry->dwUseCount = 0;
1905 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
1906 pUrlEntry->LastModifiedTime = LastModifiedTime;
1907 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1908 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
1909 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
1910 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
1913 pUrlEntry->dwUnknown1 = 0;
1914 pUrlEntry->dwUnknown2 = 0;
1915 pUrlEntry->dwUnknown3 = 0x60;
1916 pUrlEntry->Unknown4 = 0;
1917 pUrlEntry->wUnknown5 = 0x1010;
1918 pUrlEntry->dwUnknown6 = 0;
1919 pUrlEntry->dwUnknown7 = 0;
1920 pUrlEntry->dwUnknown8 = 0;
1922 strcpy(pUrlEntry->szSourceUrlName, lpszUrlName);
1923 if (dwOffsetLocalFileName)
1924 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), lpszLocalFileName);
1926 memcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetHeader), lpHeaderInfo, dwHeaderSize);
1928 if (!URLCache_AddEntryToHash(pHeader, lpszUrlName, (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader)))
1930 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1934 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1939 /***********************************************************************
1940 * CommitUrlCacheEntryW (WININET.@)
1943 BOOL WINAPI CommitUrlCacheEntryW(
1944 IN LPCWSTR lpszUrlName,
1945 IN LPCWSTR lpszLocalFileName,
1946 IN FILETIME ExpireTime,
1947 IN FILETIME LastModifiedTime,
1948 IN DWORD CacheEntryType,
1949 IN LPBYTE lpHeaderInfo,
1950 IN DWORD dwHeaderSize,
1951 IN LPCWSTR lpszFileExtension,
1952 IN LPCWSTR dwReserved
1955 FIXME("(%s, %s, ..., ..., %lx, %p, %ld, %s, %p) stub\n",
1956 debugstr_w(lpszUrlName),
1957 debugstr_w(lpszLocalFileName),
1961 debugstr_w(lpszFileExtension),
1967 /***********************************************************************
1968 * ReadUrlCacheEntryStream (WININET.@)
1971 BOOL WINAPI ReadUrlCacheEntryStream(
1972 IN HANDLE hUrlCacheStream,
1973 IN DWORD dwLocation,
1974 IN OUT LPVOID lpBuffer,
1975 IN OUT LPDWORD lpdwLen,
1979 /* Get handle to file from 'stream' */
1980 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
1982 if (dwReserved != 0)
1984 ERR("dwReserved != 0\n");
1985 SetLastError(ERROR_INVALID_PARAMETER);
1989 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
1991 SetLastError(ERROR_INVALID_HANDLE);
1995 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
1997 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2000 /***********************************************************************
2001 * RetrieveUrlCacheEntryStreamA (WININET.@)
2004 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2005 IN LPCSTR lpszUrlName,
2006 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2007 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2008 IN BOOL fRandomRead,
2012 /* NOTE: this is not the same as the way that the native
2013 * version allocates 'stream' handles. I did it this way
2014 * as it is much easier and no applications should depend
2015 * on this behaviour. (Native version appears to allocate
2016 * indices into a table)
2018 STREAM_HANDLE * pStream;
2021 TRACE( "(%s, %p, %p, %x, 0x%08lx)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2022 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2024 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2026 lpdwCacheEntryInfoBufferSize,
2032 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2037 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2039 if (hFile == INVALID_HANDLE_VALUE)
2042 /* allocate handle storage space */
2043 pStream = (STREAM_HANDLE *)HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2047 SetLastError(ERROR_OUTOFMEMORY);
2051 pStream->hFile = hFile;
2052 strcpy(pStream->lpszUrl, lpszUrlName);
2053 return (HANDLE)pStream;
2056 /***********************************************************************
2057 * RetrieveUrlCacheEntryStreamW (WININET.@)
2060 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2061 IN LPCWSTR lpszUrlName,
2062 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2063 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2064 IN BOOL fRandomRead,
2068 FIXME( "(%s, %p, %p, %x, 0x%08lx)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2069 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2073 /***********************************************************************
2074 * UnlockUrlCacheEntryStream (WININET.@)
2077 BOOL WINAPI UnlockUrlCacheEntryStream(
2078 IN HANDLE hUrlCacheStream,
2082 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2084 if (dwReserved != 0)
2086 ERR("dwReserved != 0\n");
2087 SetLastError(ERROR_INVALID_PARAMETER);
2091 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2093 SetLastError(ERROR_INVALID_HANDLE);
2097 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2100 /* close file handle */
2101 CloseHandle(pStream->hFile);
2103 /* free allocated space */
2104 HeapFree(GetProcessHeap(), 0, pStream);
2110 /***********************************************************************
2111 * DeleteUrlCacheEntryA (WININET.@)
2114 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2116 URLCACHECONTAINER * pContainer;
2117 LPURLCACHE_HEADER pHeader;
2118 CACHEFILE_ENTRY * pEntry;
2121 BYTE * AllocationTable;
2123 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2125 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
2128 if (!URLCacheContainer_OpenIndex(pContainer))
2131 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2134 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
2136 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2137 TRACE("entry %s not found!\n", lpszUrlName);
2138 SetLastError(ERROR_FILE_NOT_FOUND);
2142 AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
2144 /* update allocation table */
2145 dwStartBlock = ((DWORD)pEntry - (DWORD)pHeader) / BLOCKSIZE;
2146 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
2147 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
2149 URLCache_DeleteEntry(pEntry);
2151 URLCache_DeleteEntryFromHash(pHeader, lpszUrlName);
2153 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2158 /***********************************************************************
2159 * DeleteUrlCacheEntryW (WININET.@)
2162 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2164 FIXME("(%s) stub\n", debugstr_w(lpszUrlName));
2168 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2170 FIXME("(0x%08lx, 0x%08lx) stub\n", d1, d2);
2174 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2176 FIXME("(0x%08lx, 0x%08lx) stub\n", d1, d2);
2180 /***********************************************************************
2181 * CreateCacheContainerA (WININET.@)
2183 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2184 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2186 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) stub\n",
2187 d1, d2, d3, d4, d5, d6, d7, d8);
2191 /***********************************************************************
2192 * CreateCacheContainerW (WININET.@)
2194 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2195 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2197 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) stub\n",
2198 d1, d2, d3, d4, d5, d6, d7, d8);
2202 /***********************************************************************
2203 * FindCloseUrlCache (WININET.@)
2205 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
2207 FIXME("(%p) stub\n", hEnumHandle);
2211 /***********************************************************************
2212 * FindFirstUrlCacheContainerA (WININET.@)
2214 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2216 FIXME("(%p, %p, %p, 0x%08lx) stub\n", p1, p2, p3, d1 );
2220 /***********************************************************************
2221 * FindFirstUrlCacheContainerW (WININET.@)
2223 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2225 FIXME("(%p, %p, %p, 0x%08lx) stub\n", p1, p2, p3, d1 );
2229 /***********************************************************************
2230 * FindNextUrlCacheContainerA (WININET.@)
2232 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
2234 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2238 /***********************************************************************
2239 * FindNextUrlCacheContainerW (WININET.@)
2241 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
2243 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2247 HANDLE WINAPI FindFirstUrlCacheEntryExA(
2248 LPCSTR lpszUrlSearchPattern,
2252 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2253 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2255 LPDWORD pcbReserved2,
2259 FIXME("(%s, 0x%08lx, 0x%08lx, 0x%08lx%08lx, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
2260 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2261 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2262 SetLastError(ERROR_FILE_NOT_FOUND);
2266 HANDLE WINAPI FindFirstUrlCacheEntryExW(
2267 LPCWSTR lpszUrlSearchPattern,
2271 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2272 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2274 LPDWORD pcbReserved2,
2278 FIXME("(%s, 0x%08lx, 0x%08lx, 0x%08lx%08lx, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
2279 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2280 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2281 SetLastError(ERROR_FILE_NOT_FOUND);
2285 /***********************************************************************
2286 * FindFirstUrlCacheEntryA (WININET.@)
2289 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
2290 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2292 FIXME("(%s, %p, %p): stub\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2293 SetLastError(ERROR_FILE_NOT_FOUND);
2297 /***********************************************************************
2298 * FindFirstUrlCacheEntryW (WININET.@)
2301 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
2302 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2304 FIXME("(%s, %p, %p): stub\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2308 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
2309 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
2311 FIXME("(0x%08lx, 0x%08lx, %p, 0x%08lx, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
2312 dwSearchCondition, lpGroupId, lpReserved);
2316 BOOL WINAPI FindNextUrlCacheEntryA(
2318 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
2319 LPDWORD lpdwNextCacheEntryInfoBufferSize
2322 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2326 BOOL WINAPI FindNextUrlCacheEntryW(
2328 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
2329 LPDWORD lpdwNextCacheEntryInfoBufferSize
2332 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2336 BOOL WINAPI FindNextUrlCacheEntryExA(
2338 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2339 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2341 LPDWORD pcbReserved2,
2345 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2346 lpReserved, pcbReserved2, lpReserved3);
2350 BOOL WINAPI FindNextUrlCacheEntryExW(
2352 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2353 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2355 LPDWORD pcbReserved2,
2359 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2360 lpReserved, pcbReserved2, lpReserved3);
2364 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
2366 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
2370 /***********************************************************************
2371 * CreateUrlCacheGroup (WININET.@)
2374 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
2376 FIXME("(0x%08lx, %p): stub\n", dwFlags, lpReserved);
2380 /***********************************************************************
2381 * DeleteUrlCacheGroup (WININET.@)
2384 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
2386 FIXME("(0x%08lx%08lx, 0x%08lx, %p) stub\n",
2387 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
2391 /***********************************************************************
2392 * SetUrlCacheEntryGroupA (WININET.@)
2395 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
2396 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2399 FIXME("(%s, 0x%08lx, 0x%08lx%08lx, %p, 0x%08lx, %p) stub\n",
2400 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2401 pbGroupAttributes, cbGroupAttributes, lpReserved);
2402 SetLastError(ERROR_FILE_NOT_FOUND);
2406 /***********************************************************************
2407 * SetUrlCacheEntryGroupW (WININET.@)
2410 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
2411 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2414 FIXME("(%s, 0x%08lx, 0x%08lx%08lx, %p, 0x%08lx, %p) stub\n",
2415 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2416 pbGroupAttributes, cbGroupAttributes, lpReserved);
2417 SetLastError(ERROR_FILE_NOT_FOUND);
2421 /***********************************************************************
2422 * GetUrlCacheConfigInfoW (WININET.@)
2424 BOOL WINAPI GetUrlCacheConfigInfoW(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2426 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2427 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2431 /***********************************************************************
2432 * GetUrlCacheConfigInfoA (WININET.@)
2434 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
2436 BOOL WINAPI GetUrlCacheConfigInfoA(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2438 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2439 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2443 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2444 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
2445 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2447 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p, %p) stub\n",
2448 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2449 lpdwGroupInfo, lpReserved);
2453 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2454 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
2455 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2457 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p, %p) stub\n",
2458 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2459 lpdwGroupInfo, lpReserved);
2463 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2464 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
2466 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p) stub\n",
2467 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2471 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2472 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
2474 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p) stub\n",
2475 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2479 BOOL WINAPI SetUrlCacheConfigInfoA( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2481 FIXME("(%p, 0x%08lx) stub\n", lpCacheConfigInfo, dwFieldControl);
2485 BOOL WINAPI SetUrlCacheConfigInfoW( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2487 FIXME("(%p, 0x%08lx) stub\n", lpCacheConfigInfo, dwFieldControl);
2491 /***********************************************************************
2492 * DeleteIE3Cache (WININET.@)
2494 * Deletes the files used by the IE3 URL caching system.
2497 * hWnd [I] A dummy window.
2498 * hInst [I] Instance of process calling the function.
2499 * lpszCmdLine [I] Options used by function.
2500 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
2505 void WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
2507 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);