dplayx: Code to forward player creation
[wine/gsoc_dplay.git] / dlls / wininet / urlcache.c
blob0b29a6e9a7b0f4145140412df21848ae7a041710
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)
1482 FIXME("Undocumented flag(s): %x\n", dwFlags);
1483 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1486 /***********************************************************************
1487 * GetUrlCacheEntryInfoA (WININET.@)
1490 BOOL WINAPI GetUrlCacheEntryInfoA(
1491 IN LPCSTR lpszUrlName,
1492 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1493 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1496 LPURLCACHE_HEADER pHeader;
1497 struct _HASH_ENTRY * pHashEntry;
1498 const CACHEFILE_ENTRY * pEntry;
1499 const URL_CACHEFILE_ENTRY * pUrlEntry;
1500 URLCACHECONTAINER * pContainer;
1501 DWORD error;
1503 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1505 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1506 if (error != ERROR_SUCCESS)
1508 SetLastError(error);
1509 return FALSE;
1512 error = URLCacheContainer_OpenIndex(pContainer);
1513 if (error != ERROR_SUCCESS)
1515 SetLastError(error);
1516 return FALSE;
1519 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1520 return FALSE;
1522 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1524 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1525 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1526 SetLastError(ERROR_FILE_NOT_FOUND);
1527 return FALSE;
1530 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1531 if (pEntry->dwSignature != URL_SIGNATURE)
1533 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1534 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1535 SetLastError(ERROR_FILE_NOT_FOUND);
1536 return FALSE;
1539 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1540 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1541 if (pUrlEntry->dwOffsetHeaderInfo)
1542 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1544 if (lpdwCacheEntryInfoBufferSize)
1546 if (!lpCacheEntryInfo)
1547 *lpdwCacheEntryInfoBufferSize = 0;
1549 error = URLCache_CopyEntry(
1550 pContainer,
1551 pHeader,
1552 lpCacheEntryInfo,
1553 lpdwCacheEntryInfoBufferSize,
1554 pUrlEntry,
1555 FALSE /* ANSI */);
1556 if (error != ERROR_SUCCESS)
1558 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1559 SetLastError(error);
1560 return FALSE;
1562 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1565 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1567 return TRUE;
1570 /***********************************************************************
1571 * GetUrlCacheEntryInfoW (WININET.@)
1574 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1575 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1576 LPDWORD lpdwCacheEntryInfoBufferSize)
1578 LPURLCACHE_HEADER pHeader;
1579 struct _HASH_ENTRY * pHashEntry;
1580 const CACHEFILE_ENTRY * pEntry;
1581 const URL_CACHEFILE_ENTRY * pUrlEntry;
1582 URLCACHECONTAINER * pContainer;
1583 DWORD error;
1585 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1587 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1588 if (error != ERROR_SUCCESS)
1590 SetLastError(error);
1591 return FALSE;
1594 error = URLCacheContainer_OpenIndex(pContainer);
1595 if (error != ERROR_SUCCESS)
1597 SetLastError(error);
1598 return FALSE;
1601 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1602 return FALSE;
1604 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1606 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1607 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1608 SetLastError(ERROR_FILE_NOT_FOUND);
1609 return FALSE;
1612 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1613 if (pEntry->dwSignature != URL_SIGNATURE)
1615 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1616 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1617 SetLastError(ERROR_FILE_NOT_FOUND);
1618 return FALSE;
1621 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1622 TRACE("Found URL: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1623 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1625 if (lpdwCacheEntryInfoBufferSize)
1627 if (!lpCacheEntryInfo)
1628 *lpdwCacheEntryInfoBufferSize = 0;
1630 error = URLCache_CopyEntry(
1631 pContainer,
1632 pHeader,
1633 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1634 lpdwCacheEntryInfoBufferSize,
1635 pUrlEntry,
1636 TRUE /* UNICODE */);
1637 if (error != ERROR_SUCCESS)
1639 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1640 SetLastError(error);
1641 return FALSE;
1643 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1646 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1648 return TRUE;
1651 /***********************************************************************
1652 * GetUrlCacheEntryInfoExW (WININET.@)
1655 BOOL WINAPI GetUrlCacheEntryInfoExW(
1656 LPCWSTR lpszUrl,
1657 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1658 LPDWORD lpdwCacheEntryInfoBufSize,
1659 LPWSTR lpszReserved,
1660 LPDWORD lpdwReserved,
1661 LPVOID lpReserved,
1662 DWORD dwFlags)
1664 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1665 debugstr_w(lpszUrl),
1666 lpCacheEntryInfo,
1667 lpdwCacheEntryInfoBufSize,
1668 lpszReserved,
1669 lpdwReserved,
1670 lpReserved,
1671 dwFlags);
1673 if ((lpszReserved != NULL) ||
1674 (lpdwReserved != NULL) ||
1675 (lpReserved != NULL))
1677 ERR("Reserved value was not 0\n");
1678 SetLastError(ERROR_INVALID_PARAMETER);
1679 return FALSE;
1681 if (dwFlags != 0)
1682 FIXME("Undocumented flag(s): %x\n", dwFlags);
1683 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1686 /***********************************************************************
1687 * SetUrlCacheEntryInfoA (WININET.@)
1689 BOOL WINAPI SetUrlCacheEntryInfoA(
1690 LPCSTR lpszUrlName,
1691 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1692 DWORD dwFieldControl)
1694 LPURLCACHE_HEADER pHeader;
1695 struct _HASH_ENTRY * pHashEntry;
1696 CACHEFILE_ENTRY * pEntry;
1697 URLCACHECONTAINER * pContainer;
1698 DWORD error;
1700 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1702 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1703 if (error != ERROR_SUCCESS)
1705 SetLastError(error);
1706 return FALSE;
1709 error = URLCacheContainer_OpenIndex(pContainer);
1710 if (error != ERROR_SUCCESS)
1712 SetLastError(error);
1713 return FALSE;
1716 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1717 return FALSE;
1719 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1721 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1722 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1723 SetLastError(ERROR_FILE_NOT_FOUND);
1724 return FALSE;
1727 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1728 if (pEntry->dwSignature != URL_SIGNATURE)
1730 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1731 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1732 SetLastError(ERROR_FILE_NOT_FOUND);
1733 return FALSE;
1736 URLCache_SetEntryInfo(
1737 (URL_CACHEFILE_ENTRY *)pEntry,
1738 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1739 dwFieldControl);
1741 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1743 return TRUE;
1746 /***********************************************************************
1747 * SetUrlCacheEntryInfoW (WININET.@)
1749 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1751 LPURLCACHE_HEADER pHeader;
1752 struct _HASH_ENTRY * pHashEntry;
1753 CACHEFILE_ENTRY * pEntry;
1754 URLCACHECONTAINER * pContainer;
1755 DWORD error;
1757 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1759 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1760 if (error != ERROR_SUCCESS)
1762 SetLastError(error);
1763 return FALSE;
1766 error = URLCacheContainer_OpenIndex(pContainer);
1767 if (error != ERROR_SUCCESS)
1769 SetLastError(error);
1770 return FALSE;
1773 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1774 return FALSE;
1776 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1778 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1779 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1780 SetLastError(ERROR_FILE_NOT_FOUND);
1781 return FALSE;
1784 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1785 if (pEntry->dwSignature != URL_SIGNATURE)
1787 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1788 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1789 SetLastError(ERROR_FILE_NOT_FOUND);
1790 return FALSE;
1793 URLCache_SetEntryInfo(
1794 (URL_CACHEFILE_ENTRY *)pEntry,
1795 lpCacheEntryInfo,
1796 dwFieldControl);
1798 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1800 return TRUE;
1803 /***********************************************************************
1804 * RetrieveUrlCacheEntryFileA (WININET.@)
1807 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1808 IN LPCSTR lpszUrlName,
1809 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1810 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1811 IN DWORD dwReserved
1814 LPURLCACHE_HEADER pHeader;
1815 struct _HASH_ENTRY * pHashEntry;
1816 CACHEFILE_ENTRY * pEntry;
1817 URL_CACHEFILE_ENTRY * pUrlEntry;
1818 URLCACHECONTAINER * pContainer;
1819 DWORD error;
1821 TRACE("(%s, %p, %p, 0x%08x)\n",
1822 debugstr_a(lpszUrlName),
1823 lpCacheEntryInfo,
1824 lpdwCacheEntryInfoBufferSize,
1825 dwReserved);
1827 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1828 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1830 SetLastError(ERROR_INVALID_PARAMETER);
1831 return FALSE;
1834 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1835 if (error != ERROR_SUCCESS)
1837 SetLastError(error);
1838 return FALSE;
1841 error = URLCacheContainer_OpenIndex(pContainer);
1842 if (error != ERROR_SUCCESS)
1844 SetLastError(error);
1845 return FALSE;
1848 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1849 return FALSE;
1851 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1853 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1854 TRACE("entry %s not found!\n", lpszUrlName);
1855 SetLastError(ERROR_FILE_NOT_FOUND);
1856 return FALSE;
1859 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1860 if (pEntry->dwSignature != URL_SIGNATURE)
1862 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1863 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1864 SetLastError(ERROR_FILE_NOT_FOUND);
1865 return FALSE;
1868 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1869 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1870 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1872 pUrlEntry->dwHitRate++;
1873 pUrlEntry->dwUseCount++;
1874 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1876 error = URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo,
1877 lpdwCacheEntryInfoBufferSize, pUrlEntry,
1878 FALSE);
1879 if (error != ERROR_SUCCESS)
1881 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1882 SetLastError(error);
1883 return FALSE;
1885 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1887 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1889 return TRUE;
1892 /***********************************************************************
1893 * RetrieveUrlCacheEntryFileW (WININET.@)
1896 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1897 IN LPCWSTR lpszUrlName,
1898 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1899 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1900 IN DWORD dwReserved
1903 LPURLCACHE_HEADER pHeader;
1904 struct _HASH_ENTRY * pHashEntry;
1905 CACHEFILE_ENTRY * pEntry;
1906 URL_CACHEFILE_ENTRY * pUrlEntry;
1907 URLCACHECONTAINER * pContainer;
1908 DWORD error;
1910 TRACE("(%s, %p, %p, 0x%08x)\n",
1911 debugstr_w(lpszUrlName),
1912 lpCacheEntryInfo,
1913 lpdwCacheEntryInfoBufferSize,
1914 dwReserved);
1916 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1917 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1919 SetLastError(ERROR_INVALID_PARAMETER);
1920 return FALSE;
1923 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
1924 if (error != ERROR_SUCCESS)
1926 SetLastError(error);
1927 return FALSE;
1930 error = URLCacheContainer_OpenIndex(pContainer);
1931 if (error != ERROR_SUCCESS)
1933 SetLastError(error);
1934 return FALSE;
1937 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1938 return FALSE;
1940 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1942 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1943 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1944 SetLastError(ERROR_FILE_NOT_FOUND);
1945 return FALSE;
1948 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1949 if (pEntry->dwSignature != URL_SIGNATURE)
1951 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1952 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1953 SetLastError(ERROR_FILE_NOT_FOUND);
1954 return FALSE;
1957 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1958 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1959 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1961 pUrlEntry->dwHitRate++;
1962 pUrlEntry->dwUseCount++;
1963 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1965 error = URLCache_CopyEntry(
1966 pContainer,
1967 pHeader,
1968 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1969 lpdwCacheEntryInfoBufferSize,
1970 pUrlEntry,
1971 TRUE /* UNICODE */);
1972 if (error != ERROR_SUCCESS)
1974 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1975 SetLastError(error);
1976 return FALSE;
1978 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1980 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1982 return TRUE;
1985 /***********************************************************************
1986 * UnlockUrlCacheEntryFileA (WININET.@)
1989 BOOL WINAPI UnlockUrlCacheEntryFileA(
1990 IN LPCSTR lpszUrlName,
1991 IN DWORD dwReserved
1994 LPURLCACHE_HEADER pHeader;
1995 struct _HASH_ENTRY * pHashEntry;
1996 CACHEFILE_ENTRY * pEntry;
1997 URL_CACHEFILE_ENTRY * pUrlEntry;
1998 URLCACHECONTAINER * pContainer;
1999 DWORD error;
2001 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
2003 if (dwReserved)
2005 ERR("dwReserved != 0\n");
2006 SetLastError(ERROR_INVALID_PARAMETER);
2007 return FALSE;
2010 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2011 if (error != ERROR_SUCCESS)
2013 SetLastError(error);
2014 return FALSE;
2017 error = URLCacheContainer_OpenIndex(pContainer);
2018 if (error != ERROR_SUCCESS)
2020 SetLastError(error);
2021 return FALSE;
2024 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2025 return FALSE;
2027 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2029 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2030 TRACE("entry %s not found!\n", lpszUrlName);
2031 SetLastError(ERROR_FILE_NOT_FOUND);
2032 return FALSE;
2035 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2036 if (pEntry->dwSignature != URL_SIGNATURE)
2038 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2039 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2040 SetLastError(ERROR_FILE_NOT_FOUND);
2041 return FALSE;
2044 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2046 if (pUrlEntry->dwUseCount == 0)
2048 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2049 return FALSE;
2051 pUrlEntry->dwUseCount--;
2052 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2054 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2056 return TRUE;
2059 /***********************************************************************
2060 * UnlockUrlCacheEntryFileW (WININET.@)
2063 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
2065 LPURLCACHE_HEADER pHeader;
2066 struct _HASH_ENTRY * pHashEntry;
2067 CACHEFILE_ENTRY * pEntry;
2068 URL_CACHEFILE_ENTRY * pUrlEntry;
2069 URLCACHECONTAINER * pContainer;
2070 DWORD error;
2072 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
2074 if (dwReserved)
2076 ERR("dwReserved != 0\n");
2077 SetLastError(ERROR_INVALID_PARAMETER);
2078 return FALSE;
2081 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2082 if (error != ERROR_SUCCESS)
2084 SetLastError(error);
2085 return FALSE;
2088 error = URLCacheContainer_OpenIndex(pContainer);
2089 if (error != ERROR_SUCCESS)
2091 SetLastError(error);
2092 return FALSE;
2095 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2096 return FALSE;
2098 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
2100 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2101 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
2102 SetLastError(ERROR_FILE_NOT_FOUND);
2103 return FALSE;
2106 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2107 if (pEntry->dwSignature != URL_SIGNATURE)
2109 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2110 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2111 SetLastError(ERROR_FILE_NOT_FOUND);
2112 return FALSE;
2115 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2117 if (pUrlEntry->dwUseCount == 0)
2119 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2120 return FALSE;
2122 pUrlEntry->dwUseCount--;
2123 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2125 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2127 return TRUE;
2130 /***********************************************************************
2131 * CreateUrlCacheEntryA (WININET.@)
2134 BOOL WINAPI CreateUrlCacheEntryA(
2135 IN LPCSTR lpszUrlName,
2136 IN DWORD dwExpectedFileSize,
2137 IN LPCSTR lpszFileExtension,
2138 OUT LPSTR lpszFileName,
2139 IN DWORD dwReserved
2142 WCHAR *url_name;
2143 WCHAR *file_extension;
2144 WCHAR file_name[MAX_PATH];
2145 BOOL bSuccess = FALSE;
2146 DWORD dwError = 0;
2148 if (lpszUrlName && (url_name = heap_strdupAtoW(lpszUrlName)))
2150 if (lpszFileExtension && (file_extension = heap_strdupAtoW(lpszFileExtension)))
2152 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
2154 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
2156 bSuccess = TRUE;
2158 else
2160 dwError = GetLastError();
2163 else
2165 dwError = GetLastError();
2167 HeapFree(GetProcessHeap(), 0, file_extension);
2169 else
2171 dwError = GetLastError();
2173 HeapFree(GetProcessHeap(), 0, url_name);
2174 if (!bSuccess)
2175 SetLastError(dwError);
2177 return bSuccess;
2179 /***********************************************************************
2180 * CreateUrlCacheEntryW (WININET.@)
2183 BOOL WINAPI CreateUrlCacheEntryW(
2184 IN LPCWSTR lpszUrlName,
2185 IN DWORD dwExpectedFileSize,
2186 IN LPCWSTR lpszFileExtension,
2187 OUT LPWSTR lpszFileName,
2188 IN DWORD dwReserved
2191 URLCACHECONTAINER * pContainer;
2192 LPURLCACHE_HEADER pHeader;
2193 CHAR szFile[MAX_PATH];
2194 WCHAR szExtension[MAX_PATH];
2195 LPCWSTR lpszUrlPart;
2196 LPCWSTR lpszUrlEnd;
2197 LPCWSTR lpszFileNameExtension;
2198 LPWSTR lpszFileNameNoPath;
2199 int i;
2200 int countnoextension;
2201 BYTE CacheDir;
2202 LONG lBufferSize;
2203 BOOL bFound = FALSE;
2204 int count;
2205 DWORD error;
2206 static const WCHAR szWWW[] = {'w','w','w',0};
2208 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2209 debugstr_w(lpszUrlName),
2210 dwExpectedFileSize,
2211 debugstr_w(lpszFileExtension),
2212 lpszFileName,
2213 dwReserved);
2215 if (dwReserved)
2216 FIXME("dwReserved 0x%08x\n", dwReserved);
2218 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2220 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2221 lpszUrlEnd--;
2223 for (lpszUrlPart = lpszUrlEnd;
2224 (lpszUrlPart >= lpszUrlName);
2225 lpszUrlPart--)
2227 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2229 bFound = TRUE;
2230 lpszUrlPart++;
2231 break;
2233 else if(*lpszUrlPart == '?' || *lpszUrlPart == '#')
2235 lpszUrlEnd = lpszUrlPart;
2238 if (!lstrcmpW(lpszUrlPart, szWWW))
2240 lpszUrlPart += lstrlenW(szWWW);
2243 count = lpszUrlEnd - lpszUrlPart;
2245 if (bFound && (count < MAX_PATH))
2247 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2248 if (!len)
2249 return FALSE;
2250 szFile[len] = '\0';
2251 while(len && szFile[--len] == '/') szFile[len] = '\0';
2253 /* FIXME: get rid of illegal characters like \, / and : */
2255 else
2257 FIXME("need to generate a random filename\n");
2260 TRACE("File name: %s\n", debugstr_a(szFile));
2262 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2263 if (error != ERROR_SUCCESS)
2265 SetLastError(error);
2266 return FALSE;
2269 error = URLCacheContainer_OpenIndex(pContainer);
2270 if (error != ERROR_SUCCESS)
2272 SetLastError(error);
2273 return FALSE;
2276 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2277 return FALSE;
2279 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2281 lBufferSize = MAX_PATH * sizeof(WCHAR);
2282 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
2284 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2286 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2287 lpszFileNameNoPath >= lpszFileName;
2288 --lpszFileNameNoPath)
2290 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2291 break;
2294 countnoextension = lstrlenW(lpszFileNameNoPath);
2295 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2296 if (lpszFileNameExtension)
2297 countnoextension -= lstrlenW(lpszFileNameExtension);
2298 *szExtension = '\0';
2300 if (lpszFileExtension)
2302 szExtension[0] = '.';
2303 lstrcpyW(szExtension+1, lpszFileExtension);
2306 for (i = 0; i < 255; i++)
2308 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2309 HANDLE hFile;
2310 WCHAR *p;
2312 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2313 for (p = lpszFileNameNoPath + 1; *p; p++)
2315 switch (*p)
2317 case '<': case '>':
2318 case ':': case '"':
2319 case '/': case '\\':
2320 case '|': case '?':
2321 case '*':
2322 *p = '_'; break;
2323 default: break;
2326 if (p[-1] == ' ' || p[-1] == '.') p[-1] = '_';
2328 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2329 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2330 if (hFile != INVALID_HANDLE_VALUE)
2332 CloseHandle(hFile);
2333 return TRUE;
2337 return FALSE;
2341 /***********************************************************************
2342 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2344 * The bug we are compensating for is that some drongo at Microsoft
2345 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2346 * As a consequence, CommitUrlCacheEntryA has been effectively
2347 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2348 * is still defined as LPCWSTR. The result (other than madness) is
2349 * that we always need to store lpHeaderInfo in CP_ACP rather than
2350 * in UTF16, and we need to avoid converting lpHeaderInfo in
2351 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2352 * result will lose data for arbitrary binary data.
2355 static BOOL CommitUrlCacheEntryInternal(
2356 IN LPCWSTR lpszUrlName,
2357 IN LPCWSTR lpszLocalFileName,
2358 IN FILETIME ExpireTime,
2359 IN FILETIME LastModifiedTime,
2360 IN DWORD CacheEntryType,
2361 IN LPBYTE lpHeaderInfo,
2362 IN DWORD dwHeaderSize,
2363 IN LPCWSTR lpszFileExtension,
2364 IN LPCWSTR lpszOriginalUrl
2367 URLCACHECONTAINER * pContainer;
2368 LPURLCACHE_HEADER pHeader;
2369 struct _HASH_ENTRY * pHashEntry;
2370 CACHEFILE_ENTRY * pEntry;
2371 URL_CACHEFILE_ENTRY * pUrlEntry;
2372 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2373 DWORD dwOffsetLocalFileName = 0;
2374 DWORD dwOffsetHeader = 0;
2375 DWORD dwOffsetFileExtension = 0;
2376 DWORD dwFileSizeLow = 0;
2377 DWORD dwFileSizeHigh = 0;
2378 BYTE cDirectory = 0;
2379 int len;
2380 char achFile[MAX_PATH];
2381 LPSTR lpszUrlNameA = NULL;
2382 LPSTR lpszFileExtensionA = NULL;
2383 char *pchLocalFileName = 0;
2384 DWORD error;
2386 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2387 debugstr_w(lpszUrlName),
2388 debugstr_w(lpszLocalFileName),
2389 CacheEntryType,
2390 lpHeaderInfo,
2391 dwHeaderSize,
2392 debugstr_w(lpszFileExtension),
2393 debugstr_w(lpszOriginalUrl));
2395 if (lpszOriginalUrl)
2396 WARN(": lpszOriginalUrl ignored\n");
2398 if (lpszLocalFileName)
2400 HANDLE hFile;
2402 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2403 if (hFile == INVALID_HANDLE_VALUE)
2405 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2406 return FALSE;
2409 /* Get file size */
2410 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2411 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2413 ERR("couldn't get file size (error is %d)\n", GetLastError());
2414 CloseHandle(hFile);
2415 return FALSE;
2418 CloseHandle(hFile);
2421 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2422 if (error != ERROR_SUCCESS)
2424 SetLastError(error);
2425 return FALSE;
2428 error = URLCacheContainer_OpenIndex(pContainer);
2429 if (error != ERROR_SUCCESS)
2431 SetLastError(error);
2432 return FALSE;
2435 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2436 return FALSE;
2438 lpszUrlNameA = heap_strdupWtoA(lpszUrlName);
2439 if (!lpszUrlNameA)
2441 error = GetLastError();
2442 goto cleanup;
2445 if (lpszFileExtension && !(lpszFileExtensionA = heap_strdupWtoA(lpszFileExtension)))
2447 error = GetLastError();
2448 goto cleanup;
2451 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2453 FIXME("entry already in cache - don't know what to do!\n");
2455 * SetLastError(ERROR_FILE_NOT_FOUND);
2456 * return FALSE;
2458 goto cleanup;
2461 if (lpszLocalFileName)
2463 BOOL bFound = FALSE;
2465 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2467 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2468 error = ERROR_INVALID_PARAMETER;
2469 goto cleanup;
2472 /* skip container path prefix */
2473 lpszLocalFileName += lstrlenW(pContainer->path);
2475 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL);
2476 pchLocalFileName = achFile;
2478 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2480 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2482 bFound = TRUE;
2483 break;
2487 if (!bFound)
2489 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2490 error = ERROR_INVALID_PARAMETER;
2491 goto cleanup;
2494 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2497 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2498 if (lpszLocalFileName)
2500 len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL);
2501 dwOffsetLocalFileName = dwBytesNeeded;
2502 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2504 if (lpHeaderInfo)
2506 dwOffsetHeader = dwBytesNeeded;
2507 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2509 if (lpszFileExtensionA)
2511 dwOffsetFileExtension = dwBytesNeeded;
2512 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2515 /* round up to next block */
2516 if (dwBytesNeeded % BLOCKSIZE)
2518 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2519 dwBytesNeeded += BLOCKSIZE;
2522 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2524 ERR("no free entries\n");
2525 error = ERROR_DISK_FULL;
2526 goto cleanup;
2529 /* FindFirstFreeEntry fills in blocks used */
2530 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2531 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2532 pUrlEntry->CacheDir = cDirectory;
2533 pUrlEntry->CacheEntryType = CacheEntryType;
2534 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2535 pUrlEntry->dwExemptDelta = 0;
2536 pUrlEntry->dwHitRate = 0;
2537 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2538 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2539 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2540 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2541 pUrlEntry->dwSizeHigh = 0;
2542 pUrlEntry->dwSizeLow = dwFileSizeLow;
2543 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2544 pUrlEntry->dwUseCount = 0;
2545 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2546 pUrlEntry->LastModifiedTime = LastModifiedTime;
2547 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2548 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2549 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2550 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2552 /*** Unknowns ***/
2553 pUrlEntry->dwUnknown1 = 0;
2554 pUrlEntry->dwUnknown2 = 0;
2555 pUrlEntry->dwUnknown3 = 0x60;
2556 pUrlEntry->Unknown4 = 0;
2557 pUrlEntry->wUnknown5 = 0x1010;
2558 pUrlEntry->dwUnknown7 = 0;
2559 pUrlEntry->dwUnknown8 = 0;
2562 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2563 if (dwOffsetLocalFileName)
2564 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2565 if (dwOffsetHeader)
2566 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2567 if (dwOffsetFileExtension)
2568 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2570 error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA,
2571 (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader));
2572 if (error != ERROR_SUCCESS)
2573 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2575 cleanup:
2576 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2577 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2578 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2580 if (error == ERROR_SUCCESS)
2581 return TRUE;
2582 else
2584 SetLastError(error);
2585 return FALSE;
2589 /***********************************************************************
2590 * CommitUrlCacheEntryA (WININET.@)
2593 BOOL WINAPI CommitUrlCacheEntryA(
2594 IN LPCSTR lpszUrlName,
2595 IN LPCSTR lpszLocalFileName,
2596 IN FILETIME ExpireTime,
2597 IN FILETIME LastModifiedTime,
2598 IN DWORD CacheEntryType,
2599 IN LPBYTE lpHeaderInfo,
2600 IN DWORD dwHeaderSize,
2601 IN LPCSTR lpszFileExtension,
2602 IN LPCSTR lpszOriginalUrl
2605 WCHAR *url_name = NULL;
2606 WCHAR *local_file_name = NULL;
2607 WCHAR *original_url = NULL;
2608 WCHAR *file_extension = NULL;
2609 BOOL bSuccess = FALSE;
2611 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2612 debugstr_a(lpszUrlName),
2613 debugstr_a(lpszLocalFileName),
2614 CacheEntryType,
2615 lpHeaderInfo,
2616 dwHeaderSize,
2617 debugstr_a(lpszFileExtension),
2618 debugstr_a(lpszOriginalUrl));
2620 url_name = heap_strdupAtoW(lpszUrlName);
2621 if (!url_name)
2622 goto cleanup;
2624 if (lpszLocalFileName)
2626 local_file_name = heap_strdupAtoW(lpszLocalFileName);
2627 if (!local_file_name)
2628 goto cleanup;
2630 if (lpszFileExtension)
2632 file_extension = heap_strdupAtoW(lpszFileExtension);
2633 if (!file_extension)
2634 goto cleanup;
2636 if (lpszOriginalUrl)
2638 original_url = heap_strdupAtoW(lpszOriginalUrl);
2639 if (!original_url)
2640 goto cleanup;
2643 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2644 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2645 file_extension, original_url);
2647 cleanup:
2648 HeapFree(GetProcessHeap(), 0, original_url);
2649 HeapFree(GetProcessHeap(), 0, file_extension);
2650 HeapFree(GetProcessHeap(), 0, local_file_name);
2651 HeapFree(GetProcessHeap(), 0, url_name);
2653 return bSuccess;
2656 /***********************************************************************
2657 * CommitUrlCacheEntryW (WININET.@)
2660 BOOL WINAPI CommitUrlCacheEntryW(
2661 IN LPCWSTR lpszUrlName,
2662 IN LPCWSTR lpszLocalFileName,
2663 IN FILETIME ExpireTime,
2664 IN FILETIME LastModifiedTime,
2665 IN DWORD CacheEntryType,
2666 IN LPWSTR lpHeaderInfo,
2667 IN DWORD dwHeaderSize,
2668 IN LPCWSTR lpszFileExtension,
2669 IN LPCWSTR lpszOriginalUrl
2672 DWORD dwError = 0;
2673 BOOL bSuccess = FALSE;
2674 DWORD len = 0;
2675 CHAR *header_info = NULL;
2677 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2678 debugstr_w(lpszUrlName),
2679 debugstr_w(lpszLocalFileName),
2680 CacheEntryType,
2681 lpHeaderInfo,
2682 dwHeaderSize,
2683 debugstr_w(lpszFileExtension),
2684 debugstr_w(lpszOriginalUrl));
2686 if (!lpHeaderInfo || (header_info = heap_strdupWtoA(lpHeaderInfo)))
2688 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2689 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2691 bSuccess = TRUE;
2693 else
2695 dwError = GetLastError();
2697 if (header_info)
2699 HeapFree(GetProcessHeap(), 0, header_info);
2700 if (!bSuccess)
2701 SetLastError(dwError);
2704 return bSuccess;
2707 /***********************************************************************
2708 * ReadUrlCacheEntryStream (WININET.@)
2711 BOOL WINAPI ReadUrlCacheEntryStream(
2712 IN HANDLE hUrlCacheStream,
2713 IN DWORD dwLocation,
2714 IN OUT LPVOID lpBuffer,
2715 IN OUT LPDWORD lpdwLen,
2716 IN DWORD dwReserved
2719 /* Get handle to file from 'stream' */
2720 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2722 if (dwReserved != 0)
2724 ERR("dwReserved != 0\n");
2725 SetLastError(ERROR_INVALID_PARAMETER);
2726 return FALSE;
2729 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2731 SetLastError(ERROR_INVALID_HANDLE);
2732 return FALSE;
2735 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2736 return FALSE;
2737 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2740 /***********************************************************************
2741 * RetrieveUrlCacheEntryStreamA (WININET.@)
2744 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2745 IN LPCSTR lpszUrlName,
2746 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2747 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2748 IN BOOL fRandomRead,
2749 IN DWORD dwReserved
2752 /* NOTE: this is not the same as the way that the native
2753 * version allocates 'stream' handles. I did it this way
2754 * as it is much easier and no applications should depend
2755 * on this behaviour. (Native version appears to allocate
2756 * indices into a table)
2758 STREAM_HANDLE * pStream;
2759 HANDLE hFile;
2761 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2762 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2764 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2765 lpCacheEntryInfo,
2766 lpdwCacheEntryInfoBufferSize,
2767 dwReserved))
2769 return NULL;
2772 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2773 GENERIC_READ,
2774 FILE_SHARE_READ,
2775 NULL,
2776 OPEN_EXISTING,
2777 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2778 NULL);
2779 if (hFile == INVALID_HANDLE_VALUE)
2780 return FALSE;
2782 /* allocate handle storage space */
2783 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2784 if (!pStream)
2786 CloseHandle(hFile);
2787 SetLastError(ERROR_OUTOFMEMORY);
2788 return FALSE;
2791 pStream->hFile = hFile;
2792 strcpy(pStream->lpszUrl, lpszUrlName);
2793 return pStream;
2796 /***********************************************************************
2797 * RetrieveUrlCacheEntryStreamW (WININET.@)
2800 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2801 IN LPCWSTR lpszUrlName,
2802 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2803 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2804 IN BOOL fRandomRead,
2805 IN DWORD dwReserved
2808 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2809 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2810 return NULL;
2813 /***********************************************************************
2814 * UnlockUrlCacheEntryStream (WININET.@)
2817 BOOL WINAPI UnlockUrlCacheEntryStream(
2818 IN HANDLE hUrlCacheStream,
2819 IN DWORD dwReserved
2822 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2824 if (dwReserved != 0)
2826 ERR("dwReserved != 0\n");
2827 SetLastError(ERROR_INVALID_PARAMETER);
2828 return FALSE;
2831 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2833 SetLastError(ERROR_INVALID_HANDLE);
2834 return FALSE;
2837 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2838 return FALSE;
2840 /* close file handle */
2841 CloseHandle(pStream->hFile);
2843 /* free allocated space */
2844 HeapFree(GetProcessHeap(), 0, pStream);
2846 return TRUE;
2850 /***********************************************************************
2851 * DeleteUrlCacheEntryA (WININET.@)
2854 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2856 URLCACHECONTAINER * pContainer;
2857 LPURLCACHE_HEADER pHeader;
2858 struct _HASH_ENTRY * pHashEntry;
2859 CACHEFILE_ENTRY * pEntry;
2860 DWORD error;
2862 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2864 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2865 if (error != ERROR_SUCCESS)
2867 SetLastError(error);
2868 return FALSE;
2871 error = URLCacheContainer_OpenIndex(pContainer);
2872 if (error != ERROR_SUCCESS)
2874 SetLastError(error);
2875 return FALSE;
2878 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2879 return FALSE;
2881 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2883 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2884 TRACE("entry %s not found!\n", lpszUrlName);
2885 SetLastError(ERROR_FILE_NOT_FOUND);
2886 return FALSE;
2889 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2890 URLCache_DeleteEntry(pHeader, pEntry);
2892 URLCache_DeleteEntryFromHash(pHashEntry);
2894 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2896 return TRUE;
2899 /***********************************************************************
2900 * DeleteUrlCacheEntryW (WININET.@)
2903 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2905 URLCACHECONTAINER * pContainer;
2906 LPURLCACHE_HEADER pHeader;
2907 struct _HASH_ENTRY * pHashEntry;
2908 CACHEFILE_ENTRY * pEntry;
2909 LPSTR urlA;
2910 DWORD error;
2912 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2914 urlA = heap_strdupWtoA(lpszUrlName);
2915 if (!urlA)
2917 SetLastError(ERROR_OUTOFMEMORY);
2918 return FALSE;
2921 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2922 if (error != ERROR_SUCCESS)
2924 HeapFree(GetProcessHeap(), 0, urlA);
2925 SetLastError(error);
2926 return FALSE;
2929 error = URLCacheContainer_OpenIndex(pContainer);
2930 if (error != ERROR_SUCCESS)
2932 HeapFree(GetProcessHeap(), 0, urlA);
2933 SetLastError(error);
2934 return FALSE;
2937 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2939 HeapFree(GetProcessHeap(), 0, urlA);
2940 return FALSE;
2943 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
2945 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2946 TRACE("entry %s not found!\n", debugstr_a(urlA));
2947 HeapFree(GetProcessHeap(), 0, urlA);
2948 SetLastError(ERROR_FILE_NOT_FOUND);
2949 return FALSE;
2952 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2953 URLCache_DeleteEntry(pHeader, pEntry);
2955 URLCache_DeleteEntryFromHash(pHashEntry);
2957 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2959 HeapFree(GetProcessHeap(), 0, urlA);
2960 return TRUE;
2963 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2965 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2966 return TRUE;
2969 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2971 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
2972 return TRUE;
2975 /***********************************************************************
2976 * CreateCacheContainerA (WININET.@)
2978 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2979 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2981 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2982 d1, d2, d3, d4, d5, d6, d7, d8);
2983 return TRUE;
2986 /***********************************************************************
2987 * CreateCacheContainerW (WININET.@)
2989 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2990 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2992 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2993 d1, d2, d3, d4, d5, d6, d7, d8);
2994 return TRUE;
2997 /***********************************************************************
2998 * FindFirstUrlCacheContainerA (WININET.@)
3000 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3002 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3003 return NULL;
3006 /***********************************************************************
3007 * FindFirstUrlCacheContainerW (WININET.@)
3009 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3011 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3012 return NULL;
3015 /***********************************************************************
3016 * FindNextUrlCacheContainerA (WININET.@)
3018 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
3020 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3021 return FALSE;
3024 /***********************************************************************
3025 * FindNextUrlCacheContainerW (WININET.@)
3027 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
3029 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3030 return FALSE;
3033 HANDLE WINAPI FindFirstUrlCacheEntryExA(
3034 LPCSTR lpszUrlSearchPattern,
3035 DWORD dwFlags,
3036 DWORD dwFilter,
3037 GROUPID GroupId,
3038 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3039 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3040 LPVOID lpReserved,
3041 LPDWORD pcbReserved2,
3042 LPVOID lpReserved3
3045 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
3046 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3047 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3048 SetLastError(ERROR_FILE_NOT_FOUND);
3049 return NULL;
3052 HANDLE WINAPI FindFirstUrlCacheEntryExW(
3053 LPCWSTR lpszUrlSearchPattern,
3054 DWORD dwFlags,
3055 DWORD dwFilter,
3056 GROUPID GroupId,
3057 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3058 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3059 LPVOID lpReserved,
3060 LPDWORD pcbReserved2,
3061 LPVOID lpReserved3
3064 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
3065 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3066 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3067 SetLastError(ERROR_FILE_NOT_FOUND);
3068 return NULL;
3071 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3073 typedef struct URLCacheFindEntryHandle
3075 DWORD dwMagic;
3076 LPWSTR lpszUrlSearchPattern;
3077 DWORD dwContainerIndex;
3078 DWORD dwHashTableIndex;
3079 DWORD dwHashEntryIndex;
3080 } URLCacheFindEntryHandle;
3082 /***********************************************************************
3083 * FindFirstUrlCacheEntryA (WININET.@)
3086 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
3087 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3089 URLCacheFindEntryHandle *pEntryHandle;
3091 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3093 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3094 if (!pEntryHandle)
3095 return NULL;
3097 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3098 if (lpszUrlSearchPattern)
3100 pEntryHandle->lpszUrlSearchPattern = heap_strdupAtoW(lpszUrlSearchPattern);
3101 if (!pEntryHandle->lpszUrlSearchPattern)
3103 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3104 return NULL;
3107 else
3108 pEntryHandle->lpszUrlSearchPattern = NULL;
3109 pEntryHandle->dwContainerIndex = 0;
3110 pEntryHandle->dwHashTableIndex = 0;
3111 pEntryHandle->dwHashEntryIndex = 0;
3113 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3115 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3116 return NULL;
3118 return pEntryHandle;
3121 /***********************************************************************
3122 * FindFirstUrlCacheEntryW (WININET.@)
3125 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3126 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3128 URLCacheFindEntryHandle *pEntryHandle;
3130 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3132 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3133 if (!pEntryHandle)
3134 return NULL;
3136 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3137 if (lpszUrlSearchPattern)
3139 pEntryHandle->lpszUrlSearchPattern = heap_strdupW(lpszUrlSearchPattern);
3140 if (!pEntryHandle->lpszUrlSearchPattern)
3142 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3143 return NULL;
3146 else
3147 pEntryHandle->lpszUrlSearchPattern = NULL;
3148 pEntryHandle->dwContainerIndex = 0;
3149 pEntryHandle->dwHashTableIndex = 0;
3150 pEntryHandle->dwHashEntryIndex = 0;
3152 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3154 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3155 return NULL;
3157 return pEntryHandle;
3160 /***********************************************************************
3161 * FindNextUrlCacheEntryA (WININET.@)
3163 BOOL WINAPI FindNextUrlCacheEntryA(
3164 HANDLE hEnumHandle,
3165 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3166 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3168 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3169 URLCACHECONTAINER * pContainer;
3171 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3173 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3175 SetLastError(ERROR_INVALID_HANDLE);
3176 return FALSE;
3179 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3180 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3182 LPURLCACHE_HEADER pHeader;
3183 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3184 DWORD error;
3186 error = URLCacheContainer_OpenIndex(pContainer);
3187 if (error != ERROR_SUCCESS)
3189 SetLastError(error);
3190 return FALSE;
3193 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3194 return FALSE;
3196 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3197 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3199 const struct _HASH_ENTRY *pHashEntry = NULL;
3200 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3201 pEntryHandle->dwHashEntryIndex++)
3203 const URL_CACHEFILE_ENTRY *pUrlEntry;
3204 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3206 if (pEntry->dwSignature != URL_SIGNATURE)
3207 continue;
3209 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
3210 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3211 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3213 error = URLCache_CopyEntry(
3214 pContainer,
3215 pHeader,
3216 lpNextCacheEntryInfo,
3217 lpdwNextCacheEntryInfoBufferSize,
3218 pUrlEntry,
3219 FALSE /* not UNICODE */);
3220 if (error != ERROR_SUCCESS)
3222 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3223 SetLastError(error);
3224 return FALSE;
3226 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
3228 /* increment the current index so that next time the function
3229 * is called the next entry is returned */
3230 pEntryHandle->dwHashEntryIndex++;
3231 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3232 return TRUE;
3236 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3239 SetLastError(ERROR_NO_MORE_ITEMS);
3240 return FALSE;
3243 /***********************************************************************
3244 * FindNextUrlCacheEntryW (WININET.@)
3246 BOOL WINAPI FindNextUrlCacheEntryW(
3247 HANDLE hEnumHandle,
3248 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3249 LPDWORD lpdwNextCacheEntryInfoBufferSize
3252 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3253 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3254 return FALSE;
3257 /***********************************************************************
3258 * FindCloseUrlCache (WININET.@)
3260 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3262 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3264 TRACE("(%p)\n", hEnumHandle);
3266 if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3268 SetLastError(ERROR_INVALID_HANDLE);
3269 return FALSE;
3272 pEntryHandle->dwMagic = 0;
3273 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3274 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3276 return TRUE;
3279 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3280 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3282 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3283 dwSearchCondition, lpGroupId, lpReserved);
3284 return NULL;
3287 BOOL WINAPI FindNextUrlCacheEntryExA(
3288 HANDLE hEnumHandle,
3289 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3290 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3291 LPVOID lpReserved,
3292 LPDWORD pcbReserved2,
3293 LPVOID lpReserved3
3296 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3297 lpReserved, pcbReserved2, lpReserved3);
3298 return FALSE;
3301 BOOL WINAPI FindNextUrlCacheEntryExW(
3302 HANDLE hEnumHandle,
3303 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3304 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3305 LPVOID lpReserved,
3306 LPDWORD pcbReserved2,
3307 LPVOID lpReserved3
3310 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3311 lpReserved, pcbReserved2, lpReserved3);
3312 return FALSE;
3315 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3317 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3318 return FALSE;
3321 /***********************************************************************
3322 * CreateUrlCacheGroup (WININET.@)
3325 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3327 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3328 return FALSE;
3331 /***********************************************************************
3332 * DeleteUrlCacheGroup (WININET.@)
3335 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3337 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3338 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3339 return FALSE;
3342 /***********************************************************************
3343 * SetUrlCacheEntryGroupA (WININET.@)
3346 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3347 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3348 LPVOID lpReserved)
3350 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3351 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3352 pbGroupAttributes, cbGroupAttributes, lpReserved);
3353 SetLastError(ERROR_FILE_NOT_FOUND);
3354 return FALSE;
3357 /***********************************************************************
3358 * SetUrlCacheEntryGroupW (WININET.@)
3361 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3362 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3363 LPVOID lpReserved)
3365 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3366 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3367 pbGroupAttributes, cbGroupAttributes, lpReserved);
3368 SetLastError(ERROR_FILE_NOT_FOUND);
3369 return FALSE;
3372 /***********************************************************************
3373 * GetUrlCacheConfigInfoW (WININET.@)
3375 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3377 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3378 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3379 return FALSE;
3382 /***********************************************************************
3383 * GetUrlCacheConfigInfoA (WININET.@)
3385 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3387 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3389 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3390 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3391 return FALSE;
3394 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3395 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3396 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3398 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3399 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3400 lpdwGroupInfo, lpReserved);
3401 return FALSE;
3404 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3405 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3406 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3408 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3409 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3410 lpdwGroupInfo, lpReserved);
3411 return FALSE;
3414 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3415 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3417 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3418 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3419 return TRUE;
3422 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3423 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3425 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3426 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3427 return TRUE;
3430 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3432 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3433 return TRUE;
3436 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3438 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3439 return TRUE;
3442 /***********************************************************************
3443 * DeleteIE3Cache (WININET.@)
3445 * Deletes the files used by the IE3 URL caching system.
3447 * PARAMS
3448 * hWnd [I] A dummy window.
3449 * hInst [I] Instance of process calling the function.
3450 * lpszCmdLine [I] Options used by function.
3451 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3453 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3455 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3456 return 0;
3459 /***********************************************************************
3460 * IsUrlCacheEntryExpiredA (WININET.@)
3462 * PARAMS
3463 * url [I] Url
3464 * dwFlags [I] Unknown
3465 * pftLastModified [O] Last modified time
3467 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3469 LPURLCACHE_HEADER pHeader;
3470 struct _HASH_ENTRY * pHashEntry;
3471 const CACHEFILE_ENTRY * pEntry;
3472 const URL_CACHEFILE_ENTRY * pUrlEntry;
3473 URLCACHECONTAINER * pContainer;
3474 DWORD error;
3476 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3478 error = URLCacheContainers_FindContainerA(url, &pContainer);
3479 if (error != ERROR_SUCCESS)
3481 SetLastError(error);
3482 return FALSE;
3485 error = URLCacheContainer_OpenIndex(pContainer);
3486 if (error != ERROR_SUCCESS)
3488 SetLastError(error);
3489 return FALSE;
3492 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3493 return FALSE;
3495 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3497 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3498 TRACE("entry %s not found!\n", url);
3499 SetLastError(ERROR_FILE_NOT_FOUND);
3500 return FALSE;
3503 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3504 if (pEntry->dwSignature != URL_SIGNATURE)
3506 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3507 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3508 SetLastError(ERROR_FILE_NOT_FOUND);
3509 return FALSE;
3512 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3514 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3516 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3518 return TRUE;
3521 /***********************************************************************
3522 * IsUrlCacheEntryExpiredW (WININET.@)
3524 * PARAMS
3525 * url [I] Url
3526 * dwFlags [I] Unknown
3527 * pftLastModified [O] Last modified time
3529 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3531 LPURLCACHE_HEADER pHeader;
3532 struct _HASH_ENTRY * pHashEntry;
3533 const CACHEFILE_ENTRY * pEntry;
3534 const URL_CACHEFILE_ENTRY * pUrlEntry;
3535 URLCACHECONTAINER * pContainer;
3536 DWORD error;
3538 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3540 error = URLCacheContainers_FindContainerW(url, &pContainer);
3541 if (error != ERROR_SUCCESS)
3543 SetLastError(error);
3544 return FALSE;
3547 error = URLCacheContainer_OpenIndex(pContainer);
3548 if (error != ERROR_SUCCESS)
3550 SetLastError(error);
3551 return FALSE;
3554 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3555 return FALSE;
3557 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3559 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3560 TRACE("entry %s not found!\n", debugstr_w(url));
3561 SetLastError(ERROR_FILE_NOT_FOUND);
3562 return FALSE;
3565 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3566 if (pEntry->dwSignature != URL_SIGNATURE)
3568 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3569 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
3570 SetLastError(ERROR_FILE_NOT_FOUND);
3571 return FALSE;
3574 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3576 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3578 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3580 return TRUE;
3583 /***********************************************************************
3584 * GetDiskInfoA (WININET.@)
3586 BOOL WINAPI GetDiskInfoA(PCSTR path, PDWORD cluster_size, PDWORDLONG free, PDWORDLONG total)
3588 BOOL ret;
3589 ULARGE_INTEGER bytes_free, bytes_total;
3591 TRACE("(%s, %p, %p, %p)\n", debugstr_a(path), cluster_size, free, total);
3593 if (!path)
3595 SetLastError(ERROR_INVALID_PARAMETER);
3596 return FALSE;
3599 if ((ret = GetDiskFreeSpaceExA(path, NULL, &bytes_total, &bytes_free)))
3601 if (cluster_size) *cluster_size = 1;
3602 if (free) *free = bytes_free.QuadPart;
3603 if (total) *total = bytes_total.QuadPart;
3605 return ret;
3608 /***********************************************************************
3609 * RegisterUrlCacheNotification (WININET.@)
3611 DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
3613 FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f);
3614 return 0;
3617 /***********************************************************************
3618 * IncrementUrlCacheHeaderData (WININET.@)
3620 BOOL WINAPI IncrementUrlCacheHeaderData(DWORD index, LPDWORD data)
3622 FIXME("(%u, %p)\n", index, data);
3623 return FALSE;