push 48260896d780205bc35dd82f8382d75decb9f038
[wine/hacks.git] / dlls / wininet / urlcache.c
blob37d7b259fd62cda6a5cb2864514021f13976cbe7
1 /*
2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003-2008 Robert Shearman
7 * Eric Kohl
8 * Aric Stewart
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
26 #include "wine/port.h"
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
31 #if defined(__MINGW32__) || defined (_MSC_VER)
32 #include <ws2tcpip.h>
33 #endif
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
42 #endif
43 #include <time.h>
45 #include "windef.h"
46 #include "winbase.h"
47 #include "winuser.h"
48 #include "wininet.h"
49 #include "winineti.h"
50 #include "winerror.h"
51 #include "internet.h"
52 #include "winreg.h"
53 #include "shlwapi.h"
54 #include "shlobj.h"
56 #include "wine/unicode.h"
57 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
61 #define ENTRY_START_OFFSET 0x4000
62 #define DIR_LENGTH 8
63 #define BLOCKSIZE 128
64 #define HASHTABLE_SIZE 448
65 #define HASHTABLE_BLOCKSIZE 7
66 #define HASHTABLE_FREE 3
67 #define ALLOCATION_TABLE_OFFSET 0x250
68 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
69 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
70 #define NEWFILE_NUM_BLOCKS 0xd80
71 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
73 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
74 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
75 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
76 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
77 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
79 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
81 typedef struct _CACHEFILE_ENTRY
83 /* union
84 {*/
85 DWORD dwSignature; /* e.g. "URL " */
86 /* CHAR szSignature[4];
87 };*/
88 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
89 } CACHEFILE_ENTRY;
91 typedef struct _URL_CACHEFILE_ENTRY
93 CACHEFILE_ENTRY CacheFileEntry;
94 FILETIME LastModifiedTime;
95 FILETIME LastAccessTime;
96 WORD wExpiredDate; /* expire date in dos format */
97 WORD wExpiredTime; /* expire time in dos format */
98 DWORD dwUnknown1; /* usually zero */
99 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
100 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
101 DWORD dwUnknown2; /* usually zero */
102 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
103 DWORD dwUnknown3; /* usually 0x60 */
104 DWORD dwOffsetUrl; /* offset of start of url from start of entry */
105 BYTE CacheDir; /* index of cache directory this url is stored in */
106 BYTE Unknown4; /* usually zero */
107 WORD wUnknown5; /* usually 0x1010 */
108 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
109 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
110 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
111 DWORD dwHeaderInfoSize;
112 DWORD dwOffsetFileExtension; /* offset of start of file extension from start of entry */
113 WORD wLastSyncDate; /* last sync date in dos format */
114 WORD wLastSyncTime; /* last sync time in dos format */
115 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
116 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
117 WORD wUnknownDate; /* usually same as wLastSyncDate */
118 WORD wUnknownTime; /* usually same as wLastSyncTime */
119 DWORD dwUnknown7; /* usually zero */
120 DWORD dwUnknown8; /* usually zero */
121 /* packing to dword align start of next field */
122 /* CHAR szSourceUrlName[]; (url) */
123 /* packing to dword align start of next field */
124 /* CHAR szLocalFileName[]; (local file name excluding path) */
125 /* packing to dword align start of next field */
126 /* CHAR szHeaderInfo[]; (header info) */
127 } URL_CACHEFILE_ENTRY;
129 struct _HASH_ENTRY
131 DWORD dwHashKey;
132 DWORD dwOffsetEntry;
135 typedef struct _HASH_CACHEFILE_ENTRY
137 CACHEFILE_ENTRY CacheFileEntry;
138 DWORD dwAddressNext;
139 DWORD dwHashTableNumber;
140 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
141 } HASH_CACHEFILE_ENTRY;
143 typedef struct _DIRECTORY_DATA
145 DWORD dwUnknown;
146 char filename[DIR_LENGTH];
147 } DIRECTORY_DATA;
149 typedef struct _URLCACHE_HEADER
151 char szSignature[28];
152 DWORD dwFileSize;
153 DWORD dwOffsetFirstHashTable;
154 DWORD dwIndexCapacityInBlocks;
155 DWORD dwBlocksInUse;
156 DWORD dwUnknown1;
157 DWORD dwCacheLimitLow; /* disk space limit for cache */
158 DWORD dwCacheLimitHigh; /* disk space limit for cache */
159 DWORD dwUnknown4; /* current disk space usage for cache */
160 DWORD dwUnknown5; /* current disk space usage for cache */
161 DWORD dwUnknown6; /* possibly a flag? */
162 DWORD dwUnknown7;
163 BYTE DirectoryCount; /* number of directory_data's */
164 BYTE Unknown8[3]; /* just padding? */
165 DIRECTORY_DATA directory_data[1]; /* first directory entry */
166 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
167 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
169 typedef struct _STREAM_HANDLE
171 HANDLE hFile;
172 CHAR lpszUrl[1];
173 } STREAM_HANDLE;
175 typedef struct _URLCACHECONTAINER
177 struct list entry; /* part of a list */
178 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
179 LPWSTR path; /* path to url container directory */
180 HANDLE hMapping; /* handle of file mapping */
181 DWORD file_size; /* size of file when mapping was opened */
182 HANDLE hMutex; /* handle of mutex */
183 } URLCACHECONTAINER;
186 /* List of all containers available */
187 static struct list UrlContainers = LIST_INIT(UrlContainers);
189 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash);
191 /***********************************************************************
192 * URLCache_PathToObjectName (Internal)
194 * Converts a path to a name suitable for use as a Win32 object name.
195 * Replaces '\\' characters in-place with the specified character
196 * (usually '_' or '!')
198 * RETURNS
199 * nothing
202 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
204 for (; *lpszPath; lpszPath++)
206 if (*lpszPath == '\\')
207 *lpszPath = replace;
211 /***********************************************************************
212 * URLCacheContainer_OpenIndex (Internal)
214 * Opens the index file and saves mapping handle in hCacheIndexMapping
216 * RETURNS
217 * ERROR_SUCCESS if succeeded
218 * Any other Win32 error code if failed
221 static DWORD URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
223 HANDLE hFile;
224 WCHAR wszFilePath[MAX_PATH];
225 DWORD dwFileSize;
227 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
228 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
230 if (pContainer->hMapping)
231 return ERROR_SUCCESS;
233 strcpyW(wszFilePath, pContainer->path);
234 strcatW(wszFilePath, wszIndex);
236 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
237 if (hFile == INVALID_HANDLE_VALUE)
239 /* Maybe the directory wasn't there? Try to create it */
240 if (CreateDirectoryW(pContainer->path, 0))
241 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
243 if (hFile == INVALID_HANDLE_VALUE)
245 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath));
246 return GetLastError();
249 /* At this stage we need the mutex because we may be about to create the
250 * file.
252 WaitForSingleObject(pContainer->hMutex, INFINITE);
254 dwFileSize = GetFileSize(hFile, NULL);
255 if (dwFileSize == INVALID_FILE_SIZE)
257 ReleaseMutex(pContainer->hMutex);
258 return GetLastError();
261 if (dwFileSize == 0)
263 static const CHAR szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content";
264 HKEY key;
265 char achZeroes[0x1000];
266 DWORD dwOffset;
267 DWORD dwError = ERROR_SUCCESS;
269 /* Write zeroes to the entire file so we can safely map it without
270 * fear of getting a SEGV because the disk is full.
272 memset(achZeroes, 0, sizeof(achZeroes));
273 for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes))
275 DWORD dwWrite = sizeof(achZeroes);
276 DWORD dwWritten;
278 if (NEWFILE_SIZE - dwOffset < dwWrite)
279 dwWrite = NEWFILE_SIZE - dwOffset;
280 if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) ||
281 dwWritten != dwWrite)
283 /* If we fail to write, we need to return the error that
284 * cause the problem and also make sure the file is no
285 * longer there, if possible.
287 dwError = GetLastError();
289 break;
293 if (dwError == ERROR_SUCCESS)
295 HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL);
297 if (hMapping)
299 URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE);
301 if (pHeader)
303 WCHAR *pwchDir;
304 WCHAR wszDirPath[MAX_PATH];
305 FILETIME ft;
306 int i, j;
307 HASH_CACHEFILE_ENTRY *pHashEntry;
309 dwFileSize = NEWFILE_SIZE;
311 /* First set some constants and defaults in the header */
312 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
313 pHeader->dwFileSize = dwFileSize;
314 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
315 /* 127MB - taken from default for Windows 2000 */
316 pHeader->dwCacheLimitHigh = 0;
317 pHeader->dwCacheLimitLow = 0x07ff5400;
318 /* Copied from a Windows 2000 cache index */
319 pHeader->DirectoryCount = 4;
321 /* If the registry has a cache size set, use the registry value */
322 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
324 DWORD dw;
325 DWORD len = sizeof(dw);
326 DWORD keytype;
328 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
329 (BYTE *) &dw, &len) == ERROR_SUCCESS &&
330 keytype == REG_DWORD)
332 pHeader->dwCacheLimitHigh = (dw >> 22);
333 pHeader->dwCacheLimitLow = dw << 10;
335 RegCloseKey(key);
338 URLCache_CreateHashTable(pHeader, NULL, &pHashEntry);
340 /* Last step - create the directories */
342 strcpyW(wszDirPath, pContainer->path);
343 pwchDir = wszDirPath + strlenW(wszDirPath);
344 pwchDir[8] = 0;
346 GetSystemTimeAsFileTime(&ft);
348 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
350 /* The following values were copied from a Windows index.
351 * I don't know what the values are supposed to mean but
352 * have made them the same in the hope that this will
353 * be better for compatibility
355 pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
356 for (j = 0;; ++j)
358 int k;
359 ULONGLONG n = ft.dwHighDateTime;
361 /* Generate a file name to attempt to create.
362 * This algorithm will create what will appear
363 * to be random and unrelated directory names
364 * of up to 9 characters in length.
366 n <<= 32;
367 n += ft.dwLowDateTime;
368 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
370 for (k = 0; k < 8; ++k)
372 int r = (n % 36);
374 /* Dividing by a prime greater than 36 helps
375 * with the appearance of randomness
377 n /= 37;
379 if (r < 10)
380 pwchDir[k] = '0' + r;
381 else
382 pwchDir[k] = 'A' + (r - 10);
385 if (CreateDirectoryW(wszDirPath, 0))
387 /* The following is OK because we generated an
388 * 8 character directory name made from characters
389 * [A-Z0-9], which are equivalent for all code
390 * pages and for UTF-16
392 for (k = 0; k < 8; ++k)
393 pHeader->directory_data[i].filename[k] = pwchDir[k];
394 break;
396 else if (j >= 255)
398 /* Give up. The most likely cause of this
399 * is a full disk, but whatever the cause
400 * is, it should be more than apparent that
401 * we won't succeed.
403 dwError = GetLastError();
404 break;
409 UnmapViewOfFile(pHeader);
411 else
413 dwError = GetLastError();
415 CloseHandle(hMapping);
417 else
419 dwError = GetLastError();
423 if (dwError)
425 CloseHandle(hFile);
426 DeleteFileW(wszFilePath);
427 ReleaseMutex(pContainer->hMutex);
428 return dwError;
433 ReleaseMutex(pContainer->hMutex);
435 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
436 URLCache_PathToObjectName(wszFilePath, '_');
437 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
438 if (!pContainer->hMapping)
439 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
440 CloseHandle(hFile);
441 if (!pContainer->hMapping)
443 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
444 return GetLastError();
447 return ERROR_SUCCESS;
450 /***********************************************************************
451 * URLCacheContainer_CloseIndex (Internal)
453 * Closes the index
455 * RETURNS
456 * nothing
459 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
461 CloseHandle(pContainer->hMapping);
462 pContainer->hMapping = NULL;
465 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
467 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
468 int cache_prefix_len = strlenW(cache_prefix);
470 if (!pContainer)
472 return FALSE;
475 pContainer->hMapping = NULL;
476 pContainer->file_size = 0;
478 pContainer->path = heap_strdupW(path);
479 if (!pContainer->path)
481 HeapFree(GetProcessHeap(), 0, pContainer);
482 return FALSE;
485 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
486 if (!pContainer->cache_prefix)
488 HeapFree(GetProcessHeap(), 0, pContainer->path);
489 HeapFree(GetProcessHeap(), 0, pContainer);
490 return FALSE;
493 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
495 CharLowerW(mutex_name);
496 URLCache_PathToObjectName(mutex_name, '!');
498 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
500 ERR("couldn't create mutex (error is %d)\n", GetLastError());
501 HeapFree(GetProcessHeap(), 0, pContainer->path);
502 HeapFree(GetProcessHeap(), 0, pContainer);
503 return FALSE;
506 list_add_head(&UrlContainers, &pContainer->entry);
508 return TRUE;
511 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
513 list_remove(&pContainer->entry);
515 URLCacheContainer_CloseIndex(pContainer);
516 CloseHandle(pContainer->hMutex);
517 HeapFree(GetProcessHeap(), 0, pContainer->path);
518 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
519 HeapFree(GetProcessHeap(), 0, pContainer);
522 void URLCacheContainers_CreateDefaults(void)
524 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
525 static const WCHAR UrlPrefix[] = {0};
526 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
527 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
528 static const WCHAR CookieSuffix[] = {0};
529 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
530 static const struct
532 int nFolder; /* CSIDL_* constant */
533 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
534 const WCHAR * cache_prefix; /* prefix used to reference the container */
535 } DefaultContainerData[] =
537 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
538 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
539 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
541 DWORD i;
543 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
545 WCHAR wszCachePath[MAX_PATH];
546 WCHAR wszMutexName[MAX_PATH];
547 int path_len, suffix_len;
549 if (!SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE))
551 ERR("Couldn't get path for default container %u\n", i);
552 continue;
554 path_len = strlenW(wszCachePath);
555 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
557 if (path_len + suffix_len + 2 > MAX_PATH)
559 ERR("Path too long\n");
560 continue;
563 wszCachePath[path_len] = '\\';
564 wszCachePath[path_len+1] = 0;
566 strcpyW(wszMutexName, wszCachePath);
568 if (suffix_len)
570 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
571 wszCachePath[path_len + suffix_len + 1] = '\\';
572 wszCachePath[path_len + suffix_len + 2] = '\0';
575 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
579 void URLCacheContainers_DeleteAll(void)
581 while(!list_empty(&UrlContainers))
582 URLCacheContainer_DeleteContainer(
583 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
587 static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
589 URLCACHECONTAINER * pContainer;
591 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
593 if(!lpwszUrl)
594 return ERROR_INVALID_PARAMETER;
596 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
598 int prefix_len = strlenW(pContainer->cache_prefix);
599 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
601 TRACE("found container with prefix %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
602 *ppContainer = pContainer;
603 return ERROR_SUCCESS;
606 ERR("no container found\n");
607 return ERROR_FILE_NOT_FOUND;
610 static DWORD URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
612 LPWSTR url = NULL;
613 DWORD ret;
615 if (lpszUrl && !(url = heap_strdupAtoW(lpszUrl)))
616 return ERROR_OUTOFMEMORY;
618 ret = URLCacheContainers_FindContainerW(url, ppContainer);
619 HeapFree(GetProcessHeap(), 0, url);
620 return ret;
623 static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, URLCACHECONTAINER ** ppContainer)
625 DWORD i = 0;
626 URLCACHECONTAINER * pContainer;
628 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern));
630 /* non-NULL search pattern only returns one container ever */
631 if (lpwszSearchPattern && dwIndex > 0)
632 return FALSE;
634 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry)
636 if (lpwszSearchPattern)
638 if (!strcmpW(pContainer->cache_prefix, lpwszSearchPattern))
640 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
641 *ppContainer = pContainer;
642 return TRUE;
645 else
647 if (i == dwIndex)
649 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix));
650 *ppContainer = pContainer;
651 return TRUE;
654 i++;
656 return FALSE;
659 /***********************************************************************
660 * URLCacheContainer_LockIndex (Internal)
662 * Locks the index for system-wide exclusive access.
664 * RETURNS
665 * Cache file header if successful
666 * NULL if failed and calls SetLastError.
668 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
670 BYTE index;
671 LPVOID pIndexData;
672 URLCACHE_HEADER * pHeader;
673 DWORD error;
675 /* acquire mutex */
676 WaitForSingleObject(pContainer->hMutex, INFINITE);
678 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
680 if (!pIndexData)
682 ReleaseMutex(pContainer->hMutex);
683 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
684 return NULL;
686 pHeader = (URLCACHE_HEADER *)pIndexData;
688 /* file has grown - we need to remap to prevent us getting
689 * access violations when we try and access beyond the end
690 * of the memory mapped file */
691 if (pHeader->dwFileSize != pContainer->file_size)
693 UnmapViewOfFile( pHeader );
694 URLCacheContainer_CloseIndex(pContainer);
695 error = URLCacheContainer_OpenIndex(pContainer);
696 if (error != ERROR_SUCCESS)
698 ReleaseMutex(pContainer->hMutex);
699 SetLastError(error);
700 return NULL;
702 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
704 if (!pIndexData)
706 ReleaseMutex(pContainer->hMutex);
707 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
708 return NULL;
710 pHeader = (URLCACHE_HEADER *)pIndexData;
713 TRACE("Signature: %s, file size: %d bytes\n", pHeader->szSignature, pHeader->dwFileSize);
715 for (index = 0; index < pHeader->DirectoryCount; index++)
717 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
720 return pHeader;
723 /***********************************************************************
724 * URLCacheContainer_UnlockIndex (Internal)
727 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
729 /* release mutex */
730 ReleaseMutex(pContainer->hMutex);
731 return UnmapViewOfFile(pHeader);
735 #ifndef CHAR_BIT
736 #define CHAR_BIT (8 * sizeof(CHAR))
737 #endif
739 /***********************************************************************
740 * URLCache_Allocation_BlockIsFree (Internal)
742 * Is the specified block number free?
744 * RETURNS
745 * zero if free
746 * non-zero otherwise
749 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
751 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
752 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
755 /***********************************************************************
756 * URLCache_Allocation_BlockFree (Internal)
758 * Marks the specified block as free
760 * RETURNS
761 * nothing
764 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
766 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
767 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
770 /***********************************************************************
771 * URLCache_Allocation_BlockAllocate (Internal)
773 * Marks the specified block as allocated
775 * RETURNS
776 * nothing
779 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
781 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
782 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
785 /***********************************************************************
786 * URLCache_FindFirstFreeEntry (Internal)
788 * Finds and allocates the first block of free space big enough and
789 * sets ppEntry to point to it.
791 * RETURNS
792 * TRUE if it had enough space
793 * FALSE if it couldn't find enough space
796 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
798 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
799 DWORD dwBlockNumber;
800 DWORD dwFreeCounter;
801 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
803 for (dwFreeCounter = 0;
804 dwFreeCounter < dwBlocksNeeded &&
805 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
806 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
807 dwFreeCounter++)
808 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
810 if (dwFreeCounter == dwBlocksNeeded)
812 DWORD index;
813 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
814 for (index = 0; index < dwBlocksNeeded; index++)
815 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
816 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
817 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
818 return TRUE;
821 FIXME("Grow file\n");
822 return FALSE;
825 /***********************************************************************
826 * URLCache_DeleteEntry (Internal)
828 * Deletes the specified entry and frees the space allocated to it
830 * RETURNS
831 * TRUE if it succeeded
832 * FALSE if it failed
835 static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, CACHEFILE_ENTRY * pEntry)
837 DWORD dwStartBlock;
838 DWORD dwBlock;
839 BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
841 /* update allocation table */
842 dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE;
843 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
844 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
846 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
847 return TRUE;
850 /***********************************************************************
851 * URLCache_LocalFileNameToPathW (Internal)
853 * Copies the full path to the specified buffer given the local file
854 * name and the index of the directory it is in. Always sets value in
855 * lpBufferSize to the required buffer size (in bytes).
857 * RETURNS
858 * TRUE if the buffer was big enough
859 * FALSE if the buffer was too small
862 static BOOL URLCache_LocalFileNameToPathW(
863 const URLCACHECONTAINER * pContainer,
864 LPCURLCACHE_HEADER pHeader,
865 LPCSTR szLocalFileName,
866 BYTE Directory,
867 LPWSTR wszPath,
868 LPLONG lpBufferSize)
870 LONG nRequired;
871 int path_len = strlenW(pContainer->path);
872 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
873 if (Directory >= pHeader->DirectoryCount)
875 *lpBufferSize = 0;
876 return FALSE;
879 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
880 if (nRequired < *lpBufferSize)
882 int dir_len;
884 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
885 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
886 wszPath[dir_len + path_len] = '\\';
887 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
888 *lpBufferSize = nRequired;
889 return TRUE;
891 *lpBufferSize = nRequired;
892 return FALSE;
895 /***********************************************************************
896 * URLCache_LocalFileNameToPathA (Internal)
898 * Copies the full path to the specified buffer given the local file
899 * name and the index of the directory it is in. Always sets value in
900 * lpBufferSize to the required buffer size.
902 * RETURNS
903 * TRUE if the buffer was big enough
904 * FALSE if the buffer was too small
907 static BOOL URLCache_LocalFileNameToPathA(
908 const URLCACHECONTAINER * pContainer,
909 LPCURLCACHE_HEADER pHeader,
910 LPCSTR szLocalFileName,
911 BYTE Directory,
912 LPSTR szPath,
913 LPLONG lpBufferSize)
915 LONG nRequired;
916 int path_len, file_name_len, dir_len;
918 if (Directory >= pHeader->DirectoryCount)
920 *lpBufferSize = 0;
921 return FALSE;
924 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL) - 1;
925 file_name_len = strlen(szLocalFileName) + 1 /* for nul-terminator */;
926 dir_len = DIR_LENGTH;
928 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(char);
929 if (nRequired < *lpBufferSize)
931 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, path_len, NULL, NULL);
932 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
933 szPath[path_len + dir_len] = '\\';
934 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
935 *lpBufferSize = nRequired;
936 return TRUE;
938 *lpBufferSize = nRequired;
939 return FALSE;
942 /***********************************************************************
943 * URLCache_CopyEntry (Internal)
945 * Copies an entry from the cache index file to the Win32 structure
947 * RETURNS
948 * ERROR_SUCCESS if the buffer was big enough
949 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
952 static DWORD URLCache_CopyEntry(
953 URLCACHECONTAINER * pContainer,
954 LPCURLCACHE_HEADER pHeader,
955 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
956 LPDWORD lpdwBufferSize,
957 const URL_CACHEFILE_ENTRY * pUrlEntry,
958 BOOL bUnicode)
960 int lenUrl;
961 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
963 if (*lpdwBufferSize >= dwRequiredSize)
965 lpCacheEntryInfo->lpHeaderInfo = NULL;
966 lpCacheEntryInfo->lpszFileExtension = NULL;
967 lpCacheEntryInfo->lpszLocalFileName = NULL;
968 lpCacheEntryInfo->lpszSourceUrlName = NULL;
969 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
970 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
971 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
972 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
973 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
974 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
975 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
976 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
977 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
978 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
979 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
980 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
981 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
982 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
985 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
986 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
987 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
988 if (bUnicode)
989 lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0);
990 else
991 lenUrl = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
992 dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
994 /* FIXME: is source url optional? */
995 if (*lpdwBufferSize >= dwRequiredSize)
997 DWORD lenUrlBytes = (lenUrl+1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
999 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrlBytes;
1000 if (bUnicode)
1001 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
1002 else
1003 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lenUrlBytes);
1006 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1007 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1008 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1010 if (pUrlEntry->dwOffsetLocalName)
1012 LONG nLocalFilePathSize;
1013 LPSTR lpszLocalFileName;
1014 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
1015 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
1016 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
1017 (!bUnicode && URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize)))
1019 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
1021 dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ;
1023 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1024 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1025 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1027 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
1029 if (*lpdwBufferSize >= dwRequiredSize)
1031 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
1032 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
1033 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
1035 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1036 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1037 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1039 if (pUrlEntry->dwOffsetFileExtension)
1041 int lenExtension;
1043 if (bUnicode)
1044 lenExtension = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, NULL, 0);
1045 else
1046 lenExtension = strlen((LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension) + 1;
1047 dwRequiredSize += lenExtension * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
1049 if (*lpdwBufferSize >= dwRequiredSize)
1051 lpCacheEntryInfo->lpszFileExtension = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenExtension;
1052 if (bUnicode)
1053 MultiByteToWideChar(CP_ACP, 0, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenExtension);
1054 else
1055 memcpy(lpCacheEntryInfo->lpszFileExtension, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, lenExtension * sizeof(CHAR));
1058 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1059 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1060 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1063 if (dwRequiredSize > *lpdwBufferSize)
1065 *lpdwBufferSize = dwRequiredSize;
1066 return ERROR_INSUFFICIENT_BUFFER;
1068 *lpdwBufferSize = dwRequiredSize;
1069 return ERROR_SUCCESS;
1073 /***********************************************************************
1074 * URLCache_SetEntryInfo (Internal)
1076 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1077 * according to the flags set by dwFieldControl.
1079 * RETURNS
1080 * ERROR_SUCCESS if the buffer was big enough
1081 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1084 static DWORD URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1086 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1087 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1088 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1089 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1090 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1091 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1092 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1093 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1094 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1095 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1096 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1097 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1098 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1099 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1100 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1101 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1103 return ERROR_SUCCESS;
1106 /***********************************************************************
1107 * URLCache_HashKey (Internal)
1109 * Returns the hash key for a given string
1111 * RETURNS
1112 * hash key for the string
1115 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1117 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1118 * but the algorithm and result are not the same!
1120 static const unsigned char lookupTable[256] =
1122 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1123 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1124 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1125 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1126 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1127 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1128 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1129 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1130 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1131 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1132 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1133 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1134 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1135 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1136 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1137 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1138 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1139 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1140 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1141 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1142 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1143 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1144 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1145 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1146 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1147 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1148 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1149 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1150 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1151 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1152 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1153 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1155 BYTE key[4];
1156 DWORD i;
1158 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1159 key[i] = lookupTable[i];
1161 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
1163 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1164 key[i] = lookupTable[*lpszKey ^ key[i]];
1167 return *(DWORD *)key;
1170 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
1172 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
1175 static inline BOOL URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY *pHashEntry)
1177 /* check pHashEntry located within acceptable bounds in the URL cache mapping */
1178 return ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) &&
1179 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1182 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1184 /* structure of hash table:
1185 * 448 entries divided into 64 blocks
1186 * each block therefore contains a chain of 7 key/offset pairs
1187 * how position in table is calculated:
1188 * 1. the url is hashed in helper function
1189 * 2. the key % 64 * 8 is the offset
1190 * 3. the key in the hash table is the hash key aligned to 64
1192 * note:
1193 * there can be multiple hash tables in the file and the offset to
1194 * the next one is stored in the header of the hash table
1196 DWORD key = URLCache_HashKey(lpszUrl);
1197 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1198 HASH_CACHEFILE_ENTRY * pHashEntry;
1199 DWORD dwHashTableNumber = 0;
1201 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1203 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1204 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1205 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1207 int i;
1208 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1210 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1211 continue;
1213 /* make sure that it is in fact a hash entry */
1214 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1216 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1217 continue;
1220 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1222 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1223 if (key == (pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
1225 /* FIXME: we should make sure that this is the right element
1226 * before returning and claiming that it is. We can do this
1227 * by doing a simple compare between the URL we were given
1228 * and the URL stored in the entry. However, this assumes
1229 * we know the format of all the entries stored in the
1230 * hash table */
1231 *ppHashEntry = pHashElement;
1232 return TRUE;
1236 return FALSE;
1239 static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1241 LPSTR urlA;
1242 BOOL ret;
1244 urlA = heap_strdupWtoA(lpszUrl);
1245 if (!urlA)
1247 SetLastError(ERROR_OUTOFMEMORY);
1248 return FALSE;
1251 ret = URLCache_FindHash(pHeader, urlA, ppHashEntry);
1252 HeapFree(GetProcessHeap(), 0, urlA);
1253 return ret;
1256 /***********************************************************************
1257 * URLCache_HashEntrySetUse (Internal)
1259 * Searches all the hash tables in the index for the given URL and
1260 * sets the use count (stored or'ed with key)
1262 * RETURNS
1263 * TRUE if the entry was found
1264 * FALSE if the entry could not be found
1267 static BOOL URLCache_HashEntrySetUse(struct _HASH_ENTRY * pHashEntry, DWORD dwUseCount)
1269 pHashEntry->dwHashKey = dwUseCount | (pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1270 return TRUE;
1273 /***********************************************************************
1274 * URLCache_DeleteEntryFromHash (Internal)
1276 * Searches all the hash tables in the index for the given URL and
1277 * then if found deletes the entry.
1279 * RETURNS
1280 * TRUE if the entry was found
1281 * FALSE if the entry could not be found
1284 static BOOL URLCache_DeleteEntryFromHash(struct _HASH_ENTRY * pHashEntry)
1286 pHashEntry->dwHashKey = HASHTABLE_FREE;
1287 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1288 return TRUE;
1291 /***********************************************************************
1292 * URLCache_AddEntryToHash (Internal)
1294 * Searches all the hash tables for a free slot based on the offset
1295 * generated from the hash key. If a free slot is found, the offset and
1296 * key are entered into the hash table.
1298 * RETURNS
1299 * ERROR_SUCCESS if the entry was added
1300 * Any other Win32 error code if the entry could not be added
1303 static DWORD URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1305 /* see URLCache_FindEntryInHash for structure of hash tables */
1307 DWORD key = URLCache_HashKey(lpszUrl);
1308 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1309 HASH_CACHEFILE_ENTRY * pHashEntry;
1310 DWORD dwHashTableNumber = 0;
1311 DWORD error;
1313 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1315 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1316 URLCache_IsHashEntryValid(pHeader, pHashEntry);
1317 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1319 int i;
1320 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1322 ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1323 break;
1325 /* make sure that it is in fact a hash entry */
1326 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1328 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1329 break;
1332 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1334 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1335 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1337 pHashElement->dwHashKey = key;
1338 pHashElement->dwOffsetEntry = dwOffsetEntry;
1339 return ERROR_SUCCESS;
1343 error = URLCache_CreateHashTable(pHeader, pHashEntry, &pHashEntry);
1344 if (error != ERROR_SUCCESS)
1345 return error;
1347 pHashEntry->HashTable[offset].dwHashKey = key;
1348 pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry;
1349 return ERROR_SUCCESS;
1352 /***********************************************************************
1353 * URLCache_CreateHashTable (Internal)
1355 * Creates a new hash table in free space and adds it to the chain of existing
1356 * hash tables.
1358 * RETURNS
1359 * ERROR_SUCCESS if the hash table was created
1360 * ERROR_DISK_FULL if the hash table could not be created
1363 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash)
1365 DWORD dwOffset;
1366 int i;
1368 if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)ppHash))
1370 FIXME("no free space for hash table\n");
1371 return ERROR_DISK_FULL;
1374 dwOffset = (BYTE *)*ppHash - (BYTE *)pHeader;
1376 if (pPrevHash)
1377 pPrevHash->dwAddressNext = dwOffset;
1378 else
1379 pHeader->dwOffsetFirstHashTable = dwOffset;
1380 (*ppHash)->CacheFileEntry.dwSignature = HASH_SIGNATURE;
1381 (*ppHash)->CacheFileEntry.dwBlocksUsed = 0x20;
1382 (*ppHash)->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0;
1383 for (i = 0; i < HASHTABLE_SIZE; i++)
1385 (*ppHash)->HashTable[i].dwOffsetEntry = 0;
1386 (*ppHash)->HashTable[i].dwHashKey = HASHTABLE_FREE;
1388 return ERROR_SUCCESS;
1391 /***********************************************************************
1392 * URLCache_EnumHashTables (Internal)
1394 * Enumerates the hash tables in a container.
1396 * RETURNS
1397 * TRUE if an entry was found
1398 * FALSE if there are no more tables to enumerate.
1401 static BOOL URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader, DWORD *pdwHashTableNumber, HASH_CACHEFILE_ENTRY ** ppHashEntry)
1403 for (*ppHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1404 URLCache_IsHashEntryValid(pHeader, *ppHashEntry);
1405 *ppHashEntry = URLCache_HashEntryFromOffset(pHeader, (*ppHashEntry)->dwAddressNext))
1407 TRACE("looking at hash table number %d\n", (*ppHashEntry)->dwHashTableNumber);
1408 if ((*ppHashEntry)->dwHashTableNumber != *pdwHashTableNumber)
1409 continue;
1410 /* make sure that it is in fact a hash entry */
1411 if ((*ppHashEntry)->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1413 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&(*ppHashEntry)->CacheFileEntry.dwSignature);
1414 (*pdwHashTableNumber)++;
1415 continue;
1418 TRACE("hash table number %d found\n", *pdwHashTableNumber);
1419 return TRUE;
1421 return FALSE;
1424 /***********************************************************************
1425 * URLCache_EnumHashTableEntries (Internal)
1427 * Enumerates entries in a hash table and returns the next non-free entry.
1429 * RETURNS
1430 * TRUE if an entry was found
1431 * FALSE if the hash table is empty or there are no more entries to
1432 * enumerate.
1435 static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY * pHashEntry,
1436 DWORD * index, const struct _HASH_ENTRY ** ppHashEntry)
1438 for (; *index < HASHTABLE_SIZE ; (*index)++)
1440 if (pHashEntry->HashTable[*index].dwHashKey == HASHTABLE_FREE)
1441 continue;
1443 *ppHashEntry = &pHashEntry->HashTable[*index];
1444 TRACE("entry found %d\n", *index);
1445 return TRUE;
1447 TRACE("no more entries (%d)\n", *index);
1448 return FALSE;
1451 /***********************************************************************
1452 * GetUrlCacheEntryInfoExA (WININET.@)
1455 BOOL WINAPI GetUrlCacheEntryInfoExA(
1456 LPCSTR lpszUrl,
1457 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1458 LPDWORD lpdwCacheEntryInfoBufSize,
1459 LPSTR lpszReserved,
1460 LPDWORD lpdwReserved,
1461 LPVOID lpReserved,
1462 DWORD dwFlags)
1464 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1465 debugstr_a(lpszUrl),
1466 lpCacheEntryInfo,
1467 lpdwCacheEntryInfoBufSize,
1468 lpszReserved,
1469 lpdwReserved,
1470 lpReserved,
1471 dwFlags);
1473 if ((lpszReserved != NULL) ||
1474 (lpdwReserved != NULL) ||
1475 (lpReserved != NULL))
1477 ERR("Reserved value was not 0\n");
1478 SetLastError(ERROR_INVALID_PARAMETER);
1479 return FALSE;
1481 if (dwFlags != 0)
1483 FIXME("Undocumented flag(s): %x\n", dwFlags);
1484 SetLastError(ERROR_FILE_NOT_FOUND);
1485 return FALSE;
1487 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1490 /***********************************************************************
1491 * GetUrlCacheEntryInfoA (WININET.@)
1494 BOOL WINAPI GetUrlCacheEntryInfoA(
1495 IN LPCSTR lpszUrlName,
1496 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1497 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1500 LPURLCACHE_HEADER pHeader;
1501 struct _HASH_ENTRY * pHashEntry;
1502 const CACHEFILE_ENTRY * pEntry;
1503 const URL_CACHEFILE_ENTRY * pUrlEntry;
1504 URLCACHECONTAINER * pContainer;
1505 DWORD error;
1507 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1509 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1510 if (error != ERROR_SUCCESS)
1512 SetLastError(error);
1513 return FALSE;
1516 error = URLCacheContainer_OpenIndex(pContainer);
1517 if (error != ERROR_SUCCESS)
1519 SetLastError(error);
1520 return FALSE;
1523 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1524 return FALSE;
1526 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1528 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1529 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1530 SetLastError(ERROR_FILE_NOT_FOUND);
1531 return FALSE;
1534 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1535 if (pEntry->dwSignature != URL_SIGNATURE)
1537 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1538 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1539 SetLastError(ERROR_FILE_NOT_FOUND);
1540 return FALSE;
1543 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1544 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1545 if (pUrlEntry->dwOffsetHeaderInfo)
1546 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1548 if (lpdwCacheEntryInfoBufferSize)
1550 if (!lpCacheEntryInfo)
1551 *lpdwCacheEntryInfoBufferSize = 0;
1553 error = URLCache_CopyEntry(
1554 pContainer,
1555 pHeader,
1556 lpCacheEntryInfo,
1557 lpdwCacheEntryInfoBufferSize,
1558 pUrlEntry,
1559 FALSE /* ANSI */);
1560 if (error != ERROR_SUCCESS)
1562 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1563 SetLastError(error);
1564 return FALSE;
1566 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1569 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1571 return TRUE;
1574 /***********************************************************************
1575 * GetUrlCacheEntryInfoW (WININET.@)
1578 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1579 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1580 LPDWORD lpdwCacheEntryInfoBufferSize)
1582 LPURLCACHE_HEADER pHeader;
1583 struct _HASH_ENTRY * pHashEntry;
1584 const CACHEFILE_ENTRY * pEntry;
1585 const URL_CACHEFILE_ENTRY * pUrlEntry;
1586 URLCACHECONTAINER * pContainer;
1587 DWORD error;
1589 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1591 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1592 if (error != ERROR_SUCCESS)
1594 SetLastError(error);
1595 return FALSE;
1598 error = URLCacheContainer_OpenIndex(pContainer);
1599 if (error != ERROR_SUCCESS)
1601 SetLastError(error);
1602 return FALSE;
1605 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1606 return FALSE;
1608 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1610 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1611 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1612 SetLastError(ERROR_FILE_NOT_FOUND);
1613 return FALSE;
1616 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1617 if (pEntry->dwSignature != URL_SIGNATURE)
1619 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1620 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1621 SetLastError(ERROR_FILE_NOT_FOUND);
1622 return FALSE;
1625 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1626 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1627 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1629 if (lpdwCacheEntryInfoBufferSize)
1631 if (!lpCacheEntryInfo)
1632 *lpdwCacheEntryInfoBufferSize = 0;
1634 error = URLCache_CopyEntry(
1635 pContainer,
1636 pHeader,
1637 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1638 lpdwCacheEntryInfoBufferSize,
1639 pUrlEntry,
1640 TRUE /* UNICODE */);
1641 if (error != ERROR_SUCCESS)
1643 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1644 SetLastError(error);
1645 return FALSE;
1647 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1650 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1652 return TRUE;
1655 /***********************************************************************
1656 * GetUrlCacheEntryInfoExW (WININET.@)
1659 BOOL WINAPI GetUrlCacheEntryInfoExW(
1660 LPCWSTR lpszUrl,
1661 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1662 LPDWORD lpdwCacheEntryInfoBufSize,
1663 LPWSTR lpszReserved,
1664 LPDWORD lpdwReserved,
1665 LPVOID lpReserved,
1666 DWORD dwFlags)
1668 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1669 debugstr_w(lpszUrl),
1670 lpCacheEntryInfo,
1671 lpdwCacheEntryInfoBufSize,
1672 lpszReserved,
1673 lpdwReserved,
1674 lpReserved,
1675 dwFlags);
1677 if ((lpszReserved != NULL) ||
1678 (lpdwReserved != NULL) ||
1679 (lpReserved != NULL))
1681 ERR("Reserved value was not 0\n");
1682 SetLastError(ERROR_INVALID_PARAMETER);
1683 return FALSE;
1685 if (dwFlags != 0)
1687 FIXME("Undocumented flag(s): %x\n", dwFlags);
1688 SetLastError(ERROR_FILE_NOT_FOUND);
1689 return FALSE;
1691 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1694 /***********************************************************************
1695 * SetUrlCacheEntryInfoA (WININET.@)
1697 BOOL WINAPI SetUrlCacheEntryInfoA(
1698 LPCSTR lpszUrlName,
1699 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1700 DWORD dwFieldControl)
1702 LPURLCACHE_HEADER pHeader;
1703 struct _HASH_ENTRY * pHashEntry;
1704 CACHEFILE_ENTRY * pEntry;
1705 URLCACHECONTAINER * pContainer;
1706 DWORD error;
1708 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1710 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1711 if (error != ERROR_SUCCESS)
1713 SetLastError(error);
1714 return FALSE;
1717 error = URLCacheContainer_OpenIndex(pContainer);
1718 if (error != ERROR_SUCCESS)
1720 SetLastError(error);
1721 return FALSE;
1724 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1725 return FALSE;
1727 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1729 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1730 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1731 SetLastError(ERROR_FILE_NOT_FOUND);
1732 return FALSE;
1735 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1736 if (pEntry->dwSignature != URL_SIGNATURE)
1738 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1739 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1740 SetLastError(ERROR_FILE_NOT_FOUND);
1741 return FALSE;
1744 URLCache_SetEntryInfo(
1745 (URL_CACHEFILE_ENTRY *)pEntry,
1746 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1747 dwFieldControl);
1749 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1751 return TRUE;
1754 /***********************************************************************
1755 * SetUrlCacheEntryInfoW (WININET.@)
1757 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1759 LPURLCACHE_HEADER pHeader;
1760 struct _HASH_ENTRY * pHashEntry;
1761 CACHEFILE_ENTRY * pEntry;
1762 URLCACHECONTAINER * pContainer;
1763 DWORD error;
1765 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1767 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1768 if (error != ERROR_SUCCESS)
1770 SetLastError(error);
1771 return FALSE;
1774 error = URLCacheContainer_OpenIndex(pContainer);
1775 if (error != ERROR_SUCCESS)
1777 SetLastError(error);
1778 return FALSE;
1781 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1782 return FALSE;
1784 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1786 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1787 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1788 SetLastError(ERROR_FILE_NOT_FOUND);
1789 return FALSE;
1792 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1793 if (pEntry->dwSignature != URL_SIGNATURE)
1795 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1796 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1797 SetLastError(ERROR_FILE_NOT_FOUND);
1798 return FALSE;
1801 URLCache_SetEntryInfo(
1802 (URL_CACHEFILE_ENTRY *)pEntry,
1803 lpCacheEntryInfo,
1804 dwFieldControl);
1806 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1808 return TRUE;
1811 /***********************************************************************
1812 * RetrieveUrlCacheEntryFileA (WININET.@)
1815 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1816 IN LPCSTR lpszUrlName,
1817 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1818 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1819 IN DWORD dwReserved
1822 LPURLCACHE_HEADER pHeader;
1823 struct _HASH_ENTRY * pHashEntry;
1824 CACHEFILE_ENTRY * pEntry;
1825 URL_CACHEFILE_ENTRY * pUrlEntry;
1826 URLCACHECONTAINER * pContainer;
1827 DWORD error;
1829 TRACE("(%s, %p, %p, 0x%08x)\n",
1830 debugstr_a(lpszUrlName),
1831 lpCacheEntryInfo,
1832 lpdwCacheEntryInfoBufferSize,
1833 dwReserved);
1835 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1836 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1838 SetLastError(ERROR_INVALID_PARAMETER);
1839 return FALSE;
1842 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1843 if (error != ERROR_SUCCESS)
1845 SetLastError(error);
1846 return FALSE;
1849 error = URLCacheContainer_OpenIndex(pContainer);
1850 if (error != ERROR_SUCCESS)
1852 SetLastError(error);
1853 return FALSE;
1856 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1857 return FALSE;
1859 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1861 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1862 TRACE("entry %s not found!\n", lpszUrlName);
1863 SetLastError(ERROR_FILE_NOT_FOUND);
1864 return FALSE;
1867 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1868 if (pEntry->dwSignature != URL_SIGNATURE)
1870 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1871 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1872 SetLastError(ERROR_FILE_NOT_FOUND);
1873 return FALSE;
1876 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1877 if (!pUrlEntry->dwOffsetLocalName)
1879 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1880 SetLastError(ERROR_INVALID_DATA);
1881 return FALSE;
1884 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1885 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1887 pUrlEntry->dwHitRate++;
1888 pUrlEntry->dwUseCount++;
1889 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1891 error = URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo,
1892 lpdwCacheEntryInfoBufferSize, pUrlEntry,
1893 FALSE);
1894 if (error != ERROR_SUCCESS)
1896 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1897 SetLastError(error);
1898 return FALSE;
1900 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1902 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1904 return TRUE;
1907 /***********************************************************************
1908 * RetrieveUrlCacheEntryFileW (WININET.@)
1911 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1912 IN LPCWSTR lpszUrlName,
1913 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1914 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1915 IN DWORD dwReserved
1918 LPURLCACHE_HEADER pHeader;
1919 struct _HASH_ENTRY * pHashEntry;
1920 CACHEFILE_ENTRY * pEntry;
1921 URL_CACHEFILE_ENTRY * pUrlEntry;
1922 URLCACHECONTAINER * pContainer;
1923 DWORD error;
1925 TRACE("(%s, %p, %p, 0x%08x)\n",
1926 debugstr_w(lpszUrlName),
1927 lpCacheEntryInfo,
1928 lpdwCacheEntryInfoBufferSize,
1929 dwReserved);
1931 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1932 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1934 SetLastError(ERROR_INVALID_PARAMETER);
1935 return FALSE;
1938 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
1939 if (error != ERROR_SUCCESS)
1941 SetLastError(error);
1942 return FALSE;
1945 error = URLCacheContainer_OpenIndex(pContainer);
1946 if (error != ERROR_SUCCESS)
1948 SetLastError(error);
1949 return FALSE;
1952 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1953 return FALSE;
1955 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1957 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1958 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1959 SetLastError(ERROR_FILE_NOT_FOUND);
1960 return FALSE;
1963 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1964 if (pEntry->dwSignature != URL_SIGNATURE)
1966 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1967 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1968 SetLastError(ERROR_FILE_NOT_FOUND);
1969 return FALSE;
1972 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1973 if (!pUrlEntry->dwOffsetLocalName)
1975 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1976 SetLastError(ERROR_INVALID_DATA);
1977 return FALSE;
1980 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1981 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1983 pUrlEntry->dwHitRate++;
1984 pUrlEntry->dwUseCount++;
1985 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1987 error = URLCache_CopyEntry(
1988 pContainer,
1989 pHeader,
1990 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1991 lpdwCacheEntryInfoBufferSize,
1992 pUrlEntry,
1993 TRUE /* UNICODE */);
1994 if (error != ERROR_SUCCESS)
1996 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1997 SetLastError(error);
1998 return FALSE;
2000 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
2002 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2004 return TRUE;
2007 /***********************************************************************
2008 * UnlockUrlCacheEntryFileA (WININET.@)
2011 BOOL WINAPI UnlockUrlCacheEntryFileA(
2012 IN LPCSTR lpszUrlName,
2013 IN DWORD dwReserved
2016 LPURLCACHE_HEADER pHeader;
2017 struct _HASH_ENTRY * pHashEntry;
2018 CACHEFILE_ENTRY * pEntry;
2019 URL_CACHEFILE_ENTRY * pUrlEntry;
2020 URLCACHECONTAINER * pContainer;
2021 DWORD error;
2023 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
2025 if (dwReserved)
2027 ERR("dwReserved != 0\n");
2028 SetLastError(ERROR_INVALID_PARAMETER);
2029 return FALSE;
2032 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2033 if (error != ERROR_SUCCESS)
2035 SetLastError(error);
2036 return FALSE;
2039 error = URLCacheContainer_OpenIndex(pContainer);
2040 if (error != ERROR_SUCCESS)
2042 SetLastError(error);
2043 return FALSE;
2046 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2047 return FALSE;
2049 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2051 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2052 TRACE("entry %s not found!\n", lpszUrlName);
2053 SetLastError(ERROR_FILE_NOT_FOUND);
2054 return FALSE;
2057 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2058 if (pEntry->dwSignature != URL_SIGNATURE)
2060 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2061 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2062 SetLastError(ERROR_FILE_NOT_FOUND);
2063 return FALSE;
2066 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2068 if (pUrlEntry->dwUseCount == 0)
2070 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2071 return FALSE;
2073 pUrlEntry->dwUseCount--;
2074 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2076 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2078 return TRUE;
2081 /***********************************************************************
2082 * UnlockUrlCacheEntryFileW (WININET.@)
2085 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
2087 LPURLCACHE_HEADER pHeader;
2088 struct _HASH_ENTRY * pHashEntry;
2089 CACHEFILE_ENTRY * pEntry;
2090 URL_CACHEFILE_ENTRY * pUrlEntry;
2091 URLCACHECONTAINER * pContainer;
2092 DWORD error;
2094 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
2096 if (dwReserved)
2098 ERR("dwReserved != 0\n");
2099 SetLastError(ERROR_INVALID_PARAMETER);
2100 return FALSE;
2103 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2104 if (error != ERROR_SUCCESS)
2106 SetLastError(error);
2107 return FALSE;
2110 error = URLCacheContainer_OpenIndex(pContainer);
2111 if (error != ERROR_SUCCESS)
2113 SetLastError(error);
2114 return FALSE;
2117 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2118 return FALSE;
2120 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
2122 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2123 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
2124 SetLastError(ERROR_FILE_NOT_FOUND);
2125 return FALSE;
2128 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2129 if (pEntry->dwSignature != URL_SIGNATURE)
2131 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2132 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2133 SetLastError(ERROR_FILE_NOT_FOUND);
2134 return FALSE;
2137 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2139 if (pUrlEntry->dwUseCount == 0)
2141 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2142 return FALSE;
2144 pUrlEntry->dwUseCount--;
2145 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2147 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2149 return TRUE;
2152 /***********************************************************************
2153 * CreateUrlCacheEntryA (WININET.@)
2156 BOOL WINAPI CreateUrlCacheEntryA(
2157 IN LPCSTR lpszUrlName,
2158 IN DWORD dwExpectedFileSize,
2159 IN LPCSTR lpszFileExtension,
2160 OUT LPSTR lpszFileName,
2161 IN DWORD dwReserved
2164 WCHAR *url_name;
2165 WCHAR *file_extension;
2166 WCHAR file_name[MAX_PATH];
2167 BOOL bSuccess = FALSE;
2168 DWORD dwError = 0;
2170 if (lpszUrlName && (url_name = heap_strdupAtoW(lpszUrlName)))
2172 if (lpszFileExtension && (file_extension = heap_strdupAtoW(lpszFileExtension)))
2174 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
2176 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
2178 bSuccess = TRUE;
2180 else
2182 dwError = GetLastError();
2185 else
2187 dwError = GetLastError();
2189 HeapFree(GetProcessHeap(), 0, file_extension);
2191 else
2193 dwError = GetLastError();
2195 HeapFree(GetProcessHeap(), 0, url_name);
2196 if (!bSuccess)
2197 SetLastError(dwError);
2199 return bSuccess;
2201 /***********************************************************************
2202 * CreateUrlCacheEntryW (WININET.@)
2205 BOOL WINAPI CreateUrlCacheEntryW(
2206 IN LPCWSTR lpszUrlName,
2207 IN DWORD dwExpectedFileSize,
2208 IN LPCWSTR lpszFileExtension,
2209 OUT LPWSTR lpszFileName,
2210 IN DWORD dwReserved
2213 URLCACHECONTAINER * pContainer;
2214 LPURLCACHE_HEADER pHeader;
2215 CHAR szFile[MAX_PATH];
2216 WCHAR szExtension[MAX_PATH];
2217 LPCWSTR lpszUrlPart;
2218 LPCWSTR lpszUrlEnd;
2219 LPCWSTR lpszFileNameExtension;
2220 LPWSTR lpszFileNameNoPath;
2221 int i;
2222 int countnoextension;
2223 BYTE CacheDir;
2224 LONG lBufferSize;
2225 BOOL bFound = FALSE;
2226 int count;
2227 DWORD error;
2228 HANDLE hFile;
2229 FILETIME ft;
2231 static const WCHAR szWWW[] = {'w','w','w',0};
2232 static const WCHAR fmt[] = {'%','0','8','X','%','s',0};
2234 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2235 debugstr_w(lpszUrlName),
2236 dwExpectedFileSize,
2237 debugstr_w(lpszFileExtension),
2238 lpszFileName,
2239 dwReserved);
2241 if (dwReserved)
2242 FIXME("dwReserved 0x%08x\n", dwReserved);
2244 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2246 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2247 lpszUrlEnd--;
2249 for (lpszUrlPart = lpszUrlEnd;
2250 (lpszUrlPart >= lpszUrlName);
2251 lpszUrlPart--)
2253 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2255 bFound = TRUE;
2256 lpszUrlPart++;
2257 break;
2259 else if(*lpszUrlPart == '?' || *lpszUrlPart == '#')
2261 lpszUrlEnd = lpszUrlPart;
2264 if (!lstrcmpW(lpszUrlPart, szWWW))
2266 lpszUrlPart += lstrlenW(szWWW);
2269 count = lpszUrlEnd - lpszUrlPart;
2271 if (bFound && (count < MAX_PATH))
2273 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2274 if (!len)
2275 return FALSE;
2276 szFile[len] = '\0';
2277 while(len && szFile[--len] == '/') szFile[len] = '\0';
2279 /* FIXME: get rid of illegal characters like \, / and : */
2281 else
2283 FIXME("need to generate a random filename\n");
2286 TRACE("File name: %s\n", debugstr_a(szFile));
2288 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2289 if (error != ERROR_SUCCESS)
2291 SetLastError(error);
2292 return FALSE;
2295 error = URLCacheContainer_OpenIndex(pContainer);
2296 if (error != ERROR_SUCCESS)
2298 SetLastError(error);
2299 return FALSE;
2302 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2303 return FALSE;
2305 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2307 lBufferSize = MAX_PATH * sizeof(WCHAR);
2308 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
2310 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2312 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2313 lpszFileNameNoPath >= lpszFileName;
2314 --lpszFileNameNoPath)
2316 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2317 break;
2320 countnoextension = lstrlenW(lpszFileNameNoPath);
2321 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2322 if (lpszFileNameExtension)
2323 countnoextension -= lstrlenW(lpszFileNameExtension);
2324 *szExtension = '\0';
2326 if (lpszFileExtension)
2328 szExtension[0] = '.';
2329 lstrcpyW(szExtension+1, lpszFileExtension);
2332 for (i = 0; i < 255; i++)
2334 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2335 WCHAR *p;
2337 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2338 for (p = lpszFileNameNoPath + 1; *p; p++)
2340 switch (*p)
2342 case '<': case '>':
2343 case ':': case '"':
2344 case '/': case '\\':
2345 case '|': case '?':
2346 case '*':
2347 *p = '_'; break;
2348 default: break;
2351 if (p[-1] == ' ' || p[-1] == '.') p[-1] = '_';
2353 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2354 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2355 if (hFile != INVALID_HANDLE_VALUE)
2357 CloseHandle(hFile);
2358 return TRUE;
2362 GetSystemTimeAsFileTime(&ft);
2363 wsprintfW(lpszFileNameNoPath + countnoextension, fmt, ft.dwLowDateTime, szExtension);
2365 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2366 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2367 if (hFile != INVALID_HANDLE_VALUE)
2369 CloseHandle(hFile);
2370 return TRUE;
2373 WARN("Could not find a unique filename\n");
2374 return FALSE;
2378 /***********************************************************************
2379 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2381 * The bug we are compensating for is that some drongo at Microsoft
2382 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2383 * As a consequence, CommitUrlCacheEntryA has been effectively
2384 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2385 * is still defined as LPCWSTR. The result (other than madness) is
2386 * that we always need to store lpHeaderInfo in CP_ACP rather than
2387 * in UTF16, and we need to avoid converting lpHeaderInfo in
2388 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2389 * result will lose data for arbitrary binary data.
2392 static BOOL CommitUrlCacheEntryInternal(
2393 IN LPCWSTR lpszUrlName,
2394 IN LPCWSTR lpszLocalFileName,
2395 IN FILETIME ExpireTime,
2396 IN FILETIME LastModifiedTime,
2397 IN DWORD CacheEntryType,
2398 IN LPBYTE lpHeaderInfo,
2399 IN DWORD dwHeaderSize,
2400 IN LPCWSTR lpszFileExtension,
2401 IN LPCWSTR lpszOriginalUrl
2404 URLCACHECONTAINER * pContainer;
2405 LPURLCACHE_HEADER pHeader;
2406 struct _HASH_ENTRY * pHashEntry;
2407 CACHEFILE_ENTRY * pEntry;
2408 URL_CACHEFILE_ENTRY * pUrlEntry;
2409 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2410 DWORD dwOffsetLocalFileName = 0;
2411 DWORD dwOffsetHeader = 0;
2412 DWORD dwOffsetFileExtension = 0;
2413 DWORD dwFileSizeLow = 0;
2414 DWORD dwFileSizeHigh = 0;
2415 BYTE cDirectory = 0;
2416 int len;
2417 char achFile[MAX_PATH];
2418 LPSTR lpszUrlNameA = NULL;
2419 LPSTR lpszFileExtensionA = NULL;
2420 char *pchLocalFileName = 0;
2421 DWORD error;
2423 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2424 debugstr_w(lpszUrlName),
2425 debugstr_w(lpszLocalFileName),
2426 CacheEntryType,
2427 lpHeaderInfo,
2428 dwHeaderSize,
2429 debugstr_w(lpszFileExtension),
2430 debugstr_w(lpszOriginalUrl));
2432 if (lpszOriginalUrl)
2433 WARN(": lpszOriginalUrl ignored\n");
2435 if (lpszLocalFileName)
2437 HANDLE hFile;
2439 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2440 if (hFile == INVALID_HANDLE_VALUE)
2442 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2443 return FALSE;
2446 /* Get file size */
2447 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2448 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2450 ERR("couldn't get file size (error is %d)\n", GetLastError());
2451 CloseHandle(hFile);
2452 return FALSE;
2455 CloseHandle(hFile);
2458 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2459 if (error != ERROR_SUCCESS)
2461 SetLastError(error);
2462 return FALSE;
2465 error = URLCacheContainer_OpenIndex(pContainer);
2466 if (error != ERROR_SUCCESS)
2468 SetLastError(error);
2469 return FALSE;
2472 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2473 return FALSE;
2475 lpszUrlNameA = heap_strdupWtoA(lpszUrlName);
2476 if (!lpszUrlNameA)
2478 error = GetLastError();
2479 goto cleanup;
2482 if (lpszFileExtension && !(lpszFileExtensionA = heap_strdupWtoA(lpszFileExtension)))
2484 error = GetLastError();
2485 goto cleanup;
2488 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2490 FIXME("entry already in cache - don't know what to do!\n");
2492 * SetLastError(ERROR_FILE_NOT_FOUND);
2493 * return FALSE;
2495 goto cleanup;
2498 if (lpszLocalFileName)
2500 BOOL bFound = FALSE;
2502 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2504 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2505 error = ERROR_INVALID_PARAMETER;
2506 goto cleanup;
2509 /* skip container path prefix */
2510 lpszLocalFileName += lstrlenW(pContainer->path);
2512 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL);
2513 pchLocalFileName = achFile;
2515 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2517 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2519 bFound = TRUE;
2520 break;
2524 if (!bFound)
2526 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2527 error = ERROR_INVALID_PARAMETER;
2528 goto cleanup;
2531 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2534 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2535 if (lpszLocalFileName)
2537 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2538 dwOffsetLocalFileName = dwBytesNeeded;
2539 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2541 if (lpHeaderInfo)
2543 dwOffsetHeader = dwBytesNeeded;
2544 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2546 if (lpszFileExtensionA)
2548 dwOffsetFileExtension = dwBytesNeeded;
2549 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2552 /* round up to next block */
2553 if (dwBytesNeeded % BLOCKSIZE)
2555 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2556 dwBytesNeeded += BLOCKSIZE;
2559 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2561 ERR("no free entries\n");
2562 error = ERROR_DISK_FULL;
2563 goto cleanup;
2566 /* FindFirstFreeEntry fills in blocks used */
2567 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2568 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2569 pUrlEntry->CacheDir = cDirectory;
2570 pUrlEntry->CacheEntryType = CacheEntryType;
2571 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2572 pUrlEntry->dwExemptDelta = 0;
2573 pUrlEntry->dwHitRate = 0;
2574 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2575 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2576 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2577 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2578 pUrlEntry->dwSizeHigh = 0;
2579 pUrlEntry->dwSizeLow = dwFileSizeLow;
2580 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2581 pUrlEntry->dwUseCount = 0;
2582 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2583 pUrlEntry->LastModifiedTime = LastModifiedTime;
2584 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2585 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2586 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2587 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2589 /*** Unknowns ***/
2590 pUrlEntry->dwUnknown1 = 0;
2591 pUrlEntry->dwUnknown2 = 0;
2592 pUrlEntry->dwUnknown3 = 0x60;
2593 pUrlEntry->Unknown4 = 0;
2594 pUrlEntry->wUnknown5 = 0x1010;
2595 pUrlEntry->dwUnknown7 = 0;
2596 pUrlEntry->dwUnknown8 = 0;
2599 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2600 if (dwOffsetLocalFileName)
2601 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2602 if (dwOffsetHeader)
2603 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2604 if (dwOffsetFileExtension)
2605 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2607 error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA,
2608 (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader));
2609 if (error != ERROR_SUCCESS)
2610 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2612 cleanup:
2613 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2614 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2615 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2617 if (error == ERROR_SUCCESS)
2618 return TRUE;
2619 else
2621 SetLastError(error);
2622 return FALSE;
2626 /***********************************************************************
2627 * CommitUrlCacheEntryA (WININET.@)
2630 BOOL WINAPI CommitUrlCacheEntryA(
2631 IN LPCSTR lpszUrlName,
2632 IN LPCSTR lpszLocalFileName,
2633 IN FILETIME ExpireTime,
2634 IN FILETIME LastModifiedTime,
2635 IN DWORD CacheEntryType,
2636 IN LPBYTE lpHeaderInfo,
2637 IN DWORD dwHeaderSize,
2638 IN LPCSTR lpszFileExtension,
2639 IN LPCSTR lpszOriginalUrl
2642 WCHAR *url_name = NULL;
2643 WCHAR *local_file_name = NULL;
2644 WCHAR *original_url = NULL;
2645 WCHAR *file_extension = NULL;
2646 BOOL bSuccess = FALSE;
2648 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2649 debugstr_a(lpszUrlName),
2650 debugstr_a(lpszLocalFileName),
2651 CacheEntryType,
2652 lpHeaderInfo,
2653 dwHeaderSize,
2654 debugstr_a(lpszFileExtension),
2655 debugstr_a(lpszOriginalUrl));
2657 url_name = heap_strdupAtoW(lpszUrlName);
2658 if (!url_name)
2659 goto cleanup;
2661 if (lpszLocalFileName)
2663 local_file_name = heap_strdupAtoW(lpszLocalFileName);
2664 if (!local_file_name)
2665 goto cleanup;
2667 if (lpszFileExtension)
2669 file_extension = heap_strdupAtoW(lpszFileExtension);
2670 if (!file_extension)
2671 goto cleanup;
2673 if (lpszOriginalUrl)
2675 original_url = heap_strdupAtoW(lpszOriginalUrl);
2676 if (!original_url)
2677 goto cleanup;
2680 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2681 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2682 file_extension, original_url);
2684 cleanup:
2685 HeapFree(GetProcessHeap(), 0, original_url);
2686 HeapFree(GetProcessHeap(), 0, file_extension);
2687 HeapFree(GetProcessHeap(), 0, local_file_name);
2688 HeapFree(GetProcessHeap(), 0, url_name);
2690 return bSuccess;
2693 /***********************************************************************
2694 * CommitUrlCacheEntryW (WININET.@)
2697 BOOL WINAPI CommitUrlCacheEntryW(
2698 IN LPCWSTR lpszUrlName,
2699 IN LPCWSTR lpszLocalFileName,
2700 IN FILETIME ExpireTime,
2701 IN FILETIME LastModifiedTime,
2702 IN DWORD CacheEntryType,
2703 IN LPWSTR lpHeaderInfo,
2704 IN DWORD dwHeaderSize,
2705 IN LPCWSTR lpszFileExtension,
2706 IN LPCWSTR lpszOriginalUrl
2709 DWORD dwError = 0;
2710 BOOL bSuccess = FALSE;
2711 DWORD len = 0;
2712 CHAR *header_info = NULL;
2714 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2715 debugstr_w(lpszUrlName),
2716 debugstr_w(lpszLocalFileName),
2717 CacheEntryType,
2718 lpHeaderInfo,
2719 dwHeaderSize,
2720 debugstr_w(lpszFileExtension),
2721 debugstr_w(lpszOriginalUrl));
2723 if (!lpHeaderInfo || (header_info = heap_strdupWtoA(lpHeaderInfo)))
2725 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2726 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2728 bSuccess = TRUE;
2730 else
2732 dwError = GetLastError();
2734 if (header_info)
2736 HeapFree(GetProcessHeap(), 0, header_info);
2737 if (!bSuccess)
2738 SetLastError(dwError);
2741 return bSuccess;
2744 /***********************************************************************
2745 * ReadUrlCacheEntryStream (WININET.@)
2748 BOOL WINAPI ReadUrlCacheEntryStream(
2749 IN HANDLE hUrlCacheStream,
2750 IN DWORD dwLocation,
2751 IN OUT LPVOID lpBuffer,
2752 IN OUT LPDWORD lpdwLen,
2753 IN DWORD dwReserved
2756 /* Get handle to file from 'stream' */
2757 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2759 if (dwReserved != 0)
2761 ERR("dwReserved != 0\n");
2762 SetLastError(ERROR_INVALID_PARAMETER);
2763 return FALSE;
2766 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2768 SetLastError(ERROR_INVALID_HANDLE);
2769 return FALSE;
2772 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2773 return FALSE;
2774 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2777 /***********************************************************************
2778 * RetrieveUrlCacheEntryStreamA (WININET.@)
2781 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2782 IN LPCSTR lpszUrlName,
2783 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2784 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2785 IN BOOL fRandomRead,
2786 IN DWORD dwReserved
2789 /* NOTE: this is not the same as the way that the native
2790 * version allocates 'stream' handles. I did it this way
2791 * as it is much easier and no applications should depend
2792 * on this behaviour. (Native version appears to allocate
2793 * indices into a table)
2795 STREAM_HANDLE * pStream;
2796 HANDLE hFile;
2798 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2799 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2801 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2802 lpCacheEntryInfo,
2803 lpdwCacheEntryInfoBufferSize,
2804 dwReserved))
2806 return NULL;
2809 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2810 GENERIC_READ,
2811 FILE_SHARE_READ,
2812 NULL,
2813 OPEN_EXISTING,
2814 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2815 NULL);
2816 if (hFile == INVALID_HANDLE_VALUE)
2817 return FALSE;
2819 /* allocate handle storage space */
2820 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2821 if (!pStream)
2823 CloseHandle(hFile);
2824 SetLastError(ERROR_OUTOFMEMORY);
2825 return FALSE;
2828 pStream->hFile = hFile;
2829 strcpy(pStream->lpszUrl, lpszUrlName);
2830 return pStream;
2833 /***********************************************************************
2834 * RetrieveUrlCacheEntryStreamW (WININET.@)
2837 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2838 IN LPCWSTR lpszUrlName,
2839 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2840 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2841 IN BOOL fRandomRead,
2842 IN DWORD dwReserved
2845 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2846 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2847 return NULL;
2850 /***********************************************************************
2851 * UnlockUrlCacheEntryStream (WININET.@)
2854 BOOL WINAPI UnlockUrlCacheEntryStream(
2855 IN HANDLE hUrlCacheStream,
2856 IN DWORD dwReserved
2859 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2861 if (dwReserved != 0)
2863 ERR("dwReserved != 0\n");
2864 SetLastError(ERROR_INVALID_PARAMETER);
2865 return FALSE;
2868 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2870 SetLastError(ERROR_INVALID_HANDLE);
2871 return FALSE;
2874 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2875 return FALSE;
2877 /* close file handle */
2878 CloseHandle(pStream->hFile);
2880 /* free allocated space */
2881 HeapFree(GetProcessHeap(), 0, pStream);
2883 return TRUE;
2887 /***********************************************************************
2888 * DeleteUrlCacheEntryA (WININET.@)
2891 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2893 URLCACHECONTAINER * pContainer;
2894 LPURLCACHE_HEADER pHeader;
2895 struct _HASH_ENTRY * pHashEntry;
2896 CACHEFILE_ENTRY * pEntry;
2897 DWORD error;
2899 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2901 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2902 if (error != ERROR_SUCCESS)
2904 SetLastError(error);
2905 return FALSE;
2908 error = URLCacheContainer_OpenIndex(pContainer);
2909 if (error != ERROR_SUCCESS)
2911 SetLastError(error);
2912 return FALSE;
2915 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2916 return FALSE;
2918 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2920 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2921 TRACE("entry %s not found!\n", lpszUrlName);
2922 SetLastError(ERROR_FILE_NOT_FOUND);
2923 return FALSE;
2926 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2927 URLCache_DeleteEntry(pHeader, pEntry);
2929 URLCache_DeleteEntryFromHash(pHashEntry);
2931 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2933 return TRUE;
2936 /***********************************************************************
2937 * DeleteUrlCacheEntryW (WININET.@)
2940 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2942 URLCACHECONTAINER * pContainer;
2943 LPURLCACHE_HEADER pHeader;
2944 struct _HASH_ENTRY * pHashEntry;
2945 CACHEFILE_ENTRY * pEntry;
2946 LPSTR urlA;
2947 DWORD error;
2949 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2951 urlA = heap_strdupWtoA(lpszUrlName);
2952 if (!urlA)
2954 SetLastError(ERROR_OUTOFMEMORY);
2955 return FALSE;
2958 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2959 if (error != ERROR_SUCCESS)
2961 HeapFree(GetProcessHeap(), 0, urlA);
2962 SetLastError(error);
2963 return FALSE;
2966 error = URLCacheContainer_OpenIndex(pContainer);
2967 if (error != ERROR_SUCCESS)
2969 HeapFree(GetProcessHeap(), 0, urlA);
2970 SetLastError(error);
2971 return FALSE;
2974 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2976 HeapFree(GetProcessHeap(), 0, urlA);
2977 return FALSE;
2980 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
2982 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2983 TRACE("entry %s not found!\n", debugstr_a(urlA));
2984 HeapFree(GetProcessHeap(), 0, urlA);
2985 SetLastError(ERROR_FILE_NOT_FOUND);
2986 return FALSE;
2989 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2990 URLCache_DeleteEntry(pHeader, pEntry);
2992 URLCache_DeleteEntryFromHash(pHashEntry);
2994 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2996 HeapFree(GetProcessHeap(), 0, urlA);
2997 return TRUE;
3000 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
3002 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3003 return TRUE;
3006 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
3008 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3009 return TRUE;
3012 /***********************************************************************
3013 * CreateCacheContainerA (WININET.@)
3015 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3016 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3018 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3019 d1, d2, d3, d4, d5, d6, d7, d8);
3020 return TRUE;
3023 /***********************************************************************
3024 * CreateCacheContainerW (WININET.@)
3026 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3027 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3029 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3030 d1, d2, d3, d4, d5, d6, d7, d8);
3031 return TRUE;
3034 /***********************************************************************
3035 * FindFirstUrlCacheContainerA (WININET.@)
3037 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3039 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3040 return NULL;
3043 /***********************************************************************
3044 * FindFirstUrlCacheContainerW (WININET.@)
3046 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3048 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3049 return NULL;
3052 /***********************************************************************
3053 * FindNextUrlCacheContainerA (WININET.@)
3055 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
3057 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3058 return FALSE;
3061 /***********************************************************************
3062 * FindNextUrlCacheContainerW (WININET.@)
3064 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
3066 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3067 return FALSE;
3070 HANDLE WINAPI FindFirstUrlCacheEntryExA(
3071 LPCSTR lpszUrlSearchPattern,
3072 DWORD dwFlags,
3073 DWORD dwFilter,
3074 GROUPID GroupId,
3075 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3076 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3077 LPVOID lpReserved,
3078 LPDWORD pcbReserved2,
3079 LPVOID lpReserved3
3082 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
3083 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3084 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3085 SetLastError(ERROR_FILE_NOT_FOUND);
3086 return NULL;
3089 HANDLE WINAPI FindFirstUrlCacheEntryExW(
3090 LPCWSTR lpszUrlSearchPattern,
3091 DWORD dwFlags,
3092 DWORD dwFilter,
3093 GROUPID GroupId,
3094 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3095 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3096 LPVOID lpReserved,
3097 LPDWORD pcbReserved2,
3098 LPVOID lpReserved3
3101 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
3102 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3103 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3104 SetLastError(ERROR_FILE_NOT_FOUND);
3105 return NULL;
3108 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3110 typedef struct URLCacheFindEntryHandle
3112 DWORD dwMagic;
3113 LPWSTR lpszUrlSearchPattern;
3114 DWORD dwContainerIndex;
3115 DWORD dwHashTableIndex;
3116 DWORD dwHashEntryIndex;
3117 } URLCacheFindEntryHandle;
3119 /***********************************************************************
3120 * FindFirstUrlCacheEntryA (WININET.@)
3123 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
3124 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3126 URLCacheFindEntryHandle *pEntryHandle;
3128 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3130 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3131 if (!pEntryHandle)
3132 return NULL;
3134 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3135 if (lpszUrlSearchPattern)
3137 pEntryHandle->lpszUrlSearchPattern = heap_strdupAtoW(lpszUrlSearchPattern);
3138 if (!pEntryHandle->lpszUrlSearchPattern)
3140 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3141 return NULL;
3144 else
3145 pEntryHandle->lpszUrlSearchPattern = NULL;
3146 pEntryHandle->dwContainerIndex = 0;
3147 pEntryHandle->dwHashTableIndex = 0;
3148 pEntryHandle->dwHashEntryIndex = 0;
3150 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3152 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3153 return NULL;
3155 return pEntryHandle;
3158 /***********************************************************************
3159 * FindFirstUrlCacheEntryW (WININET.@)
3162 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3163 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3165 URLCacheFindEntryHandle *pEntryHandle;
3167 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3169 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3170 if (!pEntryHandle)
3171 return NULL;
3173 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3174 if (lpszUrlSearchPattern)
3176 pEntryHandle->lpszUrlSearchPattern = heap_strdupW(lpszUrlSearchPattern);
3177 if (!pEntryHandle->lpszUrlSearchPattern)
3179 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3180 return NULL;
3183 else
3184 pEntryHandle->lpszUrlSearchPattern = NULL;
3185 pEntryHandle->dwContainerIndex = 0;
3186 pEntryHandle->dwHashTableIndex = 0;
3187 pEntryHandle->dwHashEntryIndex = 0;
3189 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3191 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3192 return NULL;
3194 return pEntryHandle;
3197 /***********************************************************************
3198 * FindNextUrlCacheEntryA (WININET.@)
3200 BOOL WINAPI FindNextUrlCacheEntryA(
3201 HANDLE hEnumHandle,
3202 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3203 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3205 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3206 URLCACHECONTAINER * pContainer;
3208 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3210 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3212 SetLastError(ERROR_INVALID_HANDLE);
3213 return FALSE;
3216 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3217 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3219 LPURLCACHE_HEADER pHeader;
3220 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3221 DWORD error;
3223 error = URLCacheContainer_OpenIndex(pContainer);
3224 if (error != ERROR_SUCCESS)
3226 SetLastError(error);
3227 return FALSE;
3230 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3231 return FALSE;
3233 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3234 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3236 const struct _HASH_ENTRY *pHashEntry = NULL;
3237 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3238 pEntryHandle->dwHashEntryIndex++)
3240 const URL_CACHEFILE_ENTRY *pUrlEntry;
3241 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3243 if (pEntry->dwSignature != URL_SIGNATURE)
3244 continue;
3246 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3247 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3248 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3250 error = URLCache_CopyEntry(
3251 pContainer,
3252 pHeader,
3253 lpNextCacheEntryInfo,
3254 lpdwNextCacheEntryInfoBufferSize,
3255 pUrlEntry,
3256 FALSE /* not UNICODE */);
3257 if (error != ERROR_SUCCESS)
3259 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3260 SetLastError(error);
3261 return FALSE;
3263 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
3265 /* increment the current index so that next time the function
3266 * is called the next entry is returned */
3267 pEntryHandle->dwHashEntryIndex++;
3268 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3269 return TRUE;
3273 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3276 SetLastError(ERROR_NO_MORE_ITEMS);
3277 return FALSE;
3280 /***********************************************************************
3281 * FindNextUrlCacheEntryW (WININET.@)
3283 BOOL WINAPI FindNextUrlCacheEntryW(
3284 HANDLE hEnumHandle,
3285 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3286 LPDWORD lpdwNextCacheEntryInfoBufferSize
3289 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3290 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3291 return FALSE;
3294 /***********************************************************************
3295 * FindCloseUrlCache (WININET.@)
3297 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3299 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3301 TRACE("(%p)\n", hEnumHandle);
3303 if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3305 SetLastError(ERROR_INVALID_HANDLE);
3306 return FALSE;
3309 pEntryHandle->dwMagic = 0;
3310 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3311 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3313 return TRUE;
3316 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3317 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3319 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3320 dwSearchCondition, lpGroupId, lpReserved);
3321 return NULL;
3324 BOOL WINAPI FindNextUrlCacheEntryExA(
3325 HANDLE hEnumHandle,
3326 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3327 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3328 LPVOID lpReserved,
3329 LPDWORD pcbReserved2,
3330 LPVOID lpReserved3
3333 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3334 lpReserved, pcbReserved2, lpReserved3);
3335 return FALSE;
3338 BOOL WINAPI FindNextUrlCacheEntryExW(
3339 HANDLE hEnumHandle,
3340 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3341 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3342 LPVOID lpReserved,
3343 LPDWORD pcbReserved2,
3344 LPVOID lpReserved3
3347 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3348 lpReserved, pcbReserved2, lpReserved3);
3349 return FALSE;
3352 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3354 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3355 return FALSE;
3358 /***********************************************************************
3359 * CreateUrlCacheGroup (WININET.@)
3362 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3364 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3365 return FALSE;
3368 /***********************************************************************
3369 * DeleteUrlCacheGroup (WININET.@)
3372 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3374 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3375 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3376 return FALSE;
3379 /***********************************************************************
3380 * SetUrlCacheEntryGroupA (WININET.@)
3383 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3384 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3385 LPVOID lpReserved)
3387 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3388 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3389 pbGroupAttributes, cbGroupAttributes, lpReserved);
3390 SetLastError(ERROR_FILE_NOT_FOUND);
3391 return FALSE;
3394 /***********************************************************************
3395 * SetUrlCacheEntryGroupW (WININET.@)
3398 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3399 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3400 LPVOID lpReserved)
3402 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3403 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3404 pbGroupAttributes, cbGroupAttributes, lpReserved);
3405 SetLastError(ERROR_FILE_NOT_FOUND);
3406 return FALSE;
3409 /***********************************************************************
3410 * GetUrlCacheConfigInfoW (WININET.@)
3412 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3414 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3415 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3416 return FALSE;
3419 /***********************************************************************
3420 * GetUrlCacheConfigInfoA (WININET.@)
3422 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3424 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3426 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3427 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3428 return FALSE;
3431 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3432 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3433 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3435 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3436 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3437 lpdwGroupInfo, lpReserved);
3438 return FALSE;
3441 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3442 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3443 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3445 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3446 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3447 lpdwGroupInfo, lpReserved);
3448 return FALSE;
3451 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3452 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3454 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3455 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3456 return TRUE;
3459 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3460 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3462 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3463 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3464 return TRUE;
3467 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3469 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3470 return TRUE;
3473 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3475 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3476 return TRUE;
3479 /***********************************************************************
3480 * DeleteIE3Cache (WININET.@)
3482 * Deletes the files used by the IE3 URL caching system.
3484 * PARAMS
3485 * hWnd [I] A dummy window.
3486 * hInst [I] Instance of process calling the function.
3487 * lpszCmdLine [I] Options used by function.
3488 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3490 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3492 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3493 return 0;
3496 /***********************************************************************
3497 * IsUrlCacheEntryExpiredA (WININET.@)
3499 * PARAMS
3500 * url [I] Url
3501 * dwFlags [I] Unknown
3502 * pftLastModified [O] Last modified time
3504 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3506 LPURLCACHE_HEADER pHeader;
3507 struct _HASH_ENTRY * pHashEntry;
3508 const CACHEFILE_ENTRY * pEntry;
3509 const URL_CACHEFILE_ENTRY * pUrlEntry;
3510 URLCACHECONTAINER * pContainer;
3511 DWORD error;
3513 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3515 error = URLCacheContainers_FindContainerA(url, &pContainer);
3516 if (error != ERROR_SUCCESS)
3518 SetLastError(error);
3519 return FALSE;
3522 error = URLCacheContainer_OpenIndex(pContainer);
3523 if (error != ERROR_SUCCESS)
3525 SetLastError(error);
3526 return FALSE;
3529 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3530 return FALSE;
3532 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3534 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3535 TRACE("entry %s not found!\n", url);
3536 SetLastError(ERROR_FILE_NOT_FOUND);
3537 return FALSE;
3540 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3541 if (pEntry->dwSignature != URL_SIGNATURE)
3543 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3544 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3545 SetLastError(ERROR_FILE_NOT_FOUND);
3546 return FALSE;
3549 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3551 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3553 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3555 return TRUE;
3558 /***********************************************************************
3559 * IsUrlCacheEntryExpiredW (WININET.@)
3561 * PARAMS
3562 * url [I] Url
3563 * dwFlags [I] Unknown
3564 * pftLastModified [O] Last modified time
3566 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3568 LPURLCACHE_HEADER pHeader;
3569 struct _HASH_ENTRY * pHashEntry;
3570 const CACHEFILE_ENTRY * pEntry;
3571 const URL_CACHEFILE_ENTRY * pUrlEntry;
3572 URLCACHECONTAINER * pContainer;
3573 DWORD error;
3575 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3577 error = URLCacheContainers_FindContainerW(url, &pContainer);
3578 if (error != ERROR_SUCCESS)
3580 SetLastError(error);
3581 return FALSE;
3584 error = URLCacheContainer_OpenIndex(pContainer);
3585 if (error != ERROR_SUCCESS)
3587 SetLastError(error);
3588 return FALSE;
3591 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3592 return FALSE;
3594 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3596 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3597 TRACE("entry %s not found!\n", debugstr_w(url));
3598 SetLastError(ERROR_FILE_NOT_FOUND);
3599 return FALSE;
3602 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3603 if (pEntry->dwSignature != URL_SIGNATURE)
3605 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3606 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3607 SetLastError(ERROR_FILE_NOT_FOUND);
3608 return FALSE;
3611 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3613 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3615 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3617 return TRUE;
3620 /***********************************************************************
3621 * GetDiskInfoA (WININET.@)
3623 BOOL WINAPI GetDiskInfoA(PCSTR path, PDWORD cluster_size, PDWORDLONG free, PDWORDLONG total)
3625 BOOL ret;
3626 ULARGE_INTEGER bytes_free, bytes_total;
3628 TRACE("(%s, %p, %p, %p)\n", debugstr_a(path), cluster_size, free, total);
3630 if (!path)
3632 SetLastError(ERROR_INVALID_PARAMETER);
3633 return FALSE;
3636 if ((ret = GetDiskFreeSpaceExA(path, NULL, &bytes_total, &bytes_free)))
3638 if (cluster_size) *cluster_size = 1;
3639 if (free) *free = bytes_free.QuadPart;
3640 if (total) *total = bytes_total.QuadPart;
3642 return ret;
3645 /***********************************************************************
3646 * RegisterUrlCacheNotification (WININET.@)
3648 DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
3650 FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f);
3651 return 0;
3654 /***********************************************************************
3655 * IncrementUrlCacheHeaderData (WININET.@)
3657 BOOL WINAPI IncrementUrlCacheHeaderData(DWORD index, LPDWORD data)
3659 FIXME("(%u, %p)\n", index, data);
3660 return FALSE;