wininet: Fix off-by-one error.
[wine/multimedia.git] / dlls / wininet / urlcache.c
blobb80f65ea2f2a38b3c7a0385ed35debb665e15f4f
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, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0);
990 else
991 lenUrl = strlen((LPCSTR)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, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
1002 else
1003 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPCSTR)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, (LPCSTR)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, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, NULL, 0);
1045 else
1046 lenExtension = strlen((LPCSTR)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, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenExtension);
1054 else
1055 memcpy(lpCacheEntryInfo->lpszFileExtension, (LPCSTR)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 FileTimeToDosDateTime(&lpCacheEntryInfo->ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
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)((const BYTE*)pHashEntry - (const BYTE*)pHeader) >= ENTRY_START_OFFSET) &&
1179 ((DWORD)((const BYTE*)pHashEntry - (const BYTE*)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 * FreeUrlCacheSpaceA (WININET.@)
1455 BOOL WINAPI FreeUrlCacheSpaceA(LPCSTR lpszCachePath, DWORD dwSize, DWORD dwFilter)
1457 FIXME("stub!\n");
1458 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1459 return FALSE;
1462 /***********************************************************************
1463 * FreeUrlCacheSpaceW (WININET.@)
1466 BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR lpszCachePath, DWORD dwSize, DWORD dwFilter)
1468 FIXME("stub!\n");
1469 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1470 return FALSE;
1473 /***********************************************************************
1474 * GetUrlCacheEntryInfoExA (WININET.@)
1477 BOOL WINAPI GetUrlCacheEntryInfoExA(
1478 LPCSTR lpszUrl,
1479 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1480 LPDWORD lpdwCacheEntryInfoBufSize,
1481 LPSTR lpszReserved,
1482 LPDWORD lpdwReserved,
1483 LPVOID lpReserved,
1484 DWORD dwFlags)
1486 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1487 debugstr_a(lpszUrl),
1488 lpCacheEntryInfo,
1489 lpdwCacheEntryInfoBufSize,
1490 lpszReserved,
1491 lpdwReserved,
1492 lpReserved,
1493 dwFlags);
1495 if ((lpszReserved != NULL) ||
1496 (lpdwReserved != NULL) ||
1497 (lpReserved != NULL))
1499 ERR("Reserved value was not 0\n");
1500 SetLastError(ERROR_INVALID_PARAMETER);
1501 return FALSE;
1503 if (dwFlags != 0)
1505 FIXME("Undocumented flag(s): %x\n", dwFlags);
1506 SetLastError(ERROR_FILE_NOT_FOUND);
1507 return FALSE;
1509 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1512 /***********************************************************************
1513 * GetUrlCacheEntryInfoA (WININET.@)
1516 BOOL WINAPI GetUrlCacheEntryInfoA(
1517 IN LPCSTR lpszUrlName,
1518 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1519 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1522 LPURLCACHE_HEADER pHeader;
1523 struct _HASH_ENTRY * pHashEntry;
1524 const CACHEFILE_ENTRY * pEntry;
1525 const URL_CACHEFILE_ENTRY * pUrlEntry;
1526 URLCACHECONTAINER * pContainer;
1527 DWORD error;
1529 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1531 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1532 if (error != ERROR_SUCCESS)
1534 SetLastError(error);
1535 return FALSE;
1538 error = URLCacheContainer_OpenIndex(pContainer);
1539 if (error != ERROR_SUCCESS)
1541 SetLastError(error);
1542 return FALSE;
1545 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1546 return FALSE;
1548 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1550 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1551 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1552 SetLastError(ERROR_FILE_NOT_FOUND);
1553 return FALSE;
1556 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1557 if (pEntry->dwSignature != URL_SIGNATURE)
1559 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1560 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD)));
1561 SetLastError(ERROR_FILE_NOT_FOUND);
1562 return FALSE;
1565 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1566 TRACE("Found URL: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1567 if (pUrlEntry->dwOffsetHeaderInfo)
1568 TRACE("Header info: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1570 if (lpdwCacheEntryInfoBufferSize)
1572 if (!lpCacheEntryInfo)
1573 *lpdwCacheEntryInfoBufferSize = 0;
1575 error = URLCache_CopyEntry(
1576 pContainer,
1577 pHeader,
1578 lpCacheEntryInfo,
1579 lpdwCacheEntryInfoBufferSize,
1580 pUrlEntry,
1581 FALSE /* ANSI */);
1582 if (error != ERROR_SUCCESS)
1584 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1585 SetLastError(error);
1586 return FALSE;
1588 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1591 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1593 return TRUE;
1596 /***********************************************************************
1597 * GetUrlCacheEntryInfoW (WININET.@)
1600 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1601 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1602 LPDWORD lpdwCacheEntryInfoBufferSize)
1604 LPURLCACHE_HEADER pHeader;
1605 struct _HASH_ENTRY * pHashEntry;
1606 const CACHEFILE_ENTRY * pEntry;
1607 const URL_CACHEFILE_ENTRY * pUrlEntry;
1608 URLCACHECONTAINER * pContainer;
1609 DWORD error;
1611 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1613 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1614 if (error != ERROR_SUCCESS)
1616 SetLastError(error);
1617 return FALSE;
1620 error = URLCacheContainer_OpenIndex(pContainer);
1621 if (error != ERROR_SUCCESS)
1623 SetLastError(error);
1624 return FALSE;
1627 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1628 return FALSE;
1630 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1632 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1633 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1634 SetLastError(ERROR_FILE_NOT_FOUND);
1635 return FALSE;
1638 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1639 if (pEntry->dwSignature != URL_SIGNATURE)
1641 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1642 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD)));
1643 SetLastError(ERROR_FILE_NOT_FOUND);
1644 return FALSE;
1647 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
1648 TRACE("Found URL: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl));
1649 TRACE("Header info: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1651 if (lpdwCacheEntryInfoBufferSize)
1653 if (!lpCacheEntryInfo)
1654 *lpdwCacheEntryInfoBufferSize = 0;
1656 error = URLCache_CopyEntry(
1657 pContainer,
1658 pHeader,
1659 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1660 lpdwCacheEntryInfoBufferSize,
1661 pUrlEntry,
1662 TRUE /* UNICODE */);
1663 if (error != ERROR_SUCCESS)
1665 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1666 SetLastError(error);
1667 return FALSE;
1669 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1672 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1674 return TRUE;
1677 /***********************************************************************
1678 * GetUrlCacheEntryInfoExW (WININET.@)
1681 BOOL WINAPI GetUrlCacheEntryInfoExW(
1682 LPCWSTR lpszUrl,
1683 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1684 LPDWORD lpdwCacheEntryInfoBufSize,
1685 LPWSTR lpszReserved,
1686 LPDWORD lpdwReserved,
1687 LPVOID lpReserved,
1688 DWORD dwFlags)
1690 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1691 debugstr_w(lpszUrl),
1692 lpCacheEntryInfo,
1693 lpdwCacheEntryInfoBufSize,
1694 lpszReserved,
1695 lpdwReserved,
1696 lpReserved,
1697 dwFlags);
1699 if ((lpszReserved != NULL) ||
1700 (lpdwReserved != NULL) ||
1701 (lpReserved != NULL))
1703 ERR("Reserved value was not 0\n");
1704 SetLastError(ERROR_INVALID_PARAMETER);
1705 return FALSE;
1707 if (dwFlags != 0)
1709 FIXME("Undocumented flag(s): %x\n", dwFlags);
1710 SetLastError(ERROR_FILE_NOT_FOUND);
1711 return FALSE;
1713 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1716 /***********************************************************************
1717 * SetUrlCacheEntryInfoA (WININET.@)
1719 BOOL WINAPI SetUrlCacheEntryInfoA(
1720 LPCSTR lpszUrlName,
1721 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1722 DWORD dwFieldControl)
1724 LPURLCACHE_HEADER pHeader;
1725 struct _HASH_ENTRY * pHashEntry;
1726 CACHEFILE_ENTRY * pEntry;
1727 URLCACHECONTAINER * pContainer;
1728 DWORD error;
1730 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1732 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1733 if (error != ERROR_SUCCESS)
1735 SetLastError(error);
1736 return FALSE;
1739 error = URLCacheContainer_OpenIndex(pContainer);
1740 if (error != ERROR_SUCCESS)
1742 SetLastError(error);
1743 return FALSE;
1746 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1747 return FALSE;
1749 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1751 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1752 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1753 SetLastError(ERROR_FILE_NOT_FOUND);
1754 return FALSE;
1757 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1758 if (pEntry->dwSignature != URL_SIGNATURE)
1760 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1761 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1762 SetLastError(ERROR_FILE_NOT_FOUND);
1763 return FALSE;
1766 URLCache_SetEntryInfo(
1767 (URL_CACHEFILE_ENTRY *)pEntry,
1768 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1769 dwFieldControl);
1771 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1773 return TRUE;
1776 /***********************************************************************
1777 * SetUrlCacheEntryInfoW (WININET.@)
1779 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1781 LPURLCACHE_HEADER pHeader;
1782 struct _HASH_ENTRY * pHashEntry;
1783 CACHEFILE_ENTRY * pEntry;
1784 URLCACHECONTAINER * pContainer;
1785 DWORD error;
1787 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1789 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer);
1790 if (error != ERROR_SUCCESS)
1792 SetLastError(error);
1793 return FALSE;
1796 error = URLCacheContainer_OpenIndex(pContainer);
1797 if (error != ERROR_SUCCESS)
1799 SetLastError(error);
1800 return FALSE;
1803 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1804 return FALSE;
1806 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry))
1808 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1809 WARN("entry %s not found!\n", debugstr_w(lpszUrl));
1810 SetLastError(ERROR_FILE_NOT_FOUND);
1811 return FALSE;
1814 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1815 if (pEntry->dwSignature != URL_SIGNATURE)
1817 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1818 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1819 SetLastError(ERROR_FILE_NOT_FOUND);
1820 return FALSE;
1823 URLCache_SetEntryInfo(
1824 (URL_CACHEFILE_ENTRY *)pEntry,
1825 lpCacheEntryInfo,
1826 dwFieldControl);
1828 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1830 return TRUE;
1833 /***********************************************************************
1834 * RetrieveUrlCacheEntryFileA (WININET.@)
1837 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1838 IN LPCSTR lpszUrlName,
1839 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1840 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1841 IN DWORD dwReserved
1844 LPURLCACHE_HEADER pHeader;
1845 struct _HASH_ENTRY * pHashEntry;
1846 CACHEFILE_ENTRY * pEntry;
1847 URL_CACHEFILE_ENTRY * pUrlEntry;
1848 URLCACHECONTAINER * pContainer;
1849 DWORD error;
1851 TRACE("(%s, %p, %p, 0x%08x)\n",
1852 debugstr_a(lpszUrlName),
1853 lpCacheEntryInfo,
1854 lpdwCacheEntryInfoBufferSize,
1855 dwReserved);
1857 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1858 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1860 SetLastError(ERROR_INVALID_PARAMETER);
1861 return FALSE;
1864 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
1865 if (error != ERROR_SUCCESS)
1867 SetLastError(error);
1868 return FALSE;
1871 error = URLCacheContainer_OpenIndex(pContainer);
1872 if (error != ERROR_SUCCESS)
1874 SetLastError(error);
1875 return FALSE;
1878 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1879 return FALSE;
1881 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
1883 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1884 TRACE("entry %s not found!\n", lpszUrlName);
1885 SetLastError(ERROR_FILE_NOT_FOUND);
1886 return FALSE;
1889 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1890 if (pEntry->dwSignature != URL_SIGNATURE)
1892 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1893 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1894 SetLastError(ERROR_FILE_NOT_FOUND);
1895 return FALSE;
1898 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1899 if (!pUrlEntry->dwOffsetLocalName)
1901 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1902 SetLastError(ERROR_INVALID_DATA);
1903 return FALSE;
1906 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
1907 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1909 pUrlEntry->dwHitRate++;
1910 pUrlEntry->dwUseCount++;
1911 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
1913 error = URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo,
1914 lpdwCacheEntryInfoBufferSize, pUrlEntry,
1915 FALSE);
1916 if (error != ERROR_SUCCESS)
1918 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1919 SetLastError(error);
1920 return FALSE;
1922 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
1924 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1926 return TRUE;
1929 /***********************************************************************
1930 * RetrieveUrlCacheEntryFileW (WININET.@)
1933 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1934 IN LPCWSTR lpszUrlName,
1935 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1936 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1937 IN DWORD dwReserved
1940 LPURLCACHE_HEADER pHeader;
1941 struct _HASH_ENTRY * pHashEntry;
1942 CACHEFILE_ENTRY * pEntry;
1943 URL_CACHEFILE_ENTRY * pUrlEntry;
1944 URLCACHECONTAINER * pContainer;
1945 DWORD error;
1947 TRACE("(%s, %p, %p, 0x%08x)\n",
1948 debugstr_w(lpszUrlName),
1949 lpCacheEntryInfo,
1950 lpdwCacheEntryInfoBufferSize,
1951 dwReserved);
1953 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize ||
1954 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize))
1956 SetLastError(ERROR_INVALID_PARAMETER);
1957 return FALSE;
1960 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
1961 if (error != ERROR_SUCCESS)
1963 SetLastError(error);
1964 return FALSE;
1967 error = URLCacheContainer_OpenIndex(pContainer);
1968 if (error != ERROR_SUCCESS)
1970 SetLastError(error);
1971 return FALSE;
1974 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1975 return FALSE;
1977 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
1979 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1980 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
1981 SetLastError(ERROR_FILE_NOT_FOUND);
1982 return FALSE;
1985 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1986 if (pEntry->dwSignature != URL_SIGNATURE)
1988 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1989 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1990 SetLastError(ERROR_FILE_NOT_FOUND);
1991 return FALSE;
1994 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1995 if (!pUrlEntry->dwOffsetLocalName)
1997 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1998 SetLastError(ERROR_INVALID_DATA);
1999 return FALSE;
2002 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
2003 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
2005 pUrlEntry->dwHitRate++;
2006 pUrlEntry->dwUseCount++;
2007 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2009 error = URLCache_CopyEntry(
2010 pContainer,
2011 pHeader,
2012 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
2013 lpdwCacheEntryInfoBufferSize,
2014 pUrlEntry,
2015 TRUE /* UNICODE */);
2016 if (error != ERROR_SUCCESS)
2018 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2019 SetLastError(error);
2020 return FALSE;
2022 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
2024 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2026 return TRUE;
2029 /***********************************************************************
2030 * UnlockUrlCacheEntryFileA (WININET.@)
2033 BOOL WINAPI UnlockUrlCacheEntryFileA(
2034 IN LPCSTR lpszUrlName,
2035 IN DWORD dwReserved
2038 LPURLCACHE_HEADER pHeader;
2039 struct _HASH_ENTRY * pHashEntry;
2040 CACHEFILE_ENTRY * pEntry;
2041 URL_CACHEFILE_ENTRY * pUrlEntry;
2042 URLCACHECONTAINER * pContainer;
2043 DWORD error;
2045 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
2047 if (dwReserved)
2049 ERR("dwReserved != 0\n");
2050 SetLastError(ERROR_INVALID_PARAMETER);
2051 return FALSE;
2054 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2055 if (error != ERROR_SUCCESS)
2057 SetLastError(error);
2058 return FALSE;
2061 error = URLCacheContainer_OpenIndex(pContainer);
2062 if (error != ERROR_SUCCESS)
2064 SetLastError(error);
2065 return FALSE;
2068 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2069 return FALSE;
2071 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2073 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2074 TRACE("entry %s not found!\n", lpszUrlName);
2075 SetLastError(ERROR_FILE_NOT_FOUND);
2076 return FALSE;
2079 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2080 if (pEntry->dwSignature != URL_SIGNATURE)
2082 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2083 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2084 SetLastError(ERROR_FILE_NOT_FOUND);
2085 return FALSE;
2088 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2090 if (pUrlEntry->dwUseCount == 0)
2092 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2093 return FALSE;
2095 pUrlEntry->dwUseCount--;
2096 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2098 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2100 return TRUE;
2103 /***********************************************************************
2104 * UnlockUrlCacheEntryFileW (WININET.@)
2107 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
2109 LPURLCACHE_HEADER pHeader;
2110 struct _HASH_ENTRY * pHashEntry;
2111 CACHEFILE_ENTRY * pEntry;
2112 URL_CACHEFILE_ENTRY * pUrlEntry;
2113 URLCACHECONTAINER * pContainer;
2114 DWORD error;
2116 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved);
2118 if (dwReserved)
2120 ERR("dwReserved != 0\n");
2121 SetLastError(ERROR_INVALID_PARAMETER);
2122 return FALSE;
2125 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2126 if (error != ERROR_SUCCESS)
2128 SetLastError(error);
2129 return FALSE;
2132 error = URLCacheContainer_OpenIndex(pContainer);
2133 if (error != ERROR_SUCCESS)
2135 SetLastError(error);
2136 return FALSE;
2139 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2140 return FALSE;
2142 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry))
2144 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2145 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName));
2146 SetLastError(ERROR_FILE_NOT_FOUND);
2147 return FALSE;
2150 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2151 if (pEntry->dwSignature != URL_SIGNATURE)
2153 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2154 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
2155 SetLastError(ERROR_FILE_NOT_FOUND);
2156 return FALSE;
2159 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2161 if (pUrlEntry->dwUseCount == 0)
2163 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2164 return FALSE;
2166 pUrlEntry->dwUseCount--;
2167 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount);
2169 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2171 return TRUE;
2174 /***********************************************************************
2175 * CreateUrlCacheEntryA (WININET.@)
2178 BOOL WINAPI CreateUrlCacheEntryA(
2179 IN LPCSTR lpszUrlName,
2180 IN DWORD dwExpectedFileSize,
2181 IN LPCSTR lpszFileExtension,
2182 OUT LPSTR lpszFileName,
2183 IN DWORD dwReserved
2186 WCHAR *url_name;
2187 WCHAR *file_extension = NULL;
2188 WCHAR file_name[MAX_PATH];
2189 BOOL bSuccess = FALSE;
2190 DWORD dwError = 0;
2192 TRACE("(%s %d %s %p %d)\n", debugstr_a(lpszUrlName), dwExpectedFileSize,
2193 debugstr_a(lpszFileExtension), lpszFileName, dwReserved);
2195 if (lpszUrlName && (url_name = heap_strdupAtoW(lpszUrlName)))
2197 if (!lpszFileExtension || (file_extension = heap_strdupAtoW(lpszFileExtension)))
2199 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
2201 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
2203 bSuccess = TRUE;
2205 else
2207 dwError = GetLastError();
2210 else
2212 dwError = GetLastError();
2214 HeapFree(GetProcessHeap(), 0, file_extension);
2216 else
2218 dwError = GetLastError();
2220 HeapFree(GetProcessHeap(), 0, url_name);
2221 if (!bSuccess)
2222 SetLastError(dwError);
2224 return bSuccess;
2226 /***********************************************************************
2227 * CreateUrlCacheEntryW (WININET.@)
2230 BOOL WINAPI CreateUrlCacheEntryW(
2231 IN LPCWSTR lpszUrlName,
2232 IN DWORD dwExpectedFileSize,
2233 IN LPCWSTR lpszFileExtension,
2234 OUT LPWSTR lpszFileName,
2235 IN DWORD dwReserved
2238 URLCACHECONTAINER * pContainer;
2239 LPURLCACHE_HEADER pHeader;
2240 CHAR szFile[MAX_PATH];
2241 WCHAR szExtension[MAX_PATH];
2242 LPCWSTR lpszUrlPart;
2243 LPCWSTR lpszUrlEnd;
2244 LPCWSTR lpszFileNameExtension;
2245 LPWSTR lpszFileNameNoPath;
2246 int i;
2247 int countnoextension;
2248 BYTE CacheDir;
2249 LONG lBufferSize;
2250 BOOL bFound = FALSE;
2251 int count;
2252 DWORD error;
2253 HANDLE hFile;
2254 FILETIME ft;
2256 static const WCHAR szWWW[] = {'w','w','w',0};
2257 static const WCHAR fmt[] = {'%','0','8','X','%','s',0};
2259 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2260 debugstr_w(lpszUrlName),
2261 dwExpectedFileSize,
2262 debugstr_w(lpszFileExtension),
2263 lpszFileName,
2264 dwReserved);
2266 if (dwReserved)
2267 FIXME("dwReserved 0x%08x\n", dwReserved);
2269 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName);
2271 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
2272 lpszUrlEnd--;
2274 lpszUrlPart = memchrW(lpszUrlName, '?', lpszUrlEnd - lpszUrlName);
2275 if (!lpszUrlPart)
2276 lpszUrlPart = memchrW(lpszUrlName, '#', lpszUrlEnd - lpszUrlName);
2277 if (lpszUrlPart)
2278 lpszUrlEnd = lpszUrlPart;
2280 for (lpszUrlPart = lpszUrlEnd;
2281 (lpszUrlPart >= lpszUrlName);
2282 lpszUrlPart--)
2284 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
2286 bFound = TRUE;
2287 lpszUrlPart++;
2288 break;
2291 if (!lstrcmpW(lpszUrlPart, szWWW))
2293 lpszUrlPart += lstrlenW(szWWW);
2296 count = lpszUrlEnd - lpszUrlPart;
2298 if (bFound && (count < MAX_PATH))
2300 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
2301 if (!len)
2302 return FALSE;
2303 szFile[len] = '\0';
2304 while(len && szFile[--len] == '/') szFile[len] = '\0';
2306 /* FIXME: get rid of illegal characters like \, / and : */
2308 else
2310 FIXME("need to generate a random filename\n");
2313 TRACE("File name: %s\n", debugstr_a(szFile));
2315 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2316 if (error != ERROR_SUCCESS)
2318 SetLastError(error);
2319 return FALSE;
2322 error = URLCacheContainer_OpenIndex(pContainer);
2323 if (error != ERROR_SUCCESS)
2325 SetLastError(error);
2326 return FALSE;
2329 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2330 return FALSE;
2332 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
2334 lBufferSize = MAX_PATH * sizeof(WCHAR);
2335 if (!URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize))
2337 WARN("Failed to get full path for filename %s, needed %u bytes.\n",
2338 debugstr_a(szFile), lBufferSize);
2339 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2340 return FALSE;
2343 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2345 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2;
2346 lpszFileNameNoPath >= lpszFileName;
2347 --lpszFileNameNoPath)
2349 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
2350 break;
2353 countnoextension = lstrlenW(lpszFileNameNoPath);
2354 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
2355 if (lpszFileNameExtension)
2356 countnoextension -= lstrlenW(lpszFileNameExtension);
2357 *szExtension = '\0';
2359 if (lpszFileExtension)
2361 szExtension[0] = '.';
2362 lstrcpyW(szExtension+1, lpszFileExtension);
2365 for (i = 0; i < 255; i++)
2367 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0};
2368 WCHAR *p;
2370 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
2371 for (p = lpszFileNameNoPath + 1; *p; p++)
2373 switch (*p)
2375 case '<': case '>':
2376 case ':': case '"':
2377 case '/': case '\\':
2378 case '|': case '?':
2379 case '*':
2380 *p = '_'; break;
2381 default: break;
2384 if (p[-1] == ' ' || p[-1] == '.') p[-1] = '_';
2386 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2387 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2388 if (hFile != INVALID_HANDLE_VALUE)
2390 CloseHandle(hFile);
2391 return TRUE;
2395 GetSystemTimeAsFileTime(&ft);
2396 wsprintfW(lpszFileNameNoPath + countnoextension, fmt, ft.dwLowDateTime, szExtension);
2398 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
2399 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2400 if (hFile != INVALID_HANDLE_VALUE)
2402 CloseHandle(hFile);
2403 return TRUE;
2406 WARN("Could not find a unique filename\n");
2407 return FALSE;
2411 /***********************************************************************
2412 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2414 * The bug we are compensating for is that some drongo at Microsoft
2415 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2416 * As a consequence, CommitUrlCacheEntryA has been effectively
2417 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2418 * is still defined as LPCWSTR. The result (other than madness) is
2419 * that we always need to store lpHeaderInfo in CP_ACP rather than
2420 * in UTF16, and we need to avoid converting lpHeaderInfo in
2421 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2422 * result will lose data for arbitrary binary data.
2425 static BOOL CommitUrlCacheEntryInternal(
2426 IN LPCWSTR lpszUrlName,
2427 IN LPCWSTR lpszLocalFileName,
2428 IN FILETIME ExpireTime,
2429 IN FILETIME LastModifiedTime,
2430 IN DWORD CacheEntryType,
2431 IN LPBYTE lpHeaderInfo,
2432 IN DWORD dwHeaderSize,
2433 IN LPCWSTR lpszFileExtension,
2434 IN LPCWSTR lpszOriginalUrl
2437 URLCACHECONTAINER * pContainer;
2438 LPURLCACHE_HEADER pHeader;
2439 struct _HASH_ENTRY * pHashEntry;
2440 CACHEFILE_ENTRY * pEntry;
2441 URL_CACHEFILE_ENTRY * pUrlEntry;
2442 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry));
2443 DWORD dwOffsetLocalFileName = 0;
2444 DWORD dwOffsetHeader = 0;
2445 DWORD dwOffsetFileExtension = 0;
2446 DWORD dwFileSizeLow = 0;
2447 DWORD dwFileSizeHigh = 0;
2448 BYTE cDirectory = 0;
2449 char achFile[MAX_PATH];
2450 LPSTR lpszUrlNameA = NULL;
2451 LPSTR lpszFileExtensionA = NULL;
2452 char *pchLocalFileName = 0;
2453 DWORD error;
2455 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2456 debugstr_w(lpszUrlName),
2457 debugstr_w(lpszLocalFileName),
2458 CacheEntryType,
2459 lpHeaderInfo,
2460 dwHeaderSize,
2461 debugstr_w(lpszFileExtension),
2462 debugstr_w(lpszOriginalUrl));
2464 if (lpszOriginalUrl)
2465 WARN(": lpszOriginalUrl ignored\n");
2467 if (lpszLocalFileName)
2469 HANDLE hFile;
2471 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2472 if (hFile == INVALID_HANDLE_VALUE)
2474 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError());
2475 return FALSE;
2478 /* Get file size */
2479 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2480 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2482 ERR("couldn't get file size (error is %d)\n", GetLastError());
2483 CloseHandle(hFile);
2484 return FALSE;
2487 CloseHandle(hFile);
2490 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2491 if (error != ERROR_SUCCESS)
2493 SetLastError(error);
2494 return FALSE;
2497 error = URLCacheContainer_OpenIndex(pContainer);
2498 if (error != ERROR_SUCCESS)
2500 SetLastError(error);
2501 return FALSE;
2504 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2505 return FALSE;
2507 lpszUrlNameA = heap_strdupWtoA(lpszUrlName);
2508 if (!lpszUrlNameA)
2510 error = GetLastError();
2511 goto cleanup;
2514 if (lpszFileExtension && !(lpszFileExtensionA = heap_strdupWtoA(lpszFileExtension)))
2516 error = GetLastError();
2517 goto cleanup;
2520 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry))
2522 FIXME("entry already in cache - don't know what to do!\n");
2524 * SetLastError(ERROR_FILE_NOT_FOUND);
2525 * return FALSE;
2527 goto cleanup;
2530 if (lpszLocalFileName)
2532 BOOL bFound = FALSE;
2534 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2536 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2537 error = ERROR_INVALID_PARAMETER;
2538 goto cleanup;
2541 /* skip container path prefix */
2542 lpszLocalFileName += lstrlenW(pContainer->path);
2544 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL);
2545 pchLocalFileName = achFile;
2547 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2549 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2551 bFound = TRUE;
2552 break;
2556 if (!bFound)
2558 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2559 error = ERROR_INVALID_PARAMETER;
2560 goto cleanup;
2563 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2566 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1);
2567 if (lpszLocalFileName)
2569 dwOffsetLocalFileName = dwBytesNeeded;
2570 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2572 if (lpHeaderInfo)
2574 dwOffsetHeader = dwBytesNeeded;
2575 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2577 if (lpszFileExtensionA)
2579 dwOffsetFileExtension = dwBytesNeeded;
2580 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1);
2583 /* round up to next block */
2584 if (dwBytesNeeded % BLOCKSIZE)
2586 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2587 dwBytesNeeded += BLOCKSIZE;
2590 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2592 ERR("no free entries\n");
2593 error = ERROR_DISK_FULL;
2594 goto cleanup;
2597 /* FindFirstFreeEntry fills in blocks used */
2598 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2599 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2600 pUrlEntry->CacheDir = cDirectory;
2601 pUrlEntry->CacheEntryType = CacheEntryType;
2602 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2603 pUrlEntry->dwExemptDelta = 0;
2604 pUrlEntry->dwHitRate = 0;
2605 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension;
2606 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2607 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2608 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry));
2609 pUrlEntry->dwSizeHigh = 0;
2610 pUrlEntry->dwSizeLow = dwFileSizeLow;
2611 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2612 pUrlEntry->dwUseCount = 0;
2613 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2614 pUrlEntry->LastModifiedTime = LastModifiedTime;
2615 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2616 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2617 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2618 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2620 /*** Unknowns ***/
2621 pUrlEntry->dwUnknown1 = 0;
2622 pUrlEntry->dwUnknown2 = 0;
2623 pUrlEntry->dwUnknown3 = 0x60;
2624 pUrlEntry->Unknown4 = 0;
2625 pUrlEntry->wUnknown5 = 0x1010;
2626 pUrlEntry->dwUnknown7 = 0;
2627 pUrlEntry->dwUnknown8 = 0;
2630 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA);
2631 if (dwOffsetLocalFileName)
2632 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1);
2633 if (dwOffsetHeader)
2634 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2635 if (dwOffsetFileExtension)
2636 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA);
2638 error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA,
2639 (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader));
2640 if (error != ERROR_SUCCESS)
2641 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry);
2643 cleanup:
2644 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2645 HeapFree(GetProcessHeap(), 0, lpszUrlNameA);
2646 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA);
2648 if (error == ERROR_SUCCESS)
2649 return TRUE;
2650 else
2652 SetLastError(error);
2653 return FALSE;
2657 /***********************************************************************
2658 * CommitUrlCacheEntryA (WININET.@)
2661 BOOL WINAPI CommitUrlCacheEntryA(
2662 IN LPCSTR lpszUrlName,
2663 IN LPCSTR lpszLocalFileName,
2664 IN FILETIME ExpireTime,
2665 IN FILETIME LastModifiedTime,
2666 IN DWORD CacheEntryType,
2667 IN LPBYTE lpHeaderInfo,
2668 IN DWORD dwHeaderSize,
2669 IN LPCSTR lpszFileExtension,
2670 IN LPCSTR lpszOriginalUrl
2673 WCHAR *url_name = NULL;
2674 WCHAR *local_file_name = NULL;
2675 WCHAR *original_url = NULL;
2676 WCHAR *file_extension = NULL;
2677 BOOL bSuccess = FALSE;
2679 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2680 debugstr_a(lpszUrlName),
2681 debugstr_a(lpszLocalFileName),
2682 CacheEntryType,
2683 lpHeaderInfo,
2684 dwHeaderSize,
2685 debugstr_a(lpszFileExtension),
2686 debugstr_a(lpszOriginalUrl));
2688 url_name = heap_strdupAtoW(lpszUrlName);
2689 if (!url_name)
2690 goto cleanup;
2692 if (lpszLocalFileName)
2694 local_file_name = heap_strdupAtoW(lpszLocalFileName);
2695 if (!local_file_name)
2696 goto cleanup;
2698 if (lpszFileExtension)
2700 file_extension = heap_strdupAtoW(lpszFileExtension);
2701 if (!file_extension)
2702 goto cleanup;
2704 if (lpszOriginalUrl)
2706 original_url = heap_strdupAtoW(lpszOriginalUrl);
2707 if (!original_url)
2708 goto cleanup;
2711 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2712 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2713 file_extension, original_url);
2715 cleanup:
2716 HeapFree(GetProcessHeap(), 0, original_url);
2717 HeapFree(GetProcessHeap(), 0, file_extension);
2718 HeapFree(GetProcessHeap(), 0, local_file_name);
2719 HeapFree(GetProcessHeap(), 0, url_name);
2721 return bSuccess;
2724 /***********************************************************************
2725 * CommitUrlCacheEntryW (WININET.@)
2728 BOOL WINAPI CommitUrlCacheEntryW(
2729 IN LPCWSTR lpszUrlName,
2730 IN LPCWSTR lpszLocalFileName,
2731 IN FILETIME ExpireTime,
2732 IN FILETIME LastModifiedTime,
2733 IN DWORD CacheEntryType,
2734 IN LPWSTR lpHeaderInfo,
2735 IN DWORD dwHeaderSize,
2736 IN LPCWSTR lpszFileExtension,
2737 IN LPCWSTR lpszOriginalUrl
2740 DWORD dwError = 0;
2741 BOOL bSuccess = FALSE;
2742 DWORD len = 0;
2743 CHAR *header_info = NULL;
2745 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2746 debugstr_w(lpszUrlName),
2747 debugstr_w(lpszLocalFileName),
2748 CacheEntryType,
2749 lpHeaderInfo,
2750 dwHeaderSize,
2751 debugstr_w(lpszFileExtension),
2752 debugstr_w(lpszOriginalUrl));
2754 if (!lpHeaderInfo || (header_info = heap_strdupWtoA(lpHeaderInfo)))
2756 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2757 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl))
2759 bSuccess = TRUE;
2761 else
2763 dwError = GetLastError();
2765 if (header_info)
2767 HeapFree(GetProcessHeap(), 0, header_info);
2768 if (!bSuccess)
2769 SetLastError(dwError);
2772 return bSuccess;
2775 /***********************************************************************
2776 * ReadUrlCacheEntryStream (WININET.@)
2779 BOOL WINAPI ReadUrlCacheEntryStream(
2780 IN HANDLE hUrlCacheStream,
2781 IN DWORD dwLocation,
2782 IN OUT LPVOID lpBuffer,
2783 IN OUT LPDWORD lpdwLen,
2784 IN DWORD dwReserved
2787 /* Get handle to file from 'stream' */
2788 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2790 if (dwReserved != 0)
2792 ERR("dwReserved != 0\n");
2793 SetLastError(ERROR_INVALID_PARAMETER);
2794 return FALSE;
2797 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2799 SetLastError(ERROR_INVALID_HANDLE);
2800 return FALSE;
2803 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2804 return FALSE;
2805 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2808 /***********************************************************************
2809 * RetrieveUrlCacheEntryStreamA (WININET.@)
2812 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2813 IN LPCSTR lpszUrlName,
2814 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2815 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2816 IN BOOL fRandomRead,
2817 IN DWORD dwReserved
2820 /* NOTE: this is not the same as the way that the native
2821 * version allocates 'stream' handles. I did it this way
2822 * as it is much easier and no applications should depend
2823 * on this behaviour. (Native version appears to allocate
2824 * indices into a table)
2826 STREAM_HANDLE * pStream;
2827 HANDLE hFile;
2829 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2830 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2832 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2833 lpCacheEntryInfo,
2834 lpdwCacheEntryInfoBufferSize,
2835 dwReserved))
2837 return NULL;
2840 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2841 GENERIC_READ,
2842 FILE_SHARE_READ,
2843 NULL,
2844 OPEN_EXISTING,
2845 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2846 NULL);
2847 if (hFile == INVALID_HANDLE_VALUE)
2848 return FALSE;
2850 /* allocate handle storage space */
2851 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2852 if (!pStream)
2854 CloseHandle(hFile);
2855 SetLastError(ERROR_OUTOFMEMORY);
2856 return FALSE;
2859 pStream->hFile = hFile;
2860 strcpy(pStream->lpszUrl, lpszUrlName);
2861 return pStream;
2864 /***********************************************************************
2865 * RetrieveUrlCacheEntryStreamW (WININET.@)
2868 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2869 IN LPCWSTR lpszUrlName,
2870 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2871 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2872 IN BOOL fRandomRead,
2873 IN DWORD dwReserved
2876 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2877 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2878 return NULL;
2881 /***********************************************************************
2882 * UnlockUrlCacheEntryStream (WININET.@)
2885 BOOL WINAPI UnlockUrlCacheEntryStream(
2886 IN HANDLE hUrlCacheStream,
2887 IN DWORD dwReserved
2890 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2892 if (dwReserved != 0)
2894 ERR("dwReserved != 0\n");
2895 SetLastError(ERROR_INVALID_PARAMETER);
2896 return FALSE;
2899 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2901 SetLastError(ERROR_INVALID_HANDLE);
2902 return FALSE;
2905 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2906 return FALSE;
2908 /* close file handle */
2909 CloseHandle(pStream->hFile);
2911 /* free allocated space */
2912 HeapFree(GetProcessHeap(), 0, pStream);
2914 return TRUE;
2918 /***********************************************************************
2919 * DeleteUrlCacheEntryA (WININET.@)
2922 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2924 URLCACHECONTAINER * pContainer;
2925 LPURLCACHE_HEADER pHeader;
2926 struct _HASH_ENTRY * pHashEntry;
2927 CACHEFILE_ENTRY * pEntry;
2928 DWORD error;
2930 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2932 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer);
2933 if (error != ERROR_SUCCESS)
2935 SetLastError(error);
2936 return FALSE;
2939 error = URLCacheContainer_OpenIndex(pContainer);
2940 if (error != ERROR_SUCCESS)
2942 SetLastError(error);
2943 return FALSE;
2946 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2947 return FALSE;
2949 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry))
2951 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2952 TRACE("entry %s not found!\n", lpszUrlName);
2953 SetLastError(ERROR_FILE_NOT_FOUND);
2954 return FALSE;
2957 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
2958 URLCache_DeleteEntry(pHeader, pEntry);
2960 URLCache_DeleteEntryFromHash(pHashEntry);
2962 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2964 return TRUE;
2967 /***********************************************************************
2968 * DeleteUrlCacheEntryW (WININET.@)
2971 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2973 URLCACHECONTAINER * pContainer;
2974 LPURLCACHE_HEADER pHeader;
2975 struct _HASH_ENTRY * pHashEntry;
2976 CACHEFILE_ENTRY * pEntry;
2977 LPSTR urlA;
2978 DWORD error;
2980 TRACE("(%s)\n", debugstr_w(lpszUrlName));
2982 urlA = heap_strdupWtoA(lpszUrlName);
2983 if (!urlA)
2985 SetLastError(ERROR_OUTOFMEMORY);
2986 return FALSE;
2989 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer);
2990 if (error != ERROR_SUCCESS)
2992 HeapFree(GetProcessHeap(), 0, urlA);
2993 SetLastError(error);
2994 return FALSE;
2997 error = URLCacheContainer_OpenIndex(pContainer);
2998 if (error != ERROR_SUCCESS)
3000 HeapFree(GetProcessHeap(), 0, urlA);
3001 SetLastError(error);
3002 return FALSE;
3005 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3007 HeapFree(GetProcessHeap(), 0, urlA);
3008 return FALSE;
3011 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry))
3013 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3014 TRACE("entry %s not found!\n", debugstr_a(urlA));
3015 HeapFree(GetProcessHeap(), 0, urlA);
3016 SetLastError(ERROR_FILE_NOT_FOUND);
3017 return FALSE;
3020 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3021 URLCache_DeleteEntry(pHeader, pEntry);
3023 URLCache_DeleteEntryFromHash(pHashEntry);
3025 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3027 HeapFree(GetProcessHeap(), 0, urlA);
3028 return TRUE;
3031 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
3033 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3034 return TRUE;
3037 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
3039 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3040 return TRUE;
3043 /***********************************************************************
3044 * CreateCacheContainerA (WININET.@)
3046 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3047 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3049 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3050 d1, d2, d3, d4, d5, d6, d7, d8);
3051 return TRUE;
3054 /***********************************************************************
3055 * CreateCacheContainerW (WININET.@)
3057 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3058 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3060 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3061 d1, d2, d3, d4, d5, d6, d7, d8);
3062 return TRUE;
3065 /***********************************************************************
3066 * FindFirstUrlCacheContainerA (WININET.@)
3068 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3070 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3071 return NULL;
3074 /***********************************************************************
3075 * FindFirstUrlCacheContainerW (WININET.@)
3077 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3079 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3080 return NULL;
3083 /***********************************************************************
3084 * FindNextUrlCacheContainerA (WININET.@)
3086 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
3088 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3089 return FALSE;
3092 /***********************************************************************
3093 * FindNextUrlCacheContainerW (WININET.@)
3095 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
3097 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3098 return FALSE;
3101 HANDLE WINAPI FindFirstUrlCacheEntryExA(
3102 LPCSTR lpszUrlSearchPattern,
3103 DWORD dwFlags,
3104 DWORD dwFilter,
3105 GROUPID GroupId,
3106 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3107 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3108 LPVOID lpReserved,
3109 LPDWORD pcbReserved2,
3110 LPVOID lpReserved3
3113 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
3114 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3115 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3116 SetLastError(ERROR_FILE_NOT_FOUND);
3117 return NULL;
3120 HANDLE WINAPI FindFirstUrlCacheEntryExW(
3121 LPCWSTR lpszUrlSearchPattern,
3122 DWORD dwFlags,
3123 DWORD dwFilter,
3124 GROUPID GroupId,
3125 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3126 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3127 LPVOID lpReserved,
3128 LPDWORD pcbReserved2,
3129 LPVOID lpReserved3
3132 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
3133 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
3134 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3135 SetLastError(ERROR_FILE_NOT_FOUND);
3136 return NULL;
3139 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3141 typedef struct URLCacheFindEntryHandle
3143 DWORD dwMagic;
3144 LPWSTR lpszUrlSearchPattern;
3145 DWORD dwContainerIndex;
3146 DWORD dwHashTableIndex;
3147 DWORD dwHashEntryIndex;
3148 } URLCacheFindEntryHandle;
3150 /***********************************************************************
3151 * FindFirstUrlCacheEntryA (WININET.@)
3154 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
3155 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3157 URLCacheFindEntryHandle *pEntryHandle;
3159 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3161 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3162 if (!pEntryHandle)
3163 return NULL;
3165 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3166 if (lpszUrlSearchPattern)
3168 pEntryHandle->lpszUrlSearchPattern = heap_strdupAtoW(lpszUrlSearchPattern);
3169 if (!pEntryHandle->lpszUrlSearchPattern)
3171 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3172 return NULL;
3175 else
3176 pEntryHandle->lpszUrlSearchPattern = NULL;
3177 pEntryHandle->dwContainerIndex = 0;
3178 pEntryHandle->dwHashTableIndex = 0;
3179 pEntryHandle->dwHashEntryIndex = 0;
3181 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3183 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3184 return NULL;
3186 return pEntryHandle;
3189 /***********************************************************************
3190 * FindFirstUrlCacheEntryW (WININET.@)
3193 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3194 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3196 URLCacheFindEntryHandle *pEntryHandle;
3198 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3200 pEntryHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle));
3201 if (!pEntryHandle)
3202 return NULL;
3204 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3205 if (lpszUrlSearchPattern)
3207 pEntryHandle->lpszUrlSearchPattern = heap_strdupW(lpszUrlSearchPattern);
3208 if (!pEntryHandle->lpszUrlSearchPattern)
3210 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3211 return NULL;
3214 else
3215 pEntryHandle->lpszUrlSearchPattern = NULL;
3216 pEntryHandle->dwContainerIndex = 0;
3217 pEntryHandle->dwHashTableIndex = 0;
3218 pEntryHandle->dwHashEntryIndex = 0;
3220 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3222 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3223 return NULL;
3225 return pEntryHandle;
3228 /***********************************************************************
3229 * FindNextUrlCacheEntryA (WININET.@)
3231 BOOL WINAPI FindNextUrlCacheEntryA(
3232 HANDLE hEnumHandle,
3233 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3234 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3236 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3237 URLCACHECONTAINER * pContainer;
3239 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3241 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3243 SetLastError(ERROR_INVALID_HANDLE);
3244 return FALSE;
3247 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer);
3248 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0)
3250 LPURLCACHE_HEADER pHeader;
3251 HASH_CACHEFILE_ENTRY *pHashTableEntry;
3252 DWORD error;
3254 error = URLCacheContainer_OpenIndex(pContainer);
3255 if (error != ERROR_SUCCESS)
3257 SetLastError(error);
3258 return FALSE;
3261 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3262 return FALSE;
3264 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry);
3265 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0)
3267 const struct _HASH_ENTRY *pHashEntry = NULL;
3268 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry);
3269 pEntryHandle->dwHashEntryIndex++)
3271 const URL_CACHEFILE_ENTRY *pUrlEntry;
3272 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3274 if (pEntry->dwSignature != URL_SIGNATURE)
3275 continue;
3277 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3278 TRACE("Found URL: %s\n", (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl);
3279 TRACE("Header info: %s\n", (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
3281 error = URLCache_CopyEntry(
3282 pContainer,
3283 pHeader,
3284 lpNextCacheEntryInfo,
3285 lpdwNextCacheEntryInfoBufferSize,
3286 pUrlEntry,
3287 FALSE /* not UNICODE */);
3288 if (error != ERROR_SUCCESS)
3290 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3291 SetLastError(error);
3292 return FALSE;
3294 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName));
3296 /* increment the current index so that next time the function
3297 * is called the next entry is returned */
3298 pEntryHandle->dwHashEntryIndex++;
3299 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3300 return TRUE;
3304 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3307 SetLastError(ERROR_NO_MORE_ITEMS);
3308 return FALSE;
3311 /***********************************************************************
3312 * FindNextUrlCacheEntryW (WININET.@)
3314 BOOL WINAPI FindNextUrlCacheEntryW(
3315 HANDLE hEnumHandle,
3316 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3317 LPDWORD lpdwNextCacheEntryInfoBufferSize
3320 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3321 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3322 return FALSE;
3325 /***********************************************************************
3326 * FindCloseUrlCache (WININET.@)
3328 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3330 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle;
3332 TRACE("(%p)\n", hEnumHandle);
3334 if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3336 SetLastError(ERROR_INVALID_HANDLE);
3337 return FALSE;
3340 pEntryHandle->dwMagic = 0;
3341 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern);
3342 HeapFree(GetProcessHeap(), 0, pEntryHandle);
3344 return TRUE;
3347 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3348 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3350 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3351 dwSearchCondition, lpGroupId, lpReserved);
3352 return NULL;
3355 BOOL WINAPI FindNextUrlCacheEntryExA(
3356 HANDLE hEnumHandle,
3357 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3358 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3359 LPVOID lpReserved,
3360 LPDWORD pcbReserved2,
3361 LPVOID lpReserved3
3364 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3365 lpReserved, pcbReserved2, lpReserved3);
3366 return FALSE;
3369 BOOL WINAPI FindNextUrlCacheEntryExW(
3370 HANDLE hEnumHandle,
3371 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3372 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3373 LPVOID lpReserved,
3374 LPDWORD pcbReserved2,
3375 LPVOID lpReserved3
3378 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3379 lpReserved, pcbReserved2, lpReserved3);
3380 return FALSE;
3383 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3385 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3386 return FALSE;
3389 /***********************************************************************
3390 * CreateUrlCacheGroup (WININET.@)
3393 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3395 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3396 return FALSE;
3399 /***********************************************************************
3400 * DeleteUrlCacheGroup (WININET.@)
3403 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3405 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3406 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
3407 return FALSE;
3410 /***********************************************************************
3411 * SetUrlCacheEntryGroupA (WININET.@)
3414 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3415 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3416 LPVOID lpReserved)
3418 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3419 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3420 pbGroupAttributes, cbGroupAttributes, lpReserved);
3421 SetLastError(ERROR_FILE_NOT_FOUND);
3422 return FALSE;
3425 /***********************************************************************
3426 * SetUrlCacheEntryGroupW (WININET.@)
3429 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3430 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3431 LPVOID lpReserved)
3433 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3434 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
3435 pbGroupAttributes, cbGroupAttributes, lpReserved);
3436 SetLastError(ERROR_FILE_NOT_FOUND);
3437 return FALSE;
3440 /***********************************************************************
3441 * GetUrlCacheConfigInfoW (WININET.@)
3443 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask)
3445 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3446 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3447 return FALSE;
3450 /***********************************************************************
3451 * GetUrlCacheConfigInfoA (WININET.@)
3453 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3455 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask)
3457 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask);
3458 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3459 return FALSE;
3462 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3463 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3464 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3466 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3467 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3468 lpdwGroupInfo, lpReserved);
3469 return FALSE;
3472 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3473 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3474 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3476 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3477 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
3478 lpdwGroupInfo, lpReserved);
3479 return FALSE;
3482 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3483 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3485 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3486 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3487 return TRUE;
3490 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3491 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3493 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3494 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3495 return TRUE;
3498 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3500 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3501 return TRUE;
3504 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3506 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3507 return TRUE;
3510 /***********************************************************************
3511 * DeleteIE3Cache (WININET.@)
3513 * Deletes the files used by the IE3 URL caching system.
3515 * PARAMS
3516 * hWnd [I] A dummy window.
3517 * hInst [I] Instance of process calling the function.
3518 * lpszCmdLine [I] Options used by function.
3519 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3521 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3523 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3524 return 0;
3527 /***********************************************************************
3528 * IsUrlCacheEntryExpiredA (WININET.@)
3530 * PARAMS
3531 * url [I] Url
3532 * dwFlags [I] Unknown
3533 * pftLastModified [O] Last modified time
3535 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3537 LPURLCACHE_HEADER pHeader;
3538 struct _HASH_ENTRY * pHashEntry;
3539 const CACHEFILE_ENTRY * pEntry;
3540 const URL_CACHEFILE_ENTRY * pUrlEntry;
3541 URLCACHECONTAINER * pContainer;
3542 DWORD error;
3544 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3546 error = URLCacheContainers_FindContainerA(url, &pContainer);
3547 if (error != ERROR_SUCCESS)
3549 SetLastError(error);
3550 return FALSE;
3553 error = URLCacheContainer_OpenIndex(pContainer);
3554 if (error != ERROR_SUCCESS)
3556 SetLastError(error);
3557 return FALSE;
3560 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3561 return FALSE;
3563 if (!URLCache_FindHash(pHeader, url, &pHashEntry))
3565 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3566 TRACE("entry %s not found!\n", url);
3567 SetLastError(ERROR_FILE_NOT_FOUND);
3568 return FALSE;
3571 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3572 if (pEntry->dwSignature != URL_SIGNATURE)
3574 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3575 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD)));
3576 SetLastError(ERROR_FILE_NOT_FOUND);
3577 return FALSE;
3580 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3582 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3584 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3586 return TRUE;
3589 /***********************************************************************
3590 * IsUrlCacheEntryExpiredW (WININET.@)
3592 * PARAMS
3593 * url [I] Url
3594 * dwFlags [I] Unknown
3595 * pftLastModified [O] Last modified time
3597 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified )
3599 LPURLCACHE_HEADER pHeader;
3600 struct _HASH_ENTRY * pHashEntry;
3601 const CACHEFILE_ENTRY * pEntry;
3602 const URL_CACHEFILE_ENTRY * pUrlEntry;
3603 URLCACHECONTAINER * pContainer;
3604 DWORD error;
3606 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified);
3608 error = URLCacheContainers_FindContainerW(url, &pContainer);
3609 if (error != ERROR_SUCCESS)
3611 SetLastError(error);
3612 return FALSE;
3615 error = URLCacheContainer_OpenIndex(pContainer);
3616 if (error != ERROR_SUCCESS)
3618 SetLastError(error);
3619 return FALSE;
3622 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
3623 return FALSE;
3625 if (!URLCache_FindHashW(pHeader, url, &pHashEntry))
3627 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3628 TRACE("entry %s not found!\n", debugstr_w(url));
3629 SetLastError(ERROR_FILE_NOT_FOUND);
3630 return FALSE;
3633 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
3634 if (pEntry->dwSignature != URL_SIGNATURE)
3636 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3637 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD)));
3638 SetLastError(ERROR_FILE_NOT_FOUND);
3639 return FALSE;
3642 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry;
3644 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, pftLastModified);
3646 URLCacheContainer_UnlockIndex(pContainer, pHeader);
3648 return TRUE;
3651 /***********************************************************************
3652 * GetDiskInfoA (WININET.@)
3654 BOOL WINAPI GetDiskInfoA(PCSTR path, PDWORD cluster_size, PDWORDLONG free, PDWORDLONG total)
3656 BOOL ret;
3657 ULARGE_INTEGER bytes_free, bytes_total;
3659 TRACE("(%s, %p, %p, %p)\n", debugstr_a(path), cluster_size, free, total);
3661 if (!path)
3663 SetLastError(ERROR_INVALID_PARAMETER);
3664 return FALSE;
3667 if ((ret = GetDiskFreeSpaceExA(path, NULL, &bytes_total, &bytes_free)))
3669 if (cluster_size) *cluster_size = 1;
3670 if (free) *free = bytes_free.QuadPart;
3671 if (total) *total = bytes_total.QuadPart;
3673 return ret;
3676 /***********************************************************************
3677 * RegisterUrlCacheNotification (WININET.@)
3679 DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
3681 FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f);
3682 return 0;
3685 /***********************************************************************
3686 * IncrementUrlCacheHeaderData (WININET.@)
3688 BOOL WINAPI IncrementUrlCacheHeaderData(DWORD index, LPDWORD data)
3690 FIXME("(%u, %p)\n", index, data);
3691 return FALSE;