Create URL Cache if it does not already exist.
[wine/multimedia.git] / dlls / wininet / urlcache.c
blob45443afa7988c22b24e85f73fecb94e56888e58a
1 /*
2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #define COM_NO_WINDOWS_H
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <time.h>
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "wininet.h"
42 #include "winerror.h"
43 #include "internet.h"
44 #include "winreg.h"
45 #include "shlwapi.h"
46 #include "wingdi.h"
47 #include "shlobj.h"
49 #include "wine/unicode.h"
50 #include "wine/list.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
55 #define ENTRY_START_OFFSET 0x4000
56 #define DIR_LENGTH 8
57 #define BLOCKSIZE 128
58 #define HASHTABLE_SIZE 448
59 #define HASHTABLE_BLOCKSIZE 7
60 #define HASHTABLE_FREE 3
61 #define ALLOCATION_TABLE_OFFSET 0x250
62 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
63 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
64 #define NEWFILE_NUM_BLOCKS 0xd80
65 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
67 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
68 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
69 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
70 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
71 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
73 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
75 typedef struct _CACHEFILE_ENTRY
77 /* union
78 {*/
79 DWORD dwSignature; /* e.g. "URL " */
80 /* CHAR szSignature[4];
81 };*/
82 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
83 } CACHEFILE_ENTRY;
85 typedef struct _URL_CACHEFILE_ENTRY
87 CACHEFILE_ENTRY CacheFileEntry;
88 FILETIME LastModifiedTime;
89 FILETIME LastAccessTime;
90 WORD wExpiredDate; /* expire date in dos format */
91 WORD wExpiredTime; /* expire time in dos format */
92 DWORD dwUnknown1; /* usually zero */
93 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
94 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
95 DWORD dwUnknown2; /* usually zero */
96 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
97 DWORD dwUnknown3; /* usually 0x60 */
98 DWORD dwOffsetUrl; /* usually 0x68 */
99 BYTE CacheDir; /* index of cache directory this url is stored in */
100 BYTE Unknown4; /* usually zero */
101 WORD wUnknown5; /* usually 0x1010 */
102 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
103 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
104 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
105 DWORD dwHeaderInfoSize;
106 DWORD dwUnknown6; /* usually zero */
107 WORD wLastSyncDate; /* last sync date in dos format */
108 WORD wLastSyncTime; /* last sync time in dos format */
109 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
110 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
111 WORD wUnknownDate; /* usually same as wLastSyncDate */
112 WORD wUnknownTime; /* usually same as wLastSyncTime */
113 DWORD dwUnknown7; /* usually zero */
114 DWORD dwUnknown8; /* usually zero */
115 CHAR szSourceUrlName[1]; /* start of url */
116 /* packing to dword align start of next field */
117 /* CHAR szLocalFileName[]; (local file name exluding path) */
118 /* packing to dword align start of next field */
119 /* CHAR szHeaderInfo[]; (header info) */
120 } URL_CACHEFILE_ENTRY;
122 struct _HASH_ENTRY
124 DWORD dwHashKey;
125 DWORD dwOffsetEntry;
128 typedef struct _HASH_CACHEFILE_ENTRY
130 CACHEFILE_ENTRY CacheFileEntry;
131 DWORD dwAddressNext;
132 DWORD dwHashTableNumber;
133 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
134 } HASH_CACHEFILE_ENTRY;
136 typedef struct _DIRECTORY_DATA
138 DWORD dwUnknown;
139 char filename[DIR_LENGTH];
140 } DIRECTORY_DATA;
142 typedef struct _URLCACHE_HEADER
144 char szSignature[28];
145 DWORD dwFileSize;
146 DWORD dwOffsetFirstHashTable;
147 DWORD dwIndexCapacityInBlocks;
148 DWORD dwBlocksInUse;
149 DWORD dwUnknown1;
150 DWORD dwCacheLimitLow; /* disk space limit for cache */
151 DWORD dwCacheLimitHigh; /* disk space limit for cache */
152 DWORD dwUnknown4; /* current disk space usage for cache */
153 DWORD dwUnknown5; /* current disk space usage for cache */
154 DWORD dwUnknown6; /* possibly a flag? */
155 DWORD dwUnknown7;
156 BYTE DirectoryCount; /* number of directory_data's */
157 BYTE Unknown8[3]; /* just padding? */
158 DIRECTORY_DATA directory_data[1]; /* first directory entry */
159 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
160 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
162 typedef struct _STREAM_HANDLE
164 HANDLE hFile;
165 CHAR lpszUrl[1];
166 } STREAM_HANDLE;
168 typedef struct _URLCACHECONTAINER
170 struct list entry; /* part of a list */
171 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
172 LPWSTR path; /* path to url container directory */
173 HANDLE hMapping; /* handle of file mapping */
174 DWORD file_size; /* size of file when mapping was opened */
175 HANDLE hMutex; /* hande of mutex */
176 } URLCACHECONTAINER;
179 /* List of all containers available */
180 static struct list UrlContainers = LIST_INIT(UrlContainers);
182 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry);
184 /***********************************************************************
185 * URLCache_PathToObjectName (Internal)
187 * Converts a path to a name suitable for use as a Win32 object name.
188 * Replaces '\\' characters in-place with the specified character
189 * (usually '_' or '!')
191 * RETURNS
192 * nothing
195 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
197 for (; *lpszPath; lpszPath++)
199 if (*lpszPath == '\\')
200 *lpszPath = replace;
204 /***********************************************************************
205 * URLCacheContainer_OpenIndex (Internal)
207 * Opens the index file and saves mapping handle in hCacheIndexMapping
209 * RETURNS
210 * TRUE if succeeded
211 * FALSE if failed
214 static BOOL URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
216 HANDLE hFile;
217 WCHAR wszFilePath[MAX_PATH];
218 DWORD dwFileSize;
220 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
221 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
223 if (pContainer->hMapping)
224 return TRUE;
226 strcpyW(wszFilePath, pContainer->path);
227 strcatW(wszFilePath, wszIndex);
229 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
230 if (hFile == INVALID_HANDLE_VALUE)
232 /* Maybe the directory wasn't there? Try to create it */
233 if (CreateDirectoryW(pContainer->path, 0))
234 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
236 if (hFile == INVALID_HANDLE_VALUE)
238 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath));
239 return FALSE;
242 /* At this stage we need the mutex because we may be about to create the
243 * file.
245 WaitForSingleObject(pContainer->hMutex, INFINITE);
247 dwFileSize = GetFileSize(hFile, NULL);
248 if (dwFileSize == INVALID_FILE_SIZE)
250 ReleaseMutex(pContainer->hMutex);
251 return FALSE;
254 if (dwFileSize == 0)
256 static CHAR const szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Cache\\Content";
257 HKEY key;
258 char achZeroes[0x1000];
259 DWORD dwOffset;
260 DWORD dwError = 0;
262 /* Write zeroes to the entire file so we can safely map it without
263 * fear of getting a SEGV because the disk is full.
265 memset(achZeroes, 0, sizeof(achZeroes));
266 for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes))
268 DWORD dwWrite = sizeof(achZeroes);
269 DWORD dwWritten;
271 if (NEWFILE_SIZE - dwOffset < dwWrite)
272 dwWrite = NEWFILE_SIZE - dwOffset;
273 if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) ||
274 dwWritten != dwWrite)
276 /* If we fail to write, we need to return the error that
277 * cause the problem and also make sure the file is no
278 * longer there, if possible.
280 dwError = GetLastError();
282 break;
286 if (!dwError)
288 HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL);
290 if (hMapping)
292 URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE);
294 if (pHeader)
296 WCHAR *pwchDir;
297 WCHAR wszDirPath[MAX_PATH];
298 FILETIME ft;
299 int i, j;
300 HASH_CACHEFILE_ENTRY *pPrevHash = 0;
302 dwFileSize = NEWFILE_SIZE;
304 /* First set some constants and defaults in the header */
305 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
306 pHeader->dwFileSize = dwFileSize;
307 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
308 /* 127MB - taken from default for Windows 2000 */
309 pHeader->dwCacheLimitHigh = 0;
310 pHeader->dwCacheLimitLow = 0x07ff5400;
311 /* Copied from a Windows 2000 cache index */
312 pHeader->DirectoryCount = 4;
314 /* If the registry has a cache size set, use the registry value */
315 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
317 DWORD dw;
318 DWORD len = sizeof(dw);
319 DWORD keytype;
321 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
322 (BYTE *) &dw, &len) == ERROR_SUCCESS &&
323 keytype == REG_DWORD)
325 pHeader->dwCacheLimitHigh = (dw >> 22);
326 pHeader->dwCacheLimitLow = dw << 10;
328 RegCloseKey(key);
331 /* Now create the hash table entries. Windows would create
332 * these as needed, but WINE doesn't do that yet, so create
333 * four and hope it's enough.
336 for (i = 0; i < 4; ++i)
338 HASH_CACHEFILE_ENTRY *pHash;
339 DWORD dwOffset;
341 /* Request 0x20 blocks - no need to check for failure here because
342 * we started with an empty file
344 URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **) &pHash);
346 dwOffset = (BYTE *) pHash - (BYTE *) pHeader;
348 if (pPrevHash)
349 pPrevHash->dwAddressNext = dwOffset;
350 else
351 pHeader->dwOffsetFirstHashTable = dwOffset;
352 pHash->CacheFileEntry.dwSignature = HASH_SIGNATURE;
353 pHash->CacheFileEntry.dwBlocksUsed = 0x20;
354 pHash->dwHashTableNumber = i;
355 for (j = 0; j < HASHTABLE_SIZE; ++j)
357 pHash->HashTable[j].dwOffsetEntry = 0;
358 pHash->HashTable[j].dwHashKey = HASHTABLE_FREE;
360 pPrevHash = pHash;
363 /* Last step - create the directories */
365 strcpyW(wszDirPath, pContainer->path);
366 pwchDir = wszDirPath + strlenW(wszDirPath);
367 pwchDir[8] = 0;
369 GetSystemTimeAsFileTime(&ft);
371 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
373 /* The following values were copied from a Windows index.
374 * I don't know what the values are supposed to mean but
375 * have made them the same in the hope that this will
376 * be better for compatibility
378 pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
379 for (j = 0;; ++j)
381 int k;
382 ULONGLONG n = ft.dwHighDateTime;
384 /* Generate a file name to attempt to create.
385 * This algorithm will create what will appear
386 * to be random and unrelated directory names
387 * of up to 9 characters in length.
389 n <<= 32;
390 n += ft.dwLowDateTime;
391 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
393 for (k = 0; k < 8; ++k)
395 int r = (n % 36);
397 /* Dividing by a prime greater than 36 helps
398 * with the appearance of randomness
400 n /= 37;
402 if (r < 10)
403 pwchDir[k] = '0' + r;
404 else
405 pwchDir[k] = 'A' + (r - 10);
408 if (CreateDirectoryW(wszDirPath, 0))
410 int k;
412 /* The following is OK because we generated an
413 * 8 character directory name made from characters
414 * [A-Z0-9], which are equivalent for all code
415 * pages and for UTF-16
417 for (k = 0; k < 8; ++k)
418 pHeader->directory_data[i].filename[k] = pwchDir[k];
419 break;
421 else if (j >= 255)
423 /* Give up. The most likely cause of this
424 * is a full disk, but whatever the cause
425 * is, it should be more than apparent that
426 * we won't succeed.
428 dwError = GetLastError();
429 break;
434 UnmapViewOfFile(pHeader);
436 else
438 dwError = GetLastError();
440 CloseHandle(hMapping);
442 else
444 dwError = GetLastError();
448 if (dwError)
450 CloseHandle(hFile);
451 DeleteFileW(wszFilePath);
452 ReleaseMutex(pContainer->hMutex);
453 SetLastError(dwError);
454 return FALSE;
459 ReleaseMutex(pContainer->hMutex);
461 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
462 URLCache_PathToObjectName(wszFilePath, '_');
463 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
464 if (!pContainer->hMapping)
465 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
466 CloseHandle(hFile);
467 if (!pContainer->hMapping)
469 ERR("Couldn't create file mapping (error is %ld)\n", GetLastError());
470 return FALSE;
473 return TRUE;
476 /***********************************************************************
477 * URLCacheContainer_CloseIndex (Internal)
479 * Closes the index
481 * RETURNS
482 * nothing
485 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
487 CloseHandle(pContainer->hMapping);
488 pContainer->hMapping = NULL;
491 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
493 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
494 int path_len = strlenW(path);
495 int cache_prefix_len = strlenW(cache_prefix);
497 if (!pContainer)
499 return FALSE;
502 pContainer->hMapping = NULL;
503 pContainer->file_size = 0;
505 pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR));
506 if (!pContainer->path)
508 HeapFree(GetProcessHeap(), 0, pContainer);
509 return FALSE;
512 memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR));
514 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
515 if (!pContainer->cache_prefix)
517 HeapFree(GetProcessHeap(), 0, pContainer->path);
518 HeapFree(GetProcessHeap(), 0, pContainer);
519 return FALSE;
522 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
524 CharLowerW(mutex_name);
525 URLCache_PathToObjectName(mutex_name, '!');
527 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
529 ERR("couldn't create mutex (error is %ld)\n", GetLastError());
530 HeapFree(GetProcessHeap(), 0, pContainer->path);
531 HeapFree(GetProcessHeap(), 0, pContainer);
532 return FALSE;
535 list_add_head(&UrlContainers, &pContainer->entry);
537 return TRUE;
540 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
542 list_remove(&pContainer->entry);
544 URLCacheContainer_CloseIndex(pContainer);
545 CloseHandle(pContainer->hMutex);
546 HeapFree(GetProcessHeap(), 0, pContainer->path);
547 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
548 HeapFree(GetProcessHeap(), 0, pContainer);
551 void URLCacheContainers_CreateDefaults()
553 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
554 static const WCHAR UrlPrefix[] = {0};
555 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
556 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
557 static const WCHAR CookieSuffix[] = {0};
558 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
559 static const struct
561 int nFolder; /* CSIDL_* constant */
562 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
563 const WCHAR * cache_prefix; /* prefix used to reference the container */
564 } DefaultContainerData[] =
566 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
567 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
568 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
570 DWORD i;
572 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
574 WCHAR wszCachePath[MAX_PATH];
575 WCHAR wszMutexName[MAX_PATH];
576 int path_len, suffix_len;
578 if (FAILED(SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE)))
580 ERR("Couldn't get path for default container %lu\n", i);
581 continue;
583 path_len = strlenW(wszCachePath);
584 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
586 if (path_len + suffix_len + 2 > MAX_PATH)
588 ERR("Path too long\n");
589 continue;
592 wszCachePath[path_len] = '\\';
594 strcpyW(wszMutexName, wszCachePath);
596 if (suffix_len)
598 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
599 wszCachePath[path_len + suffix_len + 1] = '\\';
600 wszCachePath[path_len + suffix_len + 2] = '\0';
603 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
607 void URLCacheContainers_DeleteAll()
609 while(!list_empty(&UrlContainers))
610 URLCacheContainer_DeleteContainer(
611 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
615 static BOOL URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
617 struct list * cursor;
619 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
621 LIST_FOR_EACH(cursor, &UrlContainers)
623 URLCACHECONTAINER * pContainer = LIST_ENTRY(cursor, URLCACHECONTAINER, entry);
624 int prefix_len = strlenW(pContainer->cache_prefix);
625 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
627 TRACE("found container with prefx %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
628 *ppContainer = pContainer;
629 return TRUE;
632 ERR("no container found\n");
633 SetLastError(ERROR_FILE_NOT_FOUND);
634 return FALSE;
637 static BOOL URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
639 BOOL ret;
640 LPWSTR lpwszUrl;
641 int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
642 if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR))))
644 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len);
645 ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer);
646 HeapFree(GetProcessHeap(), 0, lpwszUrl);
647 return ret;
649 return FALSE;
652 /***********************************************************************
653 * URLCacheContainer_LockIndex (Internal)
656 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
658 BYTE index;
659 LPVOID pIndexData;
660 URLCACHE_HEADER * pHeader;
662 /* acquire mutex */
663 WaitForSingleObject(pContainer->hMutex, INFINITE);
665 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
667 if (!pIndexData)
669 ReleaseMutex(pContainer->hMutex);
670 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
671 return FALSE;
673 pHeader = (URLCACHE_HEADER *)pIndexData;
675 /* file has grown - we need to remap to prevent us getting
676 * access violations when we try and access beyond the end
677 * of the memory mapped file */
678 if (pHeader->dwFileSize != pContainer->file_size)
680 URLCacheContainer_CloseIndex(pContainer);
681 if (!URLCacheContainer_OpenIndex(pContainer))
683 ReleaseMutex(pContainer->hMutex);
684 return FALSE;
686 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
688 if (!pIndexData)
690 ReleaseMutex(pContainer->hMutex);
691 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
692 return FALSE;
694 pHeader = (URLCACHE_HEADER *)pIndexData;
697 TRACE("Signature: %s, file size: %ld bytes\n", pHeader->szSignature, pHeader->dwFileSize);
699 for (index = 0; index < pHeader->DirectoryCount; index++)
701 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
704 return pHeader;
707 /***********************************************************************
708 * URLCacheContainer_UnlockIndex (Internal)
711 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
713 /* release mutex */
714 ReleaseMutex(pContainer->hMutex);
715 return UnmapViewOfFile(pHeader);
719 #ifndef CHAR_BIT
720 #define CHAR_BIT (8 * sizeof(CHAR))
721 #endif
723 /***********************************************************************
724 * URLCache_Allocation_BlockIsFree (Internal)
726 * Is the specified block number free?
728 * RETURNS
729 * zero if free
730 * non-zero otherwise
733 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
735 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
736 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
739 /***********************************************************************
740 * URLCache_Allocation_BlockFree (Internal)
742 * Marks the specified block as free
744 * RETURNS
745 * nothing
748 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
750 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
751 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
754 /***********************************************************************
755 * URLCache_Allocation_BlockAllocate (Internal)
757 * Marks the specified block as allocated
759 * RETURNS
760 * nothing
763 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
765 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
766 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
769 /***********************************************************************
770 * URLCache_FindFirstFreeEntry (Internal)
772 * Finds and allocates the first block of free space big enough and
773 * sets ppEntry to point to it.
775 * RETURNS
776 * TRUE if it had enough space
777 * FALSE if it couldn't find enough space
780 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
782 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
783 DWORD dwBlockNumber;
784 DWORD dwFreeCounter;
785 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
787 for (dwFreeCounter = 0;
788 dwFreeCounter < dwBlocksNeeded &&
789 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
790 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
791 dwFreeCounter++)
792 TRACE("Found free block at no. %ld (0x%lx)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
794 if (dwFreeCounter == dwBlocksNeeded)
796 DWORD index;
797 TRACE("Found free blocks starting at no. %ld (0x%lx)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
798 for (index = 0; index < dwBlocksNeeded; index++)
799 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
800 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
801 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
802 return TRUE;
805 FIXME("Grow file\n");
806 return FALSE;
809 /***********************************************************************
810 * URLCache_DeleteEntry (Internal)
812 * Deletes the specified entry and frees the space allocated to it
814 * RETURNS
815 * TRUE if it succeeded
816 * FALSE if it failed
819 static BOOL URLCache_DeleteEntry(CACHEFILE_ENTRY * pEntry)
821 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
822 return TRUE;
825 /***********************************************************************
826 * URLCache_LocalFileNameToPathW (Internal)
828 * Copies the full path to the specified buffer given the local file
829 * name and the index of the directory it is in. Always sets value in
830 * lpBufferSize to the required buffer size (in bytes).
832 * RETURNS
833 * TRUE if the buffer was big enough
834 * FALSE if the buffer was too small
837 static BOOL URLCache_LocalFileNameToPathW(
838 const URLCACHECONTAINER * pContainer,
839 LPCURLCACHE_HEADER pHeader,
840 LPCSTR szLocalFileName,
841 BYTE Directory,
842 LPWSTR wszPath,
843 LPLONG lpBufferSize)
845 LONG nRequired;
846 int path_len = strlenW(pContainer->path);
847 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
848 if (Directory >= pHeader->DirectoryCount)
850 *lpBufferSize = 0;
851 return FALSE;
854 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
855 if (nRequired < *lpBufferSize)
857 int dir_len;
859 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
860 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
861 wszPath[dir_len + path_len] = '\\';
862 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
863 *lpBufferSize = nRequired;
864 return TRUE;
866 *lpBufferSize = nRequired;
867 return FALSE;
870 /***********************************************************************
871 * URLCache_LocalFileNameToPathA (Internal)
873 * Copies the full path to the specified buffer given the local file
874 * name and the index of the directory it is in. Always sets value in
875 * lpBufferSize to the required buffer size.
877 * RETURNS
878 * TRUE if the buffer was big enough
879 * FALSE if the buffer was too small
882 static BOOL URLCache_LocalFileNameToPathA(
883 const URLCACHECONTAINER * pContainer,
884 LPCURLCACHE_HEADER pHeader,
885 LPCSTR szLocalFileName,
886 BYTE Directory,
887 LPSTR szPath,
888 LPLONG lpBufferSize)
890 LONG nRequired;
891 int path_len, file_name_len, dir_len;
893 if (Directory >= pHeader->DirectoryCount)
895 *lpBufferSize = 0;
896 return FALSE;
899 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL);
900 file_name_len = strlen(szLocalFileName);
901 dir_len = DIR_LENGTH;
903 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(WCHAR);
904 if (nRequired < *lpBufferSize)
906 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, -1, NULL, NULL);
907 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len);
908 szPath[path_len + dir_len] = '\\';
909 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len);
910 *lpBufferSize = nRequired;
911 return TRUE;
913 *lpBufferSize = nRequired;
914 return FALSE;
917 /***********************************************************************
918 * URLCache_CopyEntry (Internal)
920 * Copies an entry from the cache index file to the Win32 structure
922 * RETURNS
923 * TRUE if the buffer was big enough
924 * FALSE if the buffer was too small
927 static BOOL URLCache_CopyEntry(
928 URLCACHECONTAINER * pContainer,
929 LPCURLCACHE_HEADER pHeader,
930 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
931 LPDWORD lpdwBufferSize,
932 URL_CACHEFILE_ENTRY * pUrlEntry,
933 BOOL bUnicode)
935 int lenUrl;
936 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
938 if (*lpdwBufferSize >= dwRequiredSize)
940 lpCacheEntryInfo->lpHeaderInfo = NULL;
941 lpCacheEntryInfo->lpszFileExtension = NULL;
942 lpCacheEntryInfo->lpszLocalFileName = NULL;
943 lpCacheEntryInfo->lpszSourceUrlName = NULL;
944 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
945 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
946 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
947 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
948 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
949 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
950 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
951 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
952 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
953 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
954 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
955 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
956 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
957 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
960 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
961 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
962 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
963 if (bUnicode)
964 lenUrl = MultiByteToWideChar(CP_ACP, 0, pUrlEntry->szSourceUrlName, -1, NULL, 0);
965 else
966 lenUrl = strlen(pUrlEntry->szSourceUrlName);
967 dwRequiredSize += lenUrl + 1;
969 /* FIXME: is source url optional? */
970 if (*lpdwBufferSize >= dwRequiredSize)
972 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrl - 1;
973 if (bUnicode)
974 MultiByteToWideChar(CP_ACP, 0, pUrlEntry->szSourceUrlName, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
975 else
976 memcpy(lpCacheEntryInfo->lpszSourceUrlName, pUrlEntry->szSourceUrlName, (lenUrl + 1) * sizeof(CHAR));
979 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
980 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
981 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
983 if (pUrlEntry->dwOffsetLocalName)
985 LONG nLocalFilePathSize;
986 LPSTR lpszLocalFileName;
987 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
988 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
989 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
990 URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize))
992 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
994 dwRequiredSize += nLocalFilePathSize;
996 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
997 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
998 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1000 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
1002 if (*lpdwBufferSize >= dwRequiredSize)
1004 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
1005 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
1006 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
1008 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
1009 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
1010 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
1012 if (dwRequiredSize > *lpdwBufferSize)
1014 *lpdwBufferSize = dwRequiredSize;
1015 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1016 return FALSE;
1018 *lpdwBufferSize = dwRequiredSize;
1019 return TRUE;
1023 /***********************************************************************
1024 * URLCache_SetEntryInfo (Internal)
1026 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1027 * according the the flags set by dwFieldControl.
1029 * RETURNS
1030 * TRUE if the buffer was big enough
1031 * FALSE if the buffer was too small
1034 static BOOL URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
1036 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
1037 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
1038 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
1039 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
1040 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
1041 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
1042 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
1043 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1044 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
1045 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1046 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
1047 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
1048 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
1049 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
1050 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
1051 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1053 return TRUE;
1056 /***********************************************************************
1057 * URLCache_HashKey (Internal)
1059 * Returns the hash key for a given string
1061 * RETURNS
1062 * hash key for the string
1065 static DWORD URLCache_HashKey(LPCSTR lpszKey)
1067 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1068 * but the algorithm and result are not the same!
1070 static const unsigned char lookupTable[256] =
1072 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1073 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1074 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1075 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1076 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1077 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1078 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1079 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1080 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1081 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1082 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1083 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1084 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1085 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1086 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1087 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1088 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1089 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1090 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1091 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1092 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1093 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1094 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1095 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1096 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1097 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1098 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1099 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1100 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1101 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1102 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1103 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1105 BYTE key[4];
1106 DWORD i;
1107 int subscript[sizeof(key) / sizeof(key[0])];
1109 subscript[0] = *lpszKey;
1110 subscript[1] = (char)(*lpszKey + 1);
1111 subscript[2] = (char)(*lpszKey + 2);
1112 subscript[3] = (char)(*lpszKey + 3);
1114 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1115 key[i] = lookupTable[i];
1117 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
1119 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
1120 key[i] = lookupTable[*lpszKey ^ key[i]];
1123 return *(DWORD *)key;
1126 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
1128 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
1131 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
1133 /* structure of hash table:
1134 * 448 entries divided into 64 blocks
1135 * each block therefore contains a chain of 7 key/offset pairs
1136 * how position in table is calculated:
1137 * 1. the url is hashed in helper function
1138 * 2. the key % 64 * 8 is the offset
1139 * 3. the key in the hash table is the hash key aligned to 64
1141 * note:
1142 * there can be multiple hash tables in the file and the offset to
1143 * the next one is stored in the header of the hash table
1145 DWORD key = URLCache_HashKey(lpszUrl);
1146 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1147 HASH_CACHEFILE_ENTRY * pHashEntry;
1148 DWORD dwHashTableNumber = 0;
1150 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1152 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1153 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1154 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1156 int i;
1157 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1159 ERR("Error: not right hash table number (%ld) expected %ld\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1160 continue;
1162 /* make sure that it is in fact a hash entry */
1163 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1165 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1166 continue;
1169 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1171 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1172 if (key == (DWORD)(pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
1174 /* FIXME: we should make sure that this is the right element
1175 * before returning and claiming that it is. We can do this
1176 * by doing a simple compare between the URL we were given
1177 * and the URL stored in the entry. However, this assumes
1178 * we know the format of all the entries stored in the
1179 * hash table */
1180 *ppHashEntry = pHashElement;
1181 return TRUE;
1185 return FALSE;
1188 /***********************************************************************
1189 * URLCache_FindEntryInHash (Internal)
1191 * Searches all the hash tables in the index for the given URL and
1192 * returns the entry, if it was found, in ppEntry
1194 * RETURNS
1195 * TRUE if the entry was found
1196 * FALSE if the entry could not be found
1199 static BOOL URLCache_FindEntryInHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, CACHEFILE_ENTRY ** ppEntry)
1201 struct _HASH_ENTRY * pHashEntry;
1202 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1204 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
1205 return TRUE;
1207 return FALSE;
1210 /***********************************************************************
1211 * URLCache_HashEntrySetUse (Internal)
1213 * Searches all the hash tables in the index for the given URL and
1214 * sets the use count (stored or'ed with key)
1216 * RETURNS
1217 * TRUE if the entry was found
1218 * FALSE if the entry could not be found
1221 static BOOL URLCache_HashEntrySetUse(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwUseCount)
1223 struct _HASH_ENTRY * pHashEntry;
1224 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1226 pHashEntry->dwHashKey = dwUseCount | (DWORD)(pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1227 return TRUE;
1229 return FALSE;
1232 /***********************************************************************
1233 * URLCache_DeleteEntryFromHash (Internal)
1235 * Searches all the hash tables in the index for the given URL and
1236 * then if found deletes the entry.
1238 * RETURNS
1239 * TRUE if the entry was found
1240 * FALSE if the entry could not be found
1243 static BOOL URLCache_DeleteEntryFromHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl)
1245 struct _HASH_ENTRY * pHashEntry;
1246 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1248 pHashEntry->dwHashKey = HASHTABLE_FREE;
1249 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1250 return TRUE;
1252 return FALSE;
1255 /***********************************************************************
1256 * URLCache_AddEntryToHash (Internal)
1258 * Searches all the hash tables for a free slot based on the offset
1259 * generated from the hash key. If a free slot is found, the offset and
1260 * key are entered into the hash table.
1262 * RETURNS
1263 * TRUE if the entry was added
1264 * FALSE if the entry could not be added
1267 static BOOL URLCache_AddEntryToHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1269 /* see URLCache_FindEntryInHash for structure of hash tables */
1271 DWORD key = URLCache_HashKey(lpszUrl);
1272 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1273 HASH_CACHEFILE_ENTRY * pHashEntry;
1274 DWORD dwHashTableNumber = 0;
1276 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1278 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1279 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1280 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1282 int i;
1283 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1285 ERR("not right hash table number (%ld) expected %ld\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1286 break;
1288 /* make sure that it is in fact a hash entry */
1289 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1291 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1292 break;
1295 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1297 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1298 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1300 pHashElement->dwHashKey = key;
1301 pHashElement->dwOffsetEntry = dwOffsetEntry;
1302 return TRUE;
1306 FIXME("need to create another hash table\n");
1307 return FALSE;
1310 /***********************************************************************
1311 * GetUrlCacheEntryInfoExA (WININET.@)
1314 BOOL WINAPI GetUrlCacheEntryInfoExA(
1315 LPCSTR lpszUrl,
1316 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1317 LPDWORD lpdwCacheEntryInfoBufSize,
1318 LPSTR lpszReserved,
1319 LPDWORD lpdwReserved,
1320 LPVOID lpReserved,
1321 DWORD dwFlags)
1323 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1324 debugstr_a(lpszUrl),
1325 lpCacheEntryInfo,
1326 lpdwCacheEntryInfoBufSize,
1327 lpszReserved,
1328 lpdwReserved,
1329 lpReserved,
1330 dwFlags);
1332 if ((lpszReserved != NULL) ||
1333 (lpdwReserved != NULL) ||
1334 (lpReserved != NULL))
1336 ERR("Reserved value was not 0\n");
1337 SetLastError(ERROR_INVALID_PARAMETER);
1338 return FALSE;
1340 if (dwFlags != 0)
1341 FIXME("Undocumented flag(s): %lx\n", dwFlags);
1342 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1345 /***********************************************************************
1346 * GetUrlCacheEntryInfoA (WININET.@)
1349 BOOL WINAPI GetUrlCacheEntryInfoA(
1350 IN LPCSTR lpszUrlName,
1351 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1352 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1355 LPURLCACHE_HEADER pHeader;
1356 CACHEFILE_ENTRY * pEntry;
1357 URL_CACHEFILE_ENTRY * pUrlEntry;
1358 URLCACHECONTAINER * pContainer;
1360 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1362 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1363 return FALSE;
1365 if (!URLCacheContainer_OpenIndex(pContainer))
1366 return FALSE;
1368 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1369 return FALSE;
1371 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1373 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1374 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1375 SetLastError(ERROR_FILE_NOT_FOUND);
1376 return FALSE;
1379 if (pEntry->dwSignature != URL_SIGNATURE)
1381 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1382 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1383 SetLastError(ERROR_FILE_NOT_FOUND);
1384 return FALSE;
1387 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1388 TRACE("Found URL: %s\n", debugstr_a(pUrlEntry->szSourceUrlName));
1389 if (pUrlEntry->dwOffsetHeaderInfo)
1390 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1392 if (!URLCache_CopyEntry(
1393 pContainer,
1394 pHeader,
1395 lpCacheEntryInfo,
1396 lpdwCacheEntryInfoBufferSize,
1397 pUrlEntry,
1398 FALSE /* ANSI */))
1400 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1401 return FALSE;
1403 TRACE("Local File Name: %s\n", debugstr_a(lpCacheEntryInfo->lpszLocalFileName));
1405 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1407 return TRUE;
1410 /***********************************************************************
1411 * GetUrlCacheEntryInfoW (WININET.@)
1414 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1415 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1416 LPDWORD lpdwCacheEntryInfoBufferSize)
1418 LPURLCACHE_HEADER pHeader;
1419 CACHEFILE_ENTRY * pEntry;
1420 URL_CACHEFILE_ENTRY * pUrlEntry;
1421 URLCACHECONTAINER * pContainer;
1422 LPSTR lpszUrlA;
1423 int url_len;
1425 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1427 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1428 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1429 if (!lpszUrlA)
1431 SetLastError(ERROR_OUTOFMEMORY);
1432 return FALSE;
1434 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1436 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1438 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1439 return FALSE;
1442 if (!URLCacheContainer_OpenIndex(pContainer))
1444 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1445 return FALSE;
1448 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1450 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1451 return FALSE;
1454 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1456 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1457 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1458 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1459 SetLastError(ERROR_FILE_NOT_FOUND);
1460 return FALSE;
1462 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1464 if (pEntry->dwSignature != URL_SIGNATURE)
1466 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1467 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1468 SetLastError(ERROR_FILE_NOT_FOUND);
1469 return FALSE;
1472 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1473 TRACE("Found URL: %s\n", debugstr_a(pUrlEntry->szSourceUrlName));
1474 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1476 if (!URLCache_CopyEntry(
1477 pContainer,
1478 pHeader,
1479 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1480 lpdwCacheEntryInfoBufferSize,
1481 pUrlEntry,
1482 TRUE /* UNICODE */))
1484 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1485 return FALSE;
1487 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1489 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1491 return TRUE;
1494 /***********************************************************************
1495 * GetUrlCacheEntryInfoExW (WININET.@)
1498 BOOL WINAPI GetUrlCacheEntryInfoExW(
1499 LPCWSTR lpszUrl,
1500 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1501 LPDWORD lpdwCacheEntryInfoBufSize,
1502 LPWSTR lpszReserved,
1503 LPDWORD lpdwReserved,
1504 LPVOID lpReserved,
1505 DWORD dwFlags)
1507 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1508 debugstr_w(lpszUrl),
1509 lpCacheEntryInfo,
1510 lpdwCacheEntryInfoBufSize,
1511 lpszReserved,
1512 lpdwReserved,
1513 lpReserved,
1514 dwFlags);
1516 if ((lpszReserved != NULL) ||
1517 (lpdwReserved != NULL) ||
1518 (lpReserved != NULL))
1520 ERR("Reserved value was not 0\n");
1521 SetLastError(ERROR_INVALID_PARAMETER);
1522 return FALSE;
1524 if (dwFlags != 0)
1525 FIXME("Undocumented flag(s): %lx\n", dwFlags);
1526 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1529 /***********************************************************************
1530 * SetUrlCacheEntryInfoA (WININET.@)
1532 BOOL WINAPI SetUrlCacheEntryInfoA(
1533 LPCSTR lpszUrlName,
1534 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1535 DWORD dwFieldControl)
1537 LPURLCACHE_HEADER pHeader;
1538 CACHEFILE_ENTRY * pEntry;
1539 URLCACHECONTAINER * pContainer;
1541 TRACE("(%s, %p, 0x%08lx)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1543 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1544 return FALSE;
1546 if (!URLCacheContainer_OpenIndex(pContainer))
1547 return FALSE;
1549 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1550 return FALSE;
1552 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1554 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1555 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1556 SetLastError(ERROR_FILE_NOT_FOUND);
1557 return FALSE;
1560 if (pEntry->dwSignature != URL_SIGNATURE)
1562 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1563 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1564 SetLastError(ERROR_FILE_NOT_FOUND);
1565 return FALSE;
1568 URLCache_SetEntryInfo(
1569 (URL_CACHEFILE_ENTRY *)pEntry,
1570 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1571 dwFieldControl);
1573 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1575 return TRUE;
1578 /***********************************************************************
1579 * SetUrlCacheEntryInfoW (WININET.@)
1581 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1583 LPURLCACHE_HEADER pHeader;
1584 CACHEFILE_ENTRY * pEntry;
1585 URLCACHECONTAINER * pContainer;
1586 LPSTR lpszUrlA;
1587 int url_len;
1589 TRACE("(%s, %p, 0x%08lx)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1591 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1592 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1593 if (!lpszUrlA)
1595 SetLastError(ERROR_OUTOFMEMORY);
1596 return FALSE;
1598 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1600 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1602 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1603 return FALSE;
1606 if (!URLCacheContainer_OpenIndex(pContainer))
1608 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1609 return FALSE;
1612 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1614 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1615 return FALSE;
1618 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1620 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1621 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1622 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1623 SetLastError(ERROR_FILE_NOT_FOUND);
1624 return FALSE;
1626 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1628 if (pEntry->dwSignature != URL_SIGNATURE)
1630 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1631 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1632 SetLastError(ERROR_FILE_NOT_FOUND);
1633 return FALSE;
1636 URLCache_SetEntryInfo(
1637 (URL_CACHEFILE_ENTRY *)pEntry,
1638 lpCacheEntryInfo,
1639 dwFieldControl);
1641 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1643 return TRUE;
1646 /***********************************************************************
1647 * RetrieveUrlCacheEntryFileA (WININET.@)
1650 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1651 IN LPCSTR lpszUrlName,
1652 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1653 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1654 IN DWORD dwReserved
1657 LPURLCACHE_HEADER pHeader;
1658 CACHEFILE_ENTRY * pEntry;
1659 URL_CACHEFILE_ENTRY * pUrlEntry;
1660 URLCACHECONTAINER * pContainer;
1662 TRACE("(%s, %p, %p, 0x%08lx)\n",
1663 debugstr_a(lpszUrlName),
1664 lpCacheEntryInfo,
1665 lpdwCacheEntryInfoBufferSize,
1666 dwReserved);
1668 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1669 return FALSE;
1671 if (!URLCacheContainer_OpenIndex(pContainer))
1672 return FALSE;
1674 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1675 return FALSE;
1677 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1679 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1680 TRACE("entry %s not found!\n", lpszUrlName);
1681 SetLastError(ERROR_FILE_NOT_FOUND);
1682 return FALSE;
1685 if (pEntry->dwSignature != URL_SIGNATURE)
1687 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1688 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1689 SetLastError(ERROR_FILE_NOT_FOUND);
1690 return FALSE;
1693 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1694 TRACE("Found URL: %s\n", pUrlEntry->szSourceUrlName);
1695 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1697 pUrlEntry->dwHitRate++;
1698 pUrlEntry->dwUseCount++;
1699 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1701 if (!URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize, pUrlEntry, FALSE))
1703 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1704 return FALSE;
1706 TRACE("Local File Name: %s\n", lpCacheEntryInfo->lpszLocalFileName);
1708 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1710 return TRUE;
1713 /***********************************************************************
1714 * RetrieveUrlCacheEntryFileW (WININET.@)
1717 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1718 IN LPCWSTR lpszUrlName,
1719 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1720 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1721 IN DWORD dwReserved
1724 TRACE("(%s, %p, %p, 0x%08lx)\n",
1725 debugstr_w(lpszUrlName),
1726 lpCacheEntryInfo,
1727 lpdwCacheEntryInfoBufferSize,
1728 dwReserved);
1730 return FALSE;
1733 /***********************************************************************
1734 * UnlockUrlCacheEntryFileA (WININET.@)
1737 BOOL WINAPI UnlockUrlCacheEntryFileA(
1738 IN LPCSTR lpszUrlName,
1739 IN DWORD dwReserved
1742 LPURLCACHE_HEADER pHeader;
1743 CACHEFILE_ENTRY * pEntry;
1744 URL_CACHEFILE_ENTRY * pUrlEntry;
1745 URLCACHECONTAINER * pContainer;
1747 TRACE("(%s, 0x%08lx)\n", debugstr_a(lpszUrlName), dwReserved);
1749 if (dwReserved)
1751 ERR("dwReserved != 0\n");
1752 SetLastError(ERROR_INVALID_PARAMETER);
1753 return FALSE;
1756 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1757 return FALSE;
1759 if (!URLCacheContainer_OpenIndex(pContainer))
1760 return FALSE;
1762 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1763 return FALSE;
1765 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1767 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1768 TRACE("entry %s not found!\n", lpszUrlName);
1769 SetLastError(ERROR_FILE_NOT_FOUND);
1770 return FALSE;
1773 if (pEntry->dwSignature != URL_SIGNATURE)
1775 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1776 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1777 SetLastError(ERROR_FILE_NOT_FOUND);
1778 return FALSE;
1781 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1783 if (pUrlEntry->dwUseCount == 0)
1785 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1786 return FALSE;
1788 pUrlEntry->dwUseCount--;
1789 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1791 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1793 return TRUE;
1796 /***********************************************************************
1797 * UnlockUrlCacheEntryFileW (WININET.@)
1800 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
1802 FIXME("(%s, 0x%08lx)\n", debugstr_w(lpszUrlName), dwReserved);
1803 return TRUE;
1806 /***********************************************************************
1807 * CreateUrlCacheEntryA (WININET.@)
1810 BOOL WINAPI CreateUrlCacheEntryA(
1811 IN LPCSTR lpszUrlName,
1812 IN DWORD dwExpectedFileSize,
1813 IN LPCSTR lpszFileExtension,
1814 OUT LPSTR lpszFileName,
1815 IN DWORD dwReserved
1818 DWORD len;
1819 WCHAR *url_name;
1820 WCHAR *file_extension;
1821 WCHAR file_name[MAX_PATH];
1822 BOOL bSuccess = FALSE;
1823 DWORD dwError = 0;
1825 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
1826 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
1828 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
1829 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 &&
1830 (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
1832 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
1833 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
1835 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
1837 bSuccess = TRUE;
1839 else
1841 dwError = GetLastError();
1844 else
1846 dwError = GetLastError();
1848 HeapFree(GetProcessHeap(), 0, file_extension);
1850 else
1852 dwError = GetLastError();
1854 HeapFree(GetProcessHeap(), 0, url_name);
1855 if (!bSuccess)
1856 SetLastError(dwError);
1858 return bSuccess;
1860 /***********************************************************************
1861 * CreateUrlCacheEntryW (WININET.@)
1864 BOOL WINAPI CreateUrlCacheEntryW(
1865 IN LPCWSTR lpszUrlName,
1866 IN DWORD dwExpectedFileSize,
1867 IN LPCWSTR lpszFileExtension,
1868 OUT LPWSTR lpszFileName,
1869 IN DWORD dwReserved
1872 URLCACHECONTAINER * pContainer;
1873 LPURLCACHE_HEADER pHeader;
1874 CHAR szFile[MAX_PATH];
1875 WCHAR szExtension[MAX_PATH];
1876 LPCWSTR lpszUrlPart;
1877 LPCWSTR lpszUrlEnd;
1878 LPCWSTR lpszFileNameExtension;
1879 LPWSTR lpszFileNameNoPath;
1880 int i;
1881 int countnoextension;
1882 BYTE CacheDir;
1883 LONG lBufferSize;
1884 BOOL bFound = FALSE;
1885 int count;
1886 static WCHAR szWWW[] = {'w','w','w',0};
1888 TRACE("(%s, 0x%08lx, %s, %p, 0x%08lx)\n",
1889 debugstr_w(lpszUrlName),
1890 dwExpectedFileSize,
1891 debugstr_w(lpszFileExtension),
1892 lpszFileName,
1893 dwReserved);
1895 if (dwReserved)
1897 ERR("dwReserved != 0\n");
1898 SetLastError(ERROR_INVALID_PARAMETER);
1899 return FALSE;
1902 for (lpszUrlEnd = lpszUrlName; *lpszUrlEnd; lpszUrlEnd++)
1905 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
1906 lpszUrlEnd--;
1908 for (lpszUrlPart = lpszUrlEnd;
1909 (lpszUrlPart >= lpszUrlName);
1910 lpszUrlPart--)
1912 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
1914 bFound = TRUE;
1915 lpszUrlPart++;
1916 break;
1919 if (!lstrcmpW(lpszUrlPart, szWWW))
1921 lpszUrlPart += lstrlenW(szWWW);
1924 count = lpszUrlEnd - lpszUrlPart;
1926 if (bFound && (count < MAX_PATH))
1928 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
1929 if (!len)
1930 return FALSE;
1931 szFile[len] = '\0';
1932 /* FIXME: get rid of illegal characters like \, / and : */
1934 else
1936 FIXME("need to generate a random filename\n");
1939 TRACE("File name: %s\n", debugstr_a(szFile));
1941 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
1942 return FALSE;
1944 if (!URLCacheContainer_OpenIndex(pContainer))
1945 return FALSE;
1947 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1948 return FALSE;
1950 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
1952 lBufferSize = MAX_PATH * sizeof(CHAR);
1953 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
1955 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1957 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(CHAR) - 2;
1958 lpszFileNameNoPath >= lpszFileName;
1959 --lpszFileNameNoPath)
1961 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
1962 break;
1965 countnoextension = lstrlenW(lpszFileNameNoPath);
1966 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
1967 if (lpszFileNameExtension)
1968 countnoextension -= lstrlenW(lpszFileNameExtension);
1969 *szExtension = '\0';
1971 if (lpszFileExtension)
1973 szExtension[0] = '.';
1974 lstrcpyW(szExtension+1, lpszFileExtension);
1977 for (i = 0; i < 255; i++)
1979 static WCHAR szFormat[] = {'[','%','u',']','%','s',0};
1980 HANDLE hFile;
1981 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
1982 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
1983 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
1984 if (hFile != INVALID_HANDLE_VALUE)
1986 CloseHandle(hFile);
1987 return TRUE;
1991 return FALSE;
1995 /***********************************************************************
1996 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
1998 * The bug we are compensating for is that some drongo at Microsoft
1999 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2000 * As a consequence, CommitUrlCacheEntryA has been effectively
2001 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2002 * is still defined as LPCWSTR. The result (other than madness) is
2003 * that we always need to store lpHeaderInfo in CP_ACP rather than
2004 * in UTF16, and we need to avoid converting lpHeaderInfo in
2005 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2006 * result will lose data for arbitrary binary data.
2009 static BOOL WINAPI CommitUrlCacheEntryInternal(
2010 IN LPCWSTR lpszUrlName,
2011 IN LPCWSTR lpszLocalFileName,
2012 IN FILETIME ExpireTime,
2013 IN FILETIME LastModifiedTime,
2014 IN DWORD CacheEntryType,
2015 IN LPBYTE lpHeaderInfo,
2016 IN DWORD dwHeaderSize,
2017 IN LPCWSTR lpszFileExtension,
2018 IN LPCWSTR lpszOriginalUrl
2021 URLCACHECONTAINER * pContainer;
2022 LPURLCACHE_HEADER pHeader;
2023 CACHEFILE_ENTRY * pEntry;
2024 URL_CACHEFILE_ENTRY * pUrlEntry;
2025 DWORD dwBytesNeeded = sizeof(*pUrlEntry) - sizeof(pUrlEntry->szSourceUrlName);
2026 DWORD dwOffsetLocalFileName = 0;
2027 DWORD dwOffsetHeader = 0;
2028 DWORD dwFileSizeLow = 0;
2029 DWORD dwFileSizeHigh = 0;
2030 BYTE cDirectory = 0;
2031 char achFile[MAX_PATH];
2032 char achUrl[MAX_PATH];
2033 char *pchLocalFileName = 0;
2035 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %s)\n",
2036 debugstr_w(lpszUrlName),
2037 debugstr_w(lpszLocalFileName),
2038 CacheEntryType,
2039 lpHeaderInfo,
2040 dwHeaderSize,
2041 debugstr_w(lpszFileExtension),
2042 debugstr_w(lpszOriginalUrl));
2044 if (lpszOriginalUrl)
2045 WARN(": lpszOriginalUrl ignored\n");
2047 if (lpszLocalFileName)
2049 HANDLE hFile;
2051 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
2052 if (hFile == INVALID_HANDLE_VALUE)
2054 ERR("couldn't open file %s (error is %ld)\n", debugstr_w(lpszLocalFileName), GetLastError());
2055 return FALSE;
2058 /* Get file size */
2059 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
2060 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
2062 ERR("couldn't get file size (error is %ld)\n", GetLastError());
2063 CloseHandle(hFile);
2064 return FALSE;
2067 CloseHandle(hFile);
2070 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
2071 return FALSE;
2073 if (!URLCacheContainer_OpenIndex(pContainer))
2074 return FALSE;
2076 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2077 return FALSE;
2079 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, achUrl, -1, NULL, NULL);
2081 if (URLCache_FindEntryInHash(pHeader, achUrl, &pEntry))
2083 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2084 FIXME("entry already in cache - don't know what to do!\n");
2086 * SetLastError(ERROR_FILE_NOT_FOUND);
2087 * return FALSE;
2089 return TRUE;
2092 if (lpszLocalFileName)
2094 BOOL bFound = FALSE;
2096 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
2098 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2099 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
2100 SetLastError(ERROR_INVALID_PARAMETER);
2101 return FALSE;
2104 /* skip container path prefix */
2105 lpszLocalFileName += lstrlenW(pContainer->path);
2107 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, -1, NULL, NULL);
2108 pchLocalFileName = achFile;
2110 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
2112 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
2114 bFound = TRUE;
2115 break;
2119 if (!bFound)
2121 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2122 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
2123 SetLastError(ERROR_INVALID_PARAMETER);
2124 return FALSE;
2127 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
2130 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(achUrl) + 1);
2131 if (lpszLocalFileName)
2133 dwOffsetLocalFileName = dwBytesNeeded;
2134 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
2136 if (lpHeaderInfo)
2138 dwOffsetHeader = dwBytesNeeded;
2139 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
2142 /* round up to next block */
2143 if (dwBytesNeeded % BLOCKSIZE)
2145 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
2146 dwBytesNeeded += BLOCKSIZE;
2149 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
2151 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2152 ERR("no free entries\n");
2153 return FALSE;
2156 /* FindFirstFreeEntry fills in blocks used */
2157 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
2158 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
2159 pUrlEntry->CacheDir = cDirectory;
2160 pUrlEntry->CacheEntryType = CacheEntryType;
2161 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
2162 pUrlEntry->dwExemptDelta = 0;
2163 pUrlEntry->dwHitRate = 0;
2164 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
2165 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
2166 pUrlEntry->dwOffsetUrl = sizeof(*pUrlEntry) - sizeof(pUrlEntry->szSourceUrlName);
2167 pUrlEntry->dwSizeHigh = 0;
2168 pUrlEntry->dwSizeLow = dwFileSizeLow;
2169 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
2170 pUrlEntry->dwUseCount = 0;
2171 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
2172 pUrlEntry->LastModifiedTime = LastModifiedTime;
2173 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
2174 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
2175 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
2176 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
2178 /*** Unknowns ***/
2179 pUrlEntry->dwUnknown1 = 0;
2180 pUrlEntry->dwUnknown2 = 0;
2181 pUrlEntry->dwUnknown3 = 0x60;
2182 pUrlEntry->Unknown4 = 0;
2183 pUrlEntry->wUnknown5 = 0x1010;
2184 pUrlEntry->dwUnknown6 = 0;
2185 pUrlEntry->dwUnknown7 = 0;
2186 pUrlEntry->dwUnknown8 = 0;
2189 strcpy(pUrlEntry->szSourceUrlName, achUrl);
2190 if (dwOffsetLocalFileName)
2191 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName);
2192 if (dwOffsetHeader)
2193 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
2195 if (!URLCache_AddEntryToHash(pHeader, achUrl, (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader)))
2197 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2198 return FALSE;
2201 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2203 return TRUE;
2206 /***********************************************************************
2207 * CommitUrlCacheEntryA (WININET.@)
2210 BOOL WINAPI CommitUrlCacheEntryA(
2211 IN LPCSTR lpszUrlName,
2212 IN LPCSTR lpszLocalFileName,
2213 IN FILETIME ExpireTime,
2214 IN FILETIME LastModifiedTime,
2215 IN DWORD CacheEntryType,
2216 IN LPBYTE lpHeaderInfo,
2217 IN DWORD dwHeaderSize,
2218 IN LPCSTR lpszFileExtension,
2219 IN LPCSTR lpszOriginalUrl
2222 DWORD len;
2223 WCHAR *url_name;
2224 WCHAR *local_file_name;
2225 WCHAR *original_url = NULL;
2226 BOOL bSuccess = FALSE;
2227 DWORD dwError = 0;
2229 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %s)\n",
2230 debugstr_a(lpszUrlName),
2231 debugstr_a(lpszLocalFileName),
2232 CacheEntryType,
2233 lpHeaderInfo,
2234 dwHeaderSize,
2235 debugstr_a(lpszFileExtension),
2236 debugstr_a(lpszOriginalUrl));
2238 if (lpszFileExtension != 0)
2240 SetLastError(ERROR_INVALID_PARAMETER);
2241 return FALSE;
2243 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
2244 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2246 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2247 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0)) != 0 &&
2248 (local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2250 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2251 if (!lpszOriginalUrl ||
2252 ((len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0)) != 0 &&
2253 (original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0))
2255 if (original_url)
2256 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2257 if (CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2258 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2259 NULL, original_url))
2261 bSuccess = TRUE;
2263 else
2265 dwError = GetLastError();
2267 if (original_url)
2268 HeapFree(GetProcessHeap(), 0, original_url);
2270 else
2272 dwError = GetLastError();
2274 HeapFree(GetProcessHeap(), 0, local_file_name);
2276 else
2278 dwError = GetLastError();
2280 HeapFree(GetProcessHeap(), 0, url_name);
2281 if (!bSuccess)
2282 SetLastError(dwError);
2284 return bSuccess;
2287 /***********************************************************************
2288 * CommitUrlCacheEntryW (WININET.@)
2291 BOOL WINAPI CommitUrlCacheEntryW(
2292 IN LPCWSTR lpszUrlName,
2293 IN LPCWSTR lpszLocalFileName,
2294 IN FILETIME ExpireTime,
2295 IN FILETIME LastModifiedTime,
2296 IN DWORD CacheEntryType,
2297 IN LPWSTR lpHeaderInfo,
2298 IN DWORD dwHeaderSize,
2299 IN LPCWSTR lpszFileExtension,
2300 IN LPCWSTR lpszOriginalUrl
2303 DWORD dwError = 0;
2304 BOOL bSuccess = FALSE;
2305 DWORD len = 0;
2306 CHAR *header_info = NULL;
2308 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %s)\n",
2309 debugstr_w(lpszUrlName),
2310 debugstr_w(lpszLocalFileName),
2311 CacheEntryType,
2312 lpHeaderInfo,
2313 dwHeaderSize,
2314 debugstr_w(lpszFileExtension),
2315 debugstr_w(lpszOriginalUrl));
2317 if (!lpHeaderInfo ||
2318 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2319 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2321 if (header_info)
2322 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2323 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2324 CacheEntryType, header_info, len, lpszFileExtension, lpszOriginalUrl))
2326 bSuccess = TRUE;
2328 else
2330 dwError = GetLastError();
2332 if (header_info)
2334 HeapFree(GetProcessHeap(), 0, header_info);
2335 if (!bSuccess)
2336 SetLastError(dwError);
2339 return bSuccess;
2342 /***********************************************************************
2343 * ReadUrlCacheEntryStream (WININET.@)
2346 BOOL WINAPI ReadUrlCacheEntryStream(
2347 IN HANDLE hUrlCacheStream,
2348 IN DWORD dwLocation,
2349 IN OUT LPVOID lpBuffer,
2350 IN OUT LPDWORD lpdwLen,
2351 IN DWORD dwReserved
2354 /* Get handle to file from 'stream' */
2355 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2357 if (dwReserved != 0)
2359 ERR("dwReserved != 0\n");
2360 SetLastError(ERROR_INVALID_PARAMETER);
2361 return FALSE;
2364 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2366 SetLastError(ERROR_INVALID_HANDLE);
2367 return FALSE;
2370 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2371 return FALSE;
2372 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2375 /***********************************************************************
2376 * RetrieveUrlCacheEntryStreamA (WININET.@)
2379 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2380 IN LPCSTR lpszUrlName,
2381 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2382 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2383 IN BOOL fRandomRead,
2384 IN DWORD dwReserved
2387 /* NOTE: this is not the same as the way that the native
2388 * version allocates 'stream' handles. I did it this way
2389 * as it is much easier and no applications should depend
2390 * on this behaviour. (Native version appears to allocate
2391 * indices into a table)
2393 STREAM_HANDLE * pStream;
2394 HANDLE hFile;
2396 TRACE( "(%s, %p, %p, %x, 0x%08lx)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2397 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2399 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2400 lpCacheEntryInfo,
2401 lpdwCacheEntryInfoBufferSize,
2402 dwReserved))
2404 return NULL;
2407 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2408 GENERIC_READ,
2409 FILE_SHARE_READ,
2410 NULL,
2411 OPEN_EXISTING,
2412 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2413 NULL);
2414 if (hFile == INVALID_HANDLE_VALUE)
2415 return FALSE;
2417 /* allocate handle storage space */
2418 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2419 if (!pStream)
2421 CloseHandle(hFile);
2422 SetLastError(ERROR_OUTOFMEMORY);
2423 return FALSE;
2426 pStream->hFile = hFile;
2427 strcpy(pStream->lpszUrl, lpszUrlName);
2428 return (HANDLE)pStream;
2431 /***********************************************************************
2432 * RetrieveUrlCacheEntryStreamW (WININET.@)
2435 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2436 IN LPCWSTR lpszUrlName,
2437 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2438 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2439 IN BOOL fRandomRead,
2440 IN DWORD dwReserved
2443 FIXME( "(%s, %p, %p, %x, 0x%08lx)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2444 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2445 return NULL;
2448 /***********************************************************************
2449 * UnlockUrlCacheEntryStream (WININET.@)
2452 BOOL WINAPI UnlockUrlCacheEntryStream(
2453 IN HANDLE hUrlCacheStream,
2454 IN DWORD dwReserved
2457 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2459 if (dwReserved != 0)
2461 ERR("dwReserved != 0\n");
2462 SetLastError(ERROR_INVALID_PARAMETER);
2463 return FALSE;
2466 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2468 SetLastError(ERROR_INVALID_HANDLE);
2469 return FALSE;
2472 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2473 return FALSE;
2475 /* close file handle */
2476 CloseHandle(pStream->hFile);
2478 /* free allocated space */
2479 HeapFree(GetProcessHeap(), 0, pStream);
2481 return TRUE;
2485 /***********************************************************************
2486 * DeleteUrlCacheEntryA (WININET.@)
2489 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2491 URLCACHECONTAINER * pContainer;
2492 LPURLCACHE_HEADER pHeader;
2493 CACHEFILE_ENTRY * pEntry;
2494 DWORD dwStartBlock;
2495 DWORD dwBlock;
2496 BYTE * AllocationTable;
2498 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2500 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
2501 return FALSE;
2503 if (!URLCacheContainer_OpenIndex(pContainer))
2504 return FALSE;
2506 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2507 return FALSE;
2509 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
2511 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2512 TRACE("entry %s not found!\n", lpszUrlName);
2513 SetLastError(ERROR_FILE_NOT_FOUND);
2514 return FALSE;
2517 AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
2519 /* update allocation table */
2520 dwStartBlock = ((DWORD)pEntry - (DWORD)pHeader) / BLOCKSIZE;
2521 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
2522 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
2524 URLCache_DeleteEntry(pEntry);
2526 URLCache_DeleteEntryFromHash(pHeader, lpszUrlName);
2528 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2530 return TRUE;
2533 /***********************************************************************
2534 * DeleteUrlCacheEntryW (WININET.@)
2537 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2539 FIXME("(%s) stub\n", debugstr_w(lpszUrlName));
2540 return TRUE;
2543 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2545 FIXME("(0x%08lx, 0x%08lx) stub\n", d1, d2);
2546 return TRUE;
2549 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2551 FIXME("(0x%08lx, 0x%08lx) stub\n", d1, d2);
2552 return TRUE;
2555 /***********************************************************************
2556 * CreateCacheContainerA (WININET.@)
2558 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2559 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2561 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) stub\n",
2562 d1, d2, d3, d4, d5, d6, d7, d8);
2563 return TRUE;
2566 /***********************************************************************
2567 * CreateCacheContainerW (WININET.@)
2569 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2570 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2572 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) stub\n",
2573 d1, d2, d3, d4, d5, d6, d7, d8);
2574 return TRUE;
2577 /***********************************************************************
2578 * FindCloseUrlCache (WININET.@)
2580 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
2582 FIXME("(%p) stub\n", hEnumHandle);
2583 return TRUE;
2586 /***********************************************************************
2587 * FindFirstUrlCacheContainerA (WININET.@)
2589 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2591 FIXME("(%p, %p, %p, 0x%08lx) stub\n", p1, p2, p3, d1 );
2592 return NULL;
2595 /***********************************************************************
2596 * FindFirstUrlCacheContainerW (WININET.@)
2598 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2600 FIXME("(%p, %p, %p, 0x%08lx) stub\n", p1, p2, p3, d1 );
2601 return NULL;
2604 /***********************************************************************
2605 * FindNextUrlCacheContainerA (WININET.@)
2607 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
2609 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2610 return FALSE;
2613 /***********************************************************************
2614 * FindNextUrlCacheContainerW (WININET.@)
2616 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
2618 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2619 return FALSE;
2622 HANDLE WINAPI FindFirstUrlCacheEntryExA(
2623 LPCSTR lpszUrlSearchPattern,
2624 DWORD dwFlags,
2625 DWORD dwFilter,
2626 GROUPID GroupId,
2627 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2628 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2629 LPVOID lpReserved,
2630 LPDWORD pcbReserved2,
2631 LPVOID lpReserved3
2634 FIXME("(%s, 0x%08lx, 0x%08lx, 0x%08lx%08lx, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
2635 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2636 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2637 SetLastError(ERROR_FILE_NOT_FOUND);
2638 return NULL;
2641 HANDLE WINAPI FindFirstUrlCacheEntryExW(
2642 LPCWSTR lpszUrlSearchPattern,
2643 DWORD dwFlags,
2644 DWORD dwFilter,
2645 GROUPID GroupId,
2646 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2647 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2648 LPVOID lpReserved,
2649 LPDWORD pcbReserved2,
2650 LPVOID lpReserved3
2653 FIXME("(%s, 0x%08lx, 0x%08lx, 0x%08lx%08lx, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
2654 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2655 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2656 SetLastError(ERROR_FILE_NOT_FOUND);
2657 return NULL;
2660 /***********************************************************************
2661 * FindFirstUrlCacheEntryA (WININET.@)
2664 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
2665 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2667 FIXME("(%s, %p, %p): stub\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2668 SetLastError(ERROR_FILE_NOT_FOUND);
2669 return 0;
2672 /***********************************************************************
2673 * FindFirstUrlCacheEntryW (WININET.@)
2676 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
2677 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2679 FIXME("(%s, %p, %p): stub\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2680 return 0;
2683 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
2684 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
2686 FIXME("(0x%08lx, 0x%08lx, %p, 0x%08lx, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
2687 dwSearchCondition, lpGroupId, lpReserved);
2688 return NULL;
2691 BOOL WINAPI FindNextUrlCacheEntryA(
2692 HANDLE hEnumHandle,
2693 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
2694 LPDWORD lpdwNextCacheEntryInfoBufferSize
2697 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2698 return FALSE;
2701 BOOL WINAPI FindNextUrlCacheEntryW(
2702 HANDLE hEnumHandle,
2703 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
2704 LPDWORD lpdwNextCacheEntryInfoBufferSize
2707 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2708 return FALSE;
2711 BOOL WINAPI FindNextUrlCacheEntryExA(
2712 HANDLE hEnumHandle,
2713 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2714 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2715 LPVOID lpReserved,
2716 LPDWORD pcbReserved2,
2717 LPVOID lpReserved3
2720 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2721 lpReserved, pcbReserved2, lpReserved3);
2722 return FALSE;
2725 BOOL WINAPI FindNextUrlCacheEntryExW(
2726 HANDLE hEnumHandle,
2727 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2728 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2729 LPVOID lpReserved,
2730 LPDWORD pcbReserved2,
2731 LPVOID lpReserved3
2734 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2735 lpReserved, pcbReserved2, lpReserved3);
2736 return FALSE;
2739 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
2741 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
2742 return FALSE;
2745 /***********************************************************************
2746 * CreateUrlCacheGroup (WININET.@)
2749 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
2751 FIXME("(0x%08lx, %p): stub\n", dwFlags, lpReserved);
2752 return FALSE;
2755 /***********************************************************************
2756 * DeleteUrlCacheGroup (WININET.@)
2759 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
2761 FIXME("(0x%08lx%08lx, 0x%08lx, %p) stub\n",
2762 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
2763 return FALSE;
2766 /***********************************************************************
2767 * SetUrlCacheEntryGroupA (WININET.@)
2770 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
2771 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2772 LPVOID lpReserved)
2774 FIXME("(%s, 0x%08lx, 0x%08lx%08lx, %p, 0x%08lx, %p) stub\n",
2775 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2776 pbGroupAttributes, cbGroupAttributes, lpReserved);
2777 SetLastError(ERROR_FILE_NOT_FOUND);
2778 return FALSE;
2781 /***********************************************************************
2782 * SetUrlCacheEntryGroupW (WININET.@)
2785 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
2786 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2787 LPVOID lpReserved)
2789 FIXME("(%s, 0x%08lx, 0x%08lx%08lx, %p, 0x%08lx, %p) stub\n",
2790 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2791 pbGroupAttributes, cbGroupAttributes, lpReserved);
2792 SetLastError(ERROR_FILE_NOT_FOUND);
2793 return FALSE;
2796 /***********************************************************************
2797 * GetUrlCacheConfigInfoW (WININET.@)
2799 BOOL WINAPI GetUrlCacheConfigInfoW(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2801 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2802 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2803 return FALSE;
2806 /***********************************************************************
2807 * GetUrlCacheConfigInfoA (WININET.@)
2809 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
2811 BOOL WINAPI GetUrlCacheConfigInfoA(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2813 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2814 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2815 return FALSE;
2818 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2819 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
2820 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2822 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p, %p) stub\n",
2823 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2824 lpdwGroupInfo, lpReserved);
2825 return FALSE;
2828 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2829 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
2830 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2832 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p, %p) stub\n",
2833 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2834 lpdwGroupInfo, lpReserved);
2835 return FALSE;
2838 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2839 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
2841 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p) stub\n",
2842 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2843 return TRUE;
2846 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2847 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
2849 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p) stub\n",
2850 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2851 return TRUE;
2854 BOOL WINAPI SetUrlCacheConfigInfoA( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2856 FIXME("(%p, 0x%08lx) stub\n", lpCacheConfigInfo, dwFieldControl);
2857 return TRUE;
2860 BOOL WINAPI SetUrlCacheConfigInfoW( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2862 FIXME("(%p, 0x%08lx) stub\n", lpCacheConfigInfo, dwFieldControl);
2863 return TRUE;
2866 /***********************************************************************
2867 * DeleteIE3Cache (WININET.@)
2869 * Deletes the files used by the IE3 URL caching system.
2871 * PARAMS
2872 * hWnd [I] A dummy window.
2873 * hInst [I] Instance of process calling the function.
2874 * lpszCmdLine [I] Options used by function.
2875 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
2877 * RETURNS
2878 * nothing
2880 void WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
2882 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);