- More implementation of view
[wine/testsucceed.git] / dlls / wininet / urlcache.c
blob3be7e5dd34f7eab0ec0e37a0e2bf72ad28980abc
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)
65 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
66 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
67 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
68 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
69 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
71 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
73 typedef struct _CACHEFILE_ENTRY
75 /* union
76 {*/
77 DWORD dwSignature; /* e.g. "URL " */
78 /* CHAR szSignature[4];
79 };*/
80 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
81 } CACHEFILE_ENTRY;
83 typedef struct _URL_CACHEFILE_ENTRY
85 CACHEFILE_ENTRY CacheFileEntry;
86 FILETIME LastModifiedTime;
87 FILETIME LastAccessTime;
88 WORD wExpiredDate; /* expire date in dos format */
89 WORD wExpiredTime; /* expire time in dos format */
90 DWORD dwUnknown1; /* usually zero */
91 DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
92 DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
93 DWORD dwUnknown2; /* usually zero */
94 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
95 DWORD dwUnknown3; /* usually 0x60 */
96 DWORD dwOffsetUrl; /* usually 0x68 */
97 BYTE CacheDir; /* index of cache directory this url is stored in */
98 BYTE Unknown4; /* usually zero */
99 WORD wUnknown5; /* usually 0x1010 */
100 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
101 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
102 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
103 DWORD dwHeaderInfoSize;
104 DWORD dwUnknown6; /* usually zero */
105 WORD wLastSyncDate; /* last sync date in dos format */
106 WORD wLastSyncTime; /* last sync time in dos format */
107 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
108 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
109 WORD wUnknownDate; /* usually same as wLastSyncDate */
110 WORD wUnknownTime; /* usually same as wLastSyncTime */
111 DWORD dwUnknown7; /* usually zero */
112 DWORD dwUnknown8; /* usually zero */
113 CHAR szSourceUrlName[1]; /* start of url */
114 /* packing to dword align start of next field */
115 /* CHAR szLocalFileName[]; (local file name exluding path) */
116 /* packing to dword align start of next field */
117 /* CHAR szHeaderInfo[]; (header info) */
118 } URL_CACHEFILE_ENTRY;
120 struct _HASH_ENTRY
122 DWORD dwHashKey;
123 DWORD dwOffsetEntry;
126 typedef struct _HASH_CACHEFILE_ENTRY
128 CACHEFILE_ENTRY CacheFileEntry;
129 DWORD dwAddressNext;
130 DWORD dwHashTableNumber;
131 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
132 } HASH_CACHEFILE_ENTRY;
134 typedef struct _DIRECTORY_DATA
136 DWORD dwUnknown;
137 char filename[DIR_LENGTH];
138 } DIRECTORY_DATA;
140 typedef struct _URLCACHE_HEADER
142 char szSignature[28];
143 DWORD dwFileSize;
144 DWORD dwOffsetFirstHashTable;
145 DWORD dwIndexCapacityInBlocks;
146 DWORD dwBlocksInUse; /* is this right? */
147 DWORD dwUnknown1;
148 DWORD dwCacheLimitLow; /* disk space limit for cache */
149 DWORD dwCacheLimitHigh; /* disk space limit for cache */
150 DWORD dwUnknown4; /* current disk space usage for cache? */
151 DWORD dwUnknown5; /* current disk space usage for cache? */
152 DWORD dwUnknown6; /* possibly a flag? */
153 DWORD dwUnknown7;
154 BYTE DirectoryCount; /* number of directory_data's */
155 BYTE Unknown8[3]; /* just padding? */
156 DIRECTORY_DATA directory_data[1]; /* first directory entry */
157 } URLCACHE_HEADER, *LPURLCACHE_HEADER;
158 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;
160 typedef struct _STREAM_HANDLE
162 HANDLE hFile;
163 CHAR lpszUrl[1];
164 } STREAM_HANDLE;
166 typedef struct _URLCACHECONTAINER
168 struct list entry; /* part of a list */
169 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
170 LPWSTR path; /* path to url container directory */
171 HANDLE hMapping; /* handle of file mapping */
172 DWORD file_size; /* size of file when mapping was opened */
173 HANDLE hMutex; /* hande of mutex */
174 } URLCACHECONTAINER;
177 /* List of all containers available */
178 static struct list UrlContainers = LIST_INIT(UrlContainers);
181 /***********************************************************************
182 * URLCache_PathToObjectName (Internal)
184 * Converts a path to a name suitable for use as a Win32 object name.
185 * Replaces '\\' characters in-place with the specified character
186 * (usually '_' or '!')
188 * RETURNS
189 * nothing
192 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
194 for (; *lpszPath; lpszPath++)
196 if (*lpszPath == '\\')
197 *lpszPath = replace;
201 /***********************************************************************
202 * URLCacheContainer_OpenIndex (Internal)
204 * Opens the index file and saves mapping handle in hCacheIndexMapping
206 * RETURNS
207 * TRUE if succeeded
208 * FALSE if failed
211 static BOOL URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
213 HANDLE hFile;
214 WCHAR wszFilePath[MAX_PATH];
215 DWORD dwFileSize;
217 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
218 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};
220 if (pContainer->hMapping)
221 return TRUE;
223 strcpyW(wszFilePath, pContainer->path);
224 strcatW(wszFilePath, wszIndex);
226 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
227 if (hFile == INVALID_HANDLE_VALUE)
229 FIXME("need to create cache index file\n");
230 return FALSE;
233 dwFileSize = GetFileSize(hFile, NULL);
234 if (dwFileSize == INVALID_FILE_SIZE)
235 return FALSE;
237 if (dwFileSize == 0)
239 FIXME("need to create cache index file\n");
240 return FALSE;
243 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize);
244 URLCache_PathToObjectName(wszFilePath, '_');
245 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath);
246 if (!pContainer->hMapping)
247 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath);
248 CloseHandle(hFile);
249 if (!pContainer->hMapping)
251 ERR("Couldn't create file mapping (error is %ld)\n", GetLastError());
252 return FALSE;
255 return TRUE;
258 /***********************************************************************
259 * URLCacheContainer_CloseIndex (Internal)
261 * Closes the index
263 * RETURNS
264 * nothing
267 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer)
269 CloseHandle(pContainer->hMapping);
270 pContainer->hMapping = NULL;
273 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name)
275 URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER));
276 int path_len = strlenW(path);
277 int cache_prefix_len = strlenW(cache_prefix);
279 if (!pContainer)
281 return FALSE;
284 pContainer->hMapping = NULL;
285 pContainer->file_size = 0;
287 pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR));
288 if (!pContainer->path)
290 HeapFree(GetProcessHeap(), 0, pContainer);
291 return FALSE;
294 memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR));
296 pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR));
297 if (!pContainer->cache_prefix)
299 HeapFree(GetProcessHeap(), 0, pContainer->path);
300 HeapFree(GetProcessHeap(), 0, pContainer);
301 return FALSE;
304 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR));
306 CharLowerW(mutex_name);
307 URLCache_PathToObjectName(mutex_name, '!');
309 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
311 ERR("couldn't create mutex (error is %ld)\n", GetLastError());
312 HeapFree(GetProcessHeap(), 0, pContainer->path);
313 HeapFree(GetProcessHeap(), 0, pContainer);
314 return FALSE;
317 list_add_head(&UrlContainers, &pContainer->entry);
319 return TRUE;
322 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer)
324 list_remove(&pContainer->entry);
326 URLCacheContainer_CloseIndex(pContainer);
327 CloseHandle(pContainer->hMutex);
328 HeapFree(GetProcessHeap(), 0, pContainer->path);
329 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix);
330 HeapFree(GetProcessHeap(), 0, pContainer);
333 void URLCacheContainers_CreateDefaults()
335 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
336 static const WCHAR UrlPrefix[] = {0};
337 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
338 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0};
339 static const WCHAR CookieSuffix[] = {0};
340 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0};
341 static const struct
343 int nFolder; /* CSIDL_* constant */
344 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
345 const WCHAR * cache_prefix; /* prefix used to reference the container */
346 } DefaultContainerData[] =
348 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix },
349 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix },
350 { CSIDL_COOKIES, CookieSuffix, CookiePrefix },
352 DWORD i;
354 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++)
356 WCHAR wszCachePath[MAX_PATH];
357 WCHAR wszMutexName[MAX_PATH];
358 int path_len, suffix_len;
360 if (FAILED(SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE)))
362 ERR("Couldn't get path for default container %lu\n", i);
363 continue;
365 path_len = strlenW(wszCachePath);
366 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix);
368 if (path_len + suffix_len + 2 > MAX_PATH)
370 ERR("Path too long\n");
371 continue;
374 wszCachePath[path_len] = '\\';
376 strcpyW(wszMutexName, wszCachePath);
378 if (suffix_len)
380 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
381 wszCachePath[path_len + suffix_len + 1] = '\\';
382 wszCachePath[path_len + suffix_len + 2] = '\0';
385 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName);
389 void URLCacheContainers_DeleteAll()
391 while(!list_empty(&UrlContainers))
392 URLCacheContainer_DeleteContainer(
393 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry)
397 static BOOL URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer)
399 struct list * cursor;
401 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl));
403 LIST_FOR_EACH(cursor, &UrlContainers)
405 URLCACHECONTAINER * pContainer = LIST_ENTRY(cursor, URLCACHECONTAINER, entry);
406 int prefix_len = strlenW(pContainer->cache_prefix);
407 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len))
409 TRACE("found container with prefx %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl));
410 *ppContainer = pContainer;
411 return TRUE;
414 ERR("no container found\n");
415 SetLastError(ERROR_FILE_NOT_FOUND);
416 return FALSE;
419 static BOOL URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer)
421 BOOL ret;
422 LPWSTR lpwszUrl;
423 int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
424 if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR))))
426 MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len);
427 ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer);
428 HeapFree(GetProcessHeap(), 0, lpwszUrl);
429 return ret;
431 return FALSE;
434 /***********************************************************************
435 * URLCacheContainer_LockIndex (Internal)
438 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer)
440 BYTE index;
441 LPVOID pIndexData;
442 URLCACHE_HEADER * pHeader;
444 /* acquire mutex */
445 WaitForSingleObject(pContainer->hMutex, INFINITE);
447 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
449 if (!pIndexData)
451 ReleaseMutex(pContainer->hMutex);
452 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
453 return FALSE;
455 pHeader = (URLCACHE_HEADER *)pIndexData;
457 /* file has grown - we need to remap to prevent us getting
458 * access violations when we try and access beyond the end
459 * of the memory mapped file */
460 if (pHeader->dwFileSize != pContainer->file_size)
462 URLCacheContainer_CloseIndex(pContainer);
463 if (!URLCacheContainer_OpenIndex(pContainer))
465 ReleaseMutex(pContainer->hMutex);
466 return FALSE;
468 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0);
470 if (!pIndexData)
472 ReleaseMutex(pContainer->hMutex);
473 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
474 return FALSE;
476 pHeader = (URLCACHE_HEADER *)pIndexData;
479 TRACE("Signature: %s, file size: %ld bytes\n", pHeader->szSignature, pHeader->dwFileSize);
481 for (index = 0; index < pHeader->DirectoryCount; index++)
483 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename);
486 return pHeader;
489 /***********************************************************************
490 * URLCacheContainer_UnlockIndex (Internal)
493 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader)
495 /* release mutex */
496 ReleaseMutex(pContainer->hMutex);
497 return UnmapViewOfFile(pHeader);
501 #ifndef CHAR_BIT
502 #define CHAR_BIT (8 * sizeof(CHAR))
503 #endif
505 /***********************************************************************
506 * URLCache_Allocation_BlockIsFree (Internal)
508 * Is the specified block number free?
510 * RETURNS
511 * zero if free
512 * non-zero otherwise
515 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber)
517 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
518 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0;
521 /***********************************************************************
522 * URLCache_Allocation_BlockFree (Internal)
524 * Marks the specified block as free
526 * RETURNS
527 * nothing
530 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber)
532 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT));
533 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask;
536 /***********************************************************************
537 * URLCache_Allocation_BlockAllocate (Internal)
539 * Marks the specified block as allocated
541 * RETURNS
542 * nothing
545 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber)
547 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT);
548 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask;
551 /***********************************************************************
552 * URLCache_FindFirstFreeEntry (Internal)
554 * Finds and allocates the first block of free space big enough and
555 * sets ppEntry to point to it.
557 * RETURNS
558 * TRUE if it had enough space
559 * FALSE if it couldn't find enough space
562 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry)
564 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
565 DWORD dwBlockNumber;
566 DWORD dwFreeCounter;
567 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++)
569 for (dwFreeCounter = 0;
570 dwFreeCounter < dwBlocksNeeded &&
571 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks &&
572 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter);
573 dwFreeCounter++)
574 TRACE("Found free block at no. %ld (0x%lx)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
576 if (dwFreeCounter == dwBlocksNeeded)
578 DWORD index;
579 TRACE("Found free blocks starting at no. %ld (0x%lx)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
580 for (index = 0; index < dwBlocksNeeded; index++)
581 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index);
582 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE);
583 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded;
584 return TRUE;
587 FIXME("Grow file\n");
588 return FALSE;
591 /***********************************************************************
592 * URLCache_DeleteEntry (Internal)
594 * Deletes the specified entry and frees the space allocated to it
596 * RETURNS
597 * TRUE if it succeeded
598 * FALSE if it failed
601 static BOOL URLCache_DeleteEntry(CACHEFILE_ENTRY * pEntry)
603 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE);
604 return TRUE;
607 /***********************************************************************
608 * URLCache_LocalFileNameToPathW (Internal)
610 * Copies the full path to the specified buffer given the local file
611 * name and the index of the directory it is in. Always sets value in
612 * lpBufferSize to the required buffer size (in bytes).
614 * RETURNS
615 * TRUE if the buffer was big enough
616 * FALSE if the buffer was too small
619 static BOOL URLCache_LocalFileNameToPathW(
620 const URLCACHECONTAINER * pContainer,
621 LPCURLCACHE_HEADER pHeader,
622 LPCSTR szLocalFileName,
623 BYTE Directory,
624 LPWSTR wszPath,
625 LPLONG lpBufferSize)
627 LONG nRequired;
628 int path_len = strlenW(pContainer->path);
629 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
630 if (Directory >= pHeader->DirectoryCount)
632 *lpBufferSize = 0;
633 return FALSE;
636 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR);
637 if (nRequired < *lpBufferSize)
639 int dir_len;
641 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
642 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
643 wszPath[dir_len + path_len] = '\\';
644 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len);
645 *lpBufferSize = nRequired;
646 return TRUE;
648 *lpBufferSize = nRequired;
649 return FALSE;
652 /***********************************************************************
653 * URLCache_LocalFileNameToPathA (Internal)
655 * Copies the full path to the specified buffer given the local file
656 * name and the index of the directory it is in. Always sets value in
657 * lpBufferSize to the required buffer size.
659 * RETURNS
660 * TRUE if the buffer was big enough
661 * FALSE if the buffer was too small
664 static BOOL URLCache_LocalFileNameToPathA(
665 const URLCACHECONTAINER * pContainer,
666 LPCURLCACHE_HEADER pHeader,
667 LPCSTR szLocalFileName,
668 BYTE Directory,
669 LPSTR szPath,
670 LPLONG lpBufferSize)
672 LONG nRequired;
673 int path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL);
674 int file_name_len = strlen(szLocalFileName);
675 int dir_len = DIR_LENGTH;
676 if (Directory >= pHeader->DirectoryCount)
678 *lpBufferSize = 0;
679 return FALSE;
682 nRequired = (path_len + dir_len + file_name_len + 1) * sizeof(WCHAR);
683 if (nRequired < *lpBufferSize)
685 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, -1, NULL, NULL);
686 strncpy(szPath, pHeader->directory_data[Directory].filename, DIR_LENGTH);
687 szPath[dir_len + path_len] = '\\';
688 strcpy(szPath + dir_len + path_len + 1, szLocalFileName);
689 *lpBufferSize = nRequired;
690 return TRUE;
692 *lpBufferSize = nRequired;
693 return FALSE;
696 /***********************************************************************
697 * URLCache_CopyEntry (Internal)
699 * Copies an entry from the cache index file to the Win32 structure
701 * RETURNS
702 * TRUE if the buffer was big enough
703 * FALSE if the buffer was too small
706 static BOOL URLCache_CopyEntry(
707 URLCACHECONTAINER * pContainer,
708 LPCURLCACHE_HEADER pHeader,
709 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
710 LPDWORD lpdwBufferSize,
711 URL_CACHEFILE_ENTRY * pUrlEntry,
712 BOOL bUnicode)
714 int lenUrl;
715 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo);
717 if (*lpdwBufferSize >= dwRequiredSize)
719 lpCacheEntryInfo->lpHeaderInfo = NULL;
720 lpCacheEntryInfo->lpszFileExtension = NULL;
721 lpCacheEntryInfo->lpszLocalFileName = NULL;
722 lpCacheEntryInfo->lpszSourceUrlName = NULL;
723 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType;
724 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta;
725 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize;
726 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate;
727 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->dwSizeHigh;
728 lpCacheEntryInfo->dwSizeLow = pUrlEntry->dwSizeLow;
729 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo);
730 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount;
731 DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime);
732 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime;
733 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime;
734 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime;
735 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime;
736 DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime);
739 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
740 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
741 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
742 if (bUnicode)
743 lenUrl = MultiByteToWideChar(CP_ACP, 0, pUrlEntry->szSourceUrlName, -1, NULL, 0);
744 else
745 lenUrl = strlen(pUrlEntry->szSourceUrlName);
746 dwRequiredSize += lenUrl + 1;
748 /* FIXME: is source url optional? */
749 if (*lpdwBufferSize >= dwRequiredSize)
751 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrl - 1;
752 if (bUnicode)
753 MultiByteToWideChar(CP_ACP, 0, pUrlEntry->szSourceUrlName, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1);
754 else
755 memcpy(lpCacheEntryInfo->lpszSourceUrlName, pUrlEntry->szSourceUrlName, (lenUrl + 1) * sizeof(CHAR));
758 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
759 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
760 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
762 if (pUrlEntry->dwOffsetLocalName)
764 LONG nLocalFilePathSize;
765 LPSTR lpszLocalFileName;
766 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize;
767 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize;
768 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) ||
769 URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize))
771 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName;
773 dwRequiredSize += nLocalFilePathSize;
775 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
776 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
777 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
779 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1;
781 if (*lpdwBufferSize >= dwRequiredSize)
783 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1;
784 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize);
785 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0';
787 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize))
788 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4));
789 dwRequiredSize = DWORD_ALIGN(dwRequiredSize);
791 if (dwRequiredSize > *lpdwBufferSize)
793 *lpdwBufferSize = dwRequiredSize;
794 SetLastError(ERROR_INSUFFICIENT_BUFFER);
795 return FALSE;
797 *lpdwBufferSize = dwRequiredSize;
798 return TRUE;
802 /***********************************************************************
803 * URLCache_SetEntryInfo (Internal)
805 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
806 * according the the flags set by dwFieldControl.
808 * RETURNS
809 * TRUE if the buffer was big enough
810 * FALSE if the buffer was too small
813 static BOOL URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl)
815 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC)
816 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime;
817 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC)
818 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType;
819 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC)
820 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta;
821 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC)
822 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
823 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC)
824 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
825 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC)
826 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate;
827 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC)
828 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime;
829 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC)
830 FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
832 return TRUE;
835 /***********************************************************************
836 * URLCache_HashKey (Internal)
838 * Returns the hash key for a given string
840 * RETURNS
841 * hash key for the string
844 static DWORD URLCache_HashKey(LPCSTR lpszKey)
846 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
847 * but the algorithm and result are not the same!
849 static const unsigned char lookupTable[256] =
851 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
852 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
853 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
854 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
855 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
856 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
857 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
858 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
859 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
860 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
861 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
862 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
863 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
864 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
865 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
866 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
867 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
868 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
869 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
870 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
871 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
872 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
873 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
874 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
875 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
876 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
877 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
878 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
879 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
880 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
881 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
882 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
884 BYTE key[4];
885 DWORD i;
886 int subscript[sizeof(key) / sizeof(key[0])];
888 subscript[0] = *lpszKey;
889 subscript[1] = (char)(*lpszKey + 1);
890 subscript[2] = (char)(*lpszKey + 2);
891 subscript[3] = (char)(*lpszKey + 3);
893 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
894 key[i] = lookupTable[i];
896 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++)
898 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++)
899 key[i] = lookupTable[*lpszKey ^ key[i]];
902 return *(DWORD *)key;
905 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset)
907 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset);
910 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry)
912 /* structure of hash table:
913 * 448 entries divided into 64 blocks
914 * each block therefore contains a chain of 7 key/offset pairs
915 * how position in table is calculated:
916 * 1. the url is hashed in helper function
917 * 2. the key % 64 * 8 is the offset
918 * 3. the key in the hash table is the hash key aligned to 64
920 * note:
921 * there can be multiple hash tables in the file and the offset to
922 * the next one is stored in the header of the hash table
924 DWORD key = URLCache_HashKey(lpszUrl);
925 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
926 HASH_CACHEFILE_ENTRY * pHashEntry;
927 DWORD dwHashTableNumber = 0;
929 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
931 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
932 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
933 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
935 int i;
936 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
938 ERR("Error: not right hash table number (%ld) expected %ld\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
939 continue;
941 /* make sure that it is in fact a hash entry */
942 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
944 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
945 continue;
948 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
950 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
951 if (key == (DWORD)(pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES)
953 /* FIXME: we should make sure that this is the right element
954 * before returning and claiming that it is. We can do this
955 * by doing a simple compare between the URL we were given
956 * and the URL stored in the entry. However, this assumes
957 * we know the format of all the entries stored in the
958 * hash table */
959 *ppHashEntry = pHashElement;
960 return TRUE;
964 return FALSE;
967 /***********************************************************************
968 * URLCache_FindEntryInHash (Internal)
970 * Searches all the hash tables in the index for the given URL and
971 * returns the entry, if it was found, in ppEntry
973 * RETURNS
974 * TRUE if the entry was found
975 * FALSE if the entry could not be found
978 static BOOL URLCache_FindEntryInHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, CACHEFILE_ENTRY ** ppEntry)
980 struct _HASH_ENTRY * pHashEntry;
981 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
983 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry);
984 return TRUE;
986 return FALSE;
989 /***********************************************************************
990 * URLCache_HashEntrySetUse (Internal)
992 * Searches all the hash tables in the index for the given URL and
993 * sets the use count (stored or'ed with key)
995 * RETURNS
996 * TRUE if the entry was found
997 * FALSE if the entry could not be found
1000 static BOOL URLCache_HashEntrySetUse(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwUseCount)
1002 struct _HASH_ENTRY * pHashEntry;
1003 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1005 pHashEntry->dwHashKey = dwUseCount | (DWORD)(pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1006 return TRUE;
1008 return FALSE;
1011 /***********************************************************************
1012 * URLCache_DeleteEntryFromHash (Internal)
1014 * Searches all the hash tables in the index for the given URL and
1015 * then if found deletes the entry.
1017 * RETURNS
1018 * TRUE if the entry was found
1019 * FALSE if the entry could not be found
1022 static BOOL URLCache_DeleteEntryFromHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl)
1024 struct _HASH_ENTRY * pHashEntry;
1025 if (URLCache_FindHash(pHeader, lpszUrl, &pHashEntry))
1027 pHashEntry->dwHashKey = HASHTABLE_FREE;
1028 pHashEntry->dwOffsetEntry = HASHTABLE_FREE;
1029 return TRUE;
1031 return FALSE;
1034 /***********************************************************************
1035 * URLCache_AddEntryToHash (Internal)
1037 * Searches all the hash tables for a free slot based on the offset
1038 * generated from the hash key. If a free slot is found, the offset and
1039 * key are entered into the hash table.
1041 * RETURNS
1042 * TRUE if the entry was added
1043 * FALSE if the entry could not be added
1046 static BOOL URLCache_AddEntryToHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry)
1048 /* see URLCache_FindEntryInHash for structure of hash tables */
1050 DWORD key = URLCache_HashKey(lpszUrl);
1051 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY);
1052 HASH_CACHEFILE_ENTRY * pHashEntry;
1053 DWORD dwHashTableNumber = 0;
1055 key = (DWORD)(key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES;
1057 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable);
1058 ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) >= ENTRY_START_OFFSET) && ((DWORD)((LPBYTE)pHashEntry - (LPBYTE)pHeader) < pHeader->dwFileSize);
1059 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext))
1061 int i;
1062 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++)
1064 ERR("not right hash table number (%ld) expected %ld\n", pHashEntry->dwHashTableNumber, dwHashTableNumber);
1065 break;
1067 /* make sure that it is in fact a hash entry */
1068 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE)
1070 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature);
1071 break;
1074 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1076 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i];
1077 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */
1079 pHashElement->dwHashKey = key;
1080 pHashElement->dwOffsetEntry = dwOffsetEntry;
1081 return TRUE;
1085 FIXME("need to create another hash table\n");
1086 return FALSE;
1089 /***********************************************************************
1090 * GetUrlCacheEntryInfoExA (WININET.@)
1093 BOOL WINAPI GetUrlCacheEntryInfoExA(
1094 LPCSTR lpszUrl,
1095 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1096 LPDWORD lpdwCacheEntryInfoBufSize,
1097 LPSTR lpszReserved,
1098 LPDWORD lpdwReserved,
1099 LPVOID lpReserved,
1100 DWORD dwFlags)
1102 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1103 debugstr_a(lpszUrl),
1104 lpCacheEntryInfo,
1105 lpdwCacheEntryInfoBufSize,
1106 lpszReserved,
1107 lpdwReserved,
1108 lpReserved,
1109 dwFlags);
1111 if ((lpszReserved != NULL) ||
1112 (lpdwReserved != NULL) ||
1113 (lpReserved != NULL))
1115 ERR("Reserved value was not 0\n");
1116 SetLastError(ERROR_INVALID_PARAMETER);
1117 return FALSE;
1119 if (dwFlags != 0)
1120 FIXME("Undocumented flag(s): %lx\n", dwFlags);
1121 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1124 /***********************************************************************
1125 * GetUrlCacheEntryInfoA (WININET.@)
1128 BOOL WINAPI GetUrlCacheEntryInfoA(
1129 IN LPCSTR lpszUrlName,
1130 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1131 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1134 LPURLCACHE_HEADER pHeader;
1135 CACHEFILE_ENTRY * pEntry;
1136 URL_CACHEFILE_ENTRY * pUrlEntry;
1137 URLCACHECONTAINER * pContainer;
1139 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1141 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1142 return FALSE;
1144 if (!URLCacheContainer_OpenIndex(pContainer))
1145 return FALSE;
1147 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1148 return FALSE;
1150 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1152 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1153 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1154 SetLastError(ERROR_FILE_NOT_FOUND);
1155 return FALSE;
1158 if (pEntry->dwSignature != URL_SIGNATURE)
1160 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1161 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1162 SetLastError(ERROR_FILE_NOT_FOUND);
1163 return FALSE;
1166 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1167 TRACE("Found URL: %s\n", debugstr_a(pUrlEntry->szSourceUrlName));
1168 if (pUrlEntry->dwOffsetHeaderInfo)
1169 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1171 if (!URLCache_CopyEntry(
1172 pContainer,
1173 pHeader,
1174 lpCacheEntryInfo,
1175 lpdwCacheEntryInfoBufferSize,
1176 pUrlEntry,
1177 FALSE /* ANSI */))
1179 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1180 return FALSE;
1182 TRACE("Local File Name: %s\n", debugstr_a(lpCacheEntryInfo->lpszLocalFileName));
1184 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1186 return TRUE;
1189 /***********************************************************************
1190 * GetUrlCacheEntryInfoW (WININET.@)
1193 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
1194 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1195 LPDWORD lpdwCacheEntryInfoBufferSize)
1197 LPURLCACHE_HEADER pHeader;
1198 CACHEFILE_ENTRY * pEntry;
1199 URL_CACHEFILE_ENTRY * pUrlEntry;
1200 URLCACHECONTAINER * pContainer;
1201 LPSTR lpszUrlA;
1202 int url_len;
1204 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize);
1206 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1207 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1208 if (!lpszUrlA)
1210 SetLastError(ERROR_OUTOFMEMORY);
1211 return FALSE;
1213 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1215 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1217 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1218 return FALSE;
1221 if (!URLCacheContainer_OpenIndex(pContainer))
1223 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1224 return FALSE;
1227 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1229 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1230 return FALSE;
1233 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1235 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1236 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1237 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1238 SetLastError(ERROR_FILE_NOT_FOUND);
1239 return FALSE;
1241 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1243 if (pEntry->dwSignature != URL_SIGNATURE)
1245 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1246 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1247 SetLastError(ERROR_FILE_NOT_FOUND);
1248 return FALSE;
1251 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1252 TRACE("Found URL: %s\n", debugstr_a(pUrlEntry->szSourceUrlName));
1253 TRACE("Header info: %s\n", debugstr_a((LPSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo));
1255 if (!URLCache_CopyEntry(
1256 pContainer,
1257 pHeader,
1258 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo,
1259 lpdwCacheEntryInfoBufferSize,
1260 pUrlEntry,
1261 TRUE /* UNICODE */))
1263 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1264 return FALSE;
1266 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo->lpszLocalFileName));
1268 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1270 return TRUE;
1273 /***********************************************************************
1274 * GetUrlCacheEntryInfoExW (WININET.@)
1277 BOOL WINAPI GetUrlCacheEntryInfoExW(
1278 LPCWSTR lpszUrl,
1279 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1280 LPDWORD lpdwCacheEntryInfoBufSize,
1281 LPWSTR lpszReserved,
1282 LPDWORD lpdwReserved,
1283 LPVOID lpReserved,
1284 DWORD dwFlags)
1286 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1287 debugstr_w(lpszUrl),
1288 lpCacheEntryInfo,
1289 lpdwCacheEntryInfoBufSize,
1290 lpszReserved,
1291 lpdwReserved,
1292 lpReserved,
1293 dwFlags);
1295 if ((lpszReserved != NULL) ||
1296 (lpdwReserved != NULL) ||
1297 (lpReserved != NULL))
1299 ERR("Reserved value was not 0\n");
1300 SetLastError(ERROR_INVALID_PARAMETER);
1301 return FALSE;
1303 if (dwFlags != 0)
1304 FIXME("Undocumented flag(s): %lx\n", dwFlags);
1305 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize);
1308 /***********************************************************************
1309 * SetUrlCacheEntryInfoA (WININET.@)
1311 BOOL WINAPI SetUrlCacheEntryInfoA(
1312 LPCSTR lpszUrlName,
1313 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1314 DWORD dwFieldControl)
1316 LPURLCACHE_HEADER pHeader;
1317 CACHEFILE_ENTRY * pEntry;
1318 URLCACHECONTAINER * pContainer;
1320 TRACE("(%s, %p, 0x%08lx)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
1322 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1323 return FALSE;
1325 if (!URLCacheContainer_OpenIndex(pContainer))
1326 return FALSE;
1328 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1329 return FALSE;
1331 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1333 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1334 WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
1335 SetLastError(ERROR_FILE_NOT_FOUND);
1336 return FALSE;
1339 if (pEntry->dwSignature != URL_SIGNATURE)
1341 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1342 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1343 SetLastError(ERROR_FILE_NOT_FOUND);
1344 return FALSE;
1347 URLCache_SetEntryInfo(
1348 (URL_CACHEFILE_ENTRY *)pEntry,
1349 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo,
1350 dwFieldControl);
1352 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1354 return TRUE;
1357 /***********************************************************************
1358 * SetUrlCacheEntryInfoW (WININET.@)
1360 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl)
1362 LPURLCACHE_HEADER pHeader;
1363 CACHEFILE_ENTRY * pEntry;
1364 URLCACHECONTAINER * pContainer;
1365 LPSTR lpszUrlA;
1366 int url_len;
1368 TRACE("(%s, %p, 0x%08lx)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl);
1370 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
1371 lpszUrlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR));
1372 if (!lpszUrlA)
1374 SetLastError(ERROR_OUTOFMEMORY);
1375 return FALSE;
1377 WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, lpszUrlA, url_len, NULL, NULL);
1379 if (!URLCacheContainers_FindContainerW(lpszUrl, &pContainer))
1381 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1382 return FALSE;
1385 if (!URLCacheContainer_OpenIndex(pContainer))
1387 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1388 return FALSE;
1391 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1393 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1394 return FALSE;
1397 if (!URLCache_FindEntryInHash(pHeader, lpszUrlA, &pEntry))
1399 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1400 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1401 WARN("entry %s not found!\n", debugstr_a(lpszUrlA));
1402 SetLastError(ERROR_FILE_NOT_FOUND);
1403 return FALSE;
1405 HeapFree(GetProcessHeap(), 0, lpszUrlA);
1407 if (pEntry->dwSignature != URL_SIGNATURE)
1409 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1410 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1411 SetLastError(ERROR_FILE_NOT_FOUND);
1412 return FALSE;
1415 URLCache_SetEntryInfo(
1416 (URL_CACHEFILE_ENTRY *)pEntry,
1417 lpCacheEntryInfo,
1418 dwFieldControl);
1420 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1422 return TRUE;
1425 /***********************************************************************
1426 * RetrieveUrlCacheEntryFileA (WININET.@)
1429 BOOL WINAPI RetrieveUrlCacheEntryFileA(
1430 IN LPCSTR lpszUrlName,
1431 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1432 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1433 IN DWORD dwReserved
1436 LPURLCACHE_HEADER pHeader;
1437 CACHEFILE_ENTRY * pEntry;
1438 URL_CACHEFILE_ENTRY * pUrlEntry;
1439 URLCACHECONTAINER * pContainer;
1441 TRACE("(%s, %p, %p, 0x%08lx)\n",
1442 debugstr_a(lpszUrlName),
1443 lpCacheEntryInfo,
1444 lpdwCacheEntryInfoBufferSize,
1445 dwReserved);
1447 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1448 return FALSE;
1450 if (!URLCacheContainer_OpenIndex(pContainer))
1451 return FALSE;
1453 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1454 return FALSE;
1456 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1458 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1459 TRACE("entry %s not found!\n", lpszUrlName);
1460 SetLastError(ERROR_FILE_NOT_FOUND);
1461 return FALSE;
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", pUrlEntry->szSourceUrlName);
1474 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo);
1476 pUrlEntry->dwHitRate++;
1477 pUrlEntry->dwUseCount++;
1478 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1480 if (!URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize, pUrlEntry, FALSE))
1482 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1483 return FALSE;
1485 TRACE("Local File Name: %s\n", lpCacheEntryInfo->lpszLocalFileName);
1487 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1489 return TRUE;
1492 /***********************************************************************
1493 * RetrieveUrlCacheEntryFileW (WININET.@)
1496 BOOL WINAPI RetrieveUrlCacheEntryFileW(
1497 IN LPCWSTR lpszUrlName,
1498 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1499 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
1500 IN DWORD dwReserved
1503 TRACE("(%s, %p, %p, 0x%08lx)\n",
1504 debugstr_w(lpszUrlName),
1505 lpCacheEntryInfo,
1506 lpdwCacheEntryInfoBufferSize,
1507 dwReserved);
1509 return FALSE;
1512 /***********************************************************************
1513 * UnlockUrlCacheEntryFileA (WININET.@)
1516 BOOL WINAPI UnlockUrlCacheEntryFileA(
1517 IN LPCSTR lpszUrlName,
1518 IN DWORD dwReserved
1521 LPURLCACHE_HEADER pHeader;
1522 CACHEFILE_ENTRY * pEntry;
1523 URL_CACHEFILE_ENTRY * pUrlEntry;
1524 URLCACHECONTAINER * pContainer;
1526 TRACE("(%s, 0x%08lx)\n", debugstr_a(lpszUrlName), dwReserved);
1528 if (dwReserved)
1530 ERR("dwReserved != 0\n");
1531 SetLastError(ERROR_INVALID_PARAMETER);
1532 return FALSE;
1535 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
1536 return FALSE;
1538 if (!URLCacheContainer_OpenIndex(pContainer))
1539 return FALSE;
1541 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1542 return FALSE;
1544 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
1546 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1547 TRACE("entry %s not found!\n", lpszUrlName);
1548 SetLastError(ERROR_FILE_NOT_FOUND);
1549 return FALSE;
1552 if (pEntry->dwSignature != URL_SIGNATURE)
1554 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1555 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD)));
1556 SetLastError(ERROR_FILE_NOT_FOUND);
1557 return FALSE;
1560 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1562 if (pUrlEntry->dwUseCount == 0)
1564 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1565 return FALSE;
1567 pUrlEntry->dwUseCount--;
1568 URLCache_HashEntrySetUse(pHeader, lpszUrlName, pUrlEntry->dwUseCount);
1570 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1572 return TRUE;
1575 /***********************************************************************
1576 * UnlockUrlCacheEntryFileW (WININET.@)
1579 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved )
1581 FIXME("(%s, 0x%08lx)\n", debugstr_w(lpszUrlName), dwReserved);
1582 return TRUE;
1585 /***********************************************************************
1586 * CreateUrlCacheEntryA (WININET.@)
1589 BOOL WINAPI CreateUrlCacheEntryA(
1590 IN LPCSTR lpszUrlName,
1591 IN DWORD dwExpectedFileSize,
1592 IN LPCSTR lpszFileExtension,
1593 OUT LPSTR lpszFileName,
1594 IN DWORD dwReserved
1597 DWORD len;
1598 WCHAR *url_name;
1599 WCHAR *file_extension;
1600 WCHAR file_name[MAX_PATH];
1601 BOOL bSuccess = FALSE;
1602 DWORD dwError = 0;
1604 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
1605 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
1607 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
1608 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 &&
1609 (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
1611 MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len);
1612 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved))
1614 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH)
1616 bSuccess = TRUE;
1618 else
1620 dwError = GetLastError();
1623 else
1625 dwError = GetLastError();
1627 HeapFree(GetProcessHeap(), 0, file_extension);
1629 else
1631 dwError = GetLastError();
1633 HeapFree(GetProcessHeap(), 0, url_name);
1634 if (!bSuccess)
1635 SetLastError(dwError);
1637 return bSuccess;
1639 /***********************************************************************
1640 * CreateUrlCacheEntryW (WININET.@)
1643 BOOL WINAPI CreateUrlCacheEntryW(
1644 IN LPCWSTR lpszUrlName,
1645 IN DWORD dwExpectedFileSize,
1646 IN LPCWSTR lpszFileExtension,
1647 OUT LPWSTR lpszFileName,
1648 IN DWORD dwReserved
1651 URLCACHECONTAINER * pContainer;
1652 LPURLCACHE_HEADER pHeader;
1653 CHAR szFile[MAX_PATH];
1654 WCHAR szExtension[MAX_PATH];
1655 LPCWSTR lpszUrlPart;
1656 LPCWSTR lpszUrlEnd;
1657 LPCWSTR lpszFileNameExtension;
1658 LPWSTR lpszFileNameNoPath;
1659 int i;
1660 int countnoextension;
1661 BYTE CacheDir;
1662 LONG lBufferSize;
1663 BOOL bFound = FALSE;
1664 int count;
1665 static WCHAR szWWW[] = {'w','w','w',0};
1667 TRACE("(%s, 0x%08lx, %s, %p, 0x%08lx)\n",
1668 debugstr_w(lpszUrlName),
1669 dwExpectedFileSize,
1670 debugstr_w(lpszFileExtension),
1671 lpszFileName,
1672 dwReserved);
1674 if (dwReserved)
1676 ERR("dwReserved != 0\n");
1677 SetLastError(ERROR_INVALID_PARAMETER);
1678 return FALSE;
1681 for (lpszUrlEnd = lpszUrlName; *lpszUrlEnd; lpszUrlEnd++)
1684 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\'))
1685 lpszUrlEnd--;
1687 for (lpszUrlPart = lpszUrlEnd;
1688 (lpszUrlPart >= lpszUrlName);
1689 lpszUrlPart--)
1691 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1))
1693 bFound = TRUE;
1694 lpszUrlPart++;
1695 break;
1698 if (!lstrcmpW(lpszUrlPart, szWWW))
1700 lpszUrlPart += lstrlenW(szWWW);
1703 count = lpszUrlEnd - lpszUrlPart;
1705 if (bFound && (count < MAX_PATH))
1707 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL);
1708 if (!len)
1709 return FALSE;
1710 szFile[len] = '\0';
1711 /* FIXME: get rid of illegal characters like \, / and : */
1713 else
1715 FIXME("need to generate a random filename\n");
1718 TRACE("File name: %s\n", debugstr_a(szFile));
1720 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
1721 return FALSE;
1723 if (!URLCacheContainer_OpenIndex(pContainer))
1724 return FALSE;
1726 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1727 return FALSE;
1729 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount);
1731 lBufferSize = MAX_PATH * sizeof(CHAR);
1732 URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize);
1734 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1736 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(CHAR) - 2;
1737 lpszFileNameNoPath >= lpszFileName;
1738 --lpszFileNameNoPath)
1740 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\')
1741 break;
1744 countnoextension = lstrlenW(lpszFileNameNoPath);
1745 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath);
1746 if (lpszFileNameExtension)
1747 countnoextension -= lstrlenW(lpszFileNameExtension);
1748 *szExtension = '\0';
1750 if (lpszFileExtension)
1752 szExtension[0] = '.';
1753 lstrcpyW(szExtension+1, lpszFileExtension);
1756 for (i = 0; i < 255; i++)
1758 static WCHAR szFormat[] = {'[','%','u',']','%','s',0};
1759 HANDLE hFile;
1760 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension);
1761 TRACE("Trying: %s\n", debugstr_w(lpszFileName));
1762 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
1763 if (hFile != INVALID_HANDLE_VALUE)
1765 CloseHandle(hFile);
1766 return TRUE;
1770 return FALSE;
1774 /***********************************************************************
1775 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
1777 * The bug we are compensating for is that some drongo at Microsoft
1778 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
1779 * As a consequence, CommitUrlCacheEntryA has been effectively
1780 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
1781 * is still defined as LPCWSTR. The result (other than madness) is
1782 * that we always need to store lpHeaderInfo in CP_ACP rather than
1783 * in UTF16, and we need to avoid converting lpHeaderInfo in
1784 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
1785 * result will lose data for arbitrary binary data.
1788 static BOOL WINAPI CommitUrlCacheEntryInternal(
1789 IN LPCWSTR lpszUrlName,
1790 IN LPCWSTR lpszLocalFileName,
1791 IN FILETIME ExpireTime,
1792 IN FILETIME LastModifiedTime,
1793 IN DWORD CacheEntryType,
1794 IN LPBYTE lpHeaderInfo,
1795 IN DWORD dwHeaderSize,
1796 IN LPCWSTR lpszFileExtension,
1797 IN LPCWSTR lpszOriginalUrl
1800 URLCACHECONTAINER * pContainer;
1801 LPURLCACHE_HEADER pHeader;
1802 CACHEFILE_ENTRY * pEntry;
1803 URL_CACHEFILE_ENTRY * pUrlEntry;
1804 DWORD dwBytesNeeded = sizeof(*pUrlEntry) - sizeof(pUrlEntry->szSourceUrlName);
1805 DWORD dwOffsetLocalFileName = 0;
1806 DWORD dwOffsetHeader = 0;
1807 DWORD dwFileSizeLow = 0;
1808 DWORD dwFileSizeHigh = 0;
1809 BYTE cDirectory = 0;
1810 char achFile[MAX_PATH];
1811 char achUrl[MAX_PATH];
1812 char *pchLocalFileName = 0;
1814 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %s)\n",
1815 debugstr_w(lpszUrlName),
1816 debugstr_w(lpszLocalFileName),
1817 CacheEntryType,
1818 lpHeaderInfo,
1819 dwHeaderSize,
1820 debugstr_w(lpszFileExtension),
1821 debugstr_w(lpszOriginalUrl));
1823 if (lpszOriginalUrl)
1824 WARN(": lpszOriginalUrl ignored\n");
1826 if (lpszLocalFileName)
1828 HANDLE hFile;
1830 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
1831 if (hFile == INVALID_HANDLE_VALUE)
1833 ERR("couldn't open file %s (error is %ld)\n", debugstr_w(lpszLocalFileName), GetLastError());
1834 return FALSE;
1837 /* Get file size */
1838 dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
1839 if ((dwFileSizeLow == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
1841 ERR("couldn't get file size (error is %ld)\n", GetLastError());
1842 CloseHandle(hFile);
1843 return FALSE;
1846 CloseHandle(hFile);
1849 if (!URLCacheContainers_FindContainerW(lpszUrlName, &pContainer))
1850 return FALSE;
1852 if (!URLCacheContainer_OpenIndex(pContainer))
1853 return FALSE;
1855 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
1856 return FALSE;
1858 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, achUrl, -1, NULL, NULL);
1860 if (URLCache_FindEntryInHash(pHeader, achUrl, &pEntry))
1862 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1863 FIXME("entry already in cache - don't know what to do!\n");
1865 * SetLastError(ERROR_FILE_NOT_FOUND);
1866 * return FALSE;
1868 return TRUE;
1871 if (lpszLocalFileName)
1873 BOOL bFound = FALSE;
1875 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path)))
1877 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1878 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path));
1879 SetLastError(ERROR_INVALID_PARAMETER);
1880 return FALSE;
1883 /* skip container path prefix */
1884 lpszLocalFileName += lstrlenW(pContainer->path);
1886 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, -1, NULL, NULL);
1887 pchLocalFileName = achFile;
1889 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++)
1891 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH))
1893 bFound = TRUE;
1894 break;
1898 if (!bFound)
1900 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1901 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName));
1902 SetLastError(ERROR_INVALID_PARAMETER);
1903 return FALSE;
1906 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */
1909 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(achUrl) + 1);
1910 if (lpszLocalFileName)
1912 dwOffsetLocalFileName = dwBytesNeeded;
1913 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1);
1915 if (lpHeaderInfo)
1917 dwOffsetHeader = dwBytesNeeded;
1918 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize);
1921 /* round up to next block */
1922 if (dwBytesNeeded % BLOCKSIZE)
1924 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE;
1925 dwBytesNeeded += BLOCKSIZE;
1928 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry))
1930 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1931 ERR("no free entries\n");
1932 return FALSE;
1935 /* FindFirstFreeEntry fills in blocks used */
1936 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry;
1937 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE;
1938 pUrlEntry->CacheDir = cDirectory;
1939 pUrlEntry->CacheEntryType = CacheEntryType;
1940 pUrlEntry->dwHeaderInfoSize = dwHeaderSize;
1941 pUrlEntry->dwExemptDelta = 0;
1942 pUrlEntry->dwHitRate = 0;
1943 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader;
1944 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName;
1945 pUrlEntry->dwOffsetUrl = sizeof(*pUrlEntry) - sizeof(pUrlEntry->szSourceUrlName);
1946 pUrlEntry->dwSizeHigh = 0;
1947 pUrlEntry->dwSizeLow = dwFileSizeLow;
1948 pUrlEntry->dwSizeHigh = dwFileSizeHigh;
1949 pUrlEntry->dwUseCount = 0;
1950 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime);
1951 pUrlEntry->LastModifiedTime = LastModifiedTime;
1952 FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime);
1953 FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime);
1954 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate;
1955 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime;
1957 /*** Unknowns ***/
1958 pUrlEntry->dwUnknown1 = 0;
1959 pUrlEntry->dwUnknown2 = 0;
1960 pUrlEntry->dwUnknown3 = 0x60;
1961 pUrlEntry->Unknown4 = 0;
1962 pUrlEntry->wUnknown5 = 0x1010;
1963 pUrlEntry->dwUnknown6 = 0;
1964 pUrlEntry->dwUnknown7 = 0;
1965 pUrlEntry->dwUnknown8 = 0;
1968 strcpy(pUrlEntry->szSourceUrlName, achUrl);
1969 if (dwOffsetLocalFileName)
1970 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName);
1971 if (dwOffsetHeader)
1972 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize);
1974 if (!URLCache_AddEntryToHash(pHeader, achUrl, (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader)))
1976 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1977 return FALSE;
1980 URLCacheContainer_UnlockIndex(pContainer, pHeader);
1982 return TRUE;
1985 /***********************************************************************
1986 * CommitUrlCacheEntryA (WININET.@)
1989 BOOL WINAPI CommitUrlCacheEntryA(
1990 IN LPCSTR lpszUrlName,
1991 IN LPCSTR lpszLocalFileName,
1992 IN FILETIME ExpireTime,
1993 IN FILETIME LastModifiedTime,
1994 IN DWORD CacheEntryType,
1995 IN LPBYTE lpHeaderInfo,
1996 IN DWORD dwHeaderSize,
1997 IN LPCSTR lpszFileExtension,
1998 IN LPCSTR lpszOriginalUrl
2001 DWORD len;
2002 WCHAR *url_name;
2003 WCHAR *local_file_name;
2004 WCHAR *original_url = NULL;
2005 BOOL bSuccess = FALSE;
2006 DWORD dwError = 0;
2008 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %s)\n",
2009 debugstr_a(lpszUrlName),
2010 debugstr_a(lpszLocalFileName),
2011 CacheEntryType,
2012 lpHeaderInfo,
2013 dwHeaderSize,
2014 debugstr_a(lpszFileExtension),
2015 debugstr_a(lpszOriginalUrl));
2017 if (lpszFileExtension != 0)
2019 SetLastError(ERROR_INVALID_PARAMETER);
2020 return FALSE;
2022 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 &&
2023 (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2025 MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len);
2026 if ((len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0)) != 0 &&
2027 (local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0)
2029 MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len);
2030 if (!lpszOriginalUrl ||
2031 ((len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0)) != 0 &&
2032 (original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0))
2034 if (original_url)
2035 MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len);
2036 if (CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime,
2037 CacheEntryType, lpHeaderInfo, dwHeaderSize,
2038 NULL, original_url))
2040 bSuccess = TRUE;
2042 else
2044 dwError = GetLastError();
2046 if (original_url)
2047 HeapFree(GetProcessHeap(), 0, original_url);
2049 else
2051 dwError = GetLastError();
2053 HeapFree(GetProcessHeap(), 0, local_file_name);
2055 else
2057 dwError = GetLastError();
2059 HeapFree(GetProcessHeap(), 0, url_name);
2060 if (!bSuccess)
2061 SetLastError(dwError);
2063 return bSuccess;
2066 /***********************************************************************
2067 * CommitUrlCacheEntryW (WININET.@)
2070 BOOL WINAPI CommitUrlCacheEntryW(
2071 IN LPCWSTR lpszUrlName,
2072 IN LPCWSTR lpszLocalFileName,
2073 IN FILETIME ExpireTime,
2074 IN FILETIME LastModifiedTime,
2075 IN DWORD CacheEntryType,
2076 IN LPWSTR lpHeaderInfo,
2077 IN DWORD dwHeaderSize,
2078 IN LPCWSTR lpszFileExtension,
2079 IN LPCWSTR lpszOriginalUrl
2082 DWORD dwError = 0;
2083 BOOL bSuccess = FALSE;
2084 DWORD len = 0;
2085 CHAR *header_info = NULL;
2087 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %s)\n",
2088 debugstr_w(lpszUrlName),
2089 debugstr_w(lpszLocalFileName),
2090 CacheEntryType,
2091 lpHeaderInfo,
2092 dwHeaderSize,
2093 debugstr_w(lpszFileExtension),
2094 debugstr_w(lpszOriginalUrl));
2096 if (!lpHeaderInfo ||
2097 ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 &&
2098 (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0))
2100 if (header_info)
2101 WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL);
2102 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime,
2103 CacheEntryType, header_info, len, lpszFileExtension, lpszOriginalUrl))
2105 bSuccess = TRUE;
2107 else
2109 dwError = GetLastError();
2111 if (header_info)
2113 HeapFree(GetProcessHeap(), 0, header_info);
2114 if (!bSuccess)
2115 SetLastError(dwError);
2118 return bSuccess;
2121 /***********************************************************************
2122 * ReadUrlCacheEntryStream (WININET.@)
2125 BOOL WINAPI ReadUrlCacheEntryStream(
2126 IN HANDLE hUrlCacheStream,
2127 IN DWORD dwLocation,
2128 IN OUT LPVOID lpBuffer,
2129 IN OUT LPDWORD lpdwLen,
2130 IN DWORD dwReserved
2133 /* Get handle to file from 'stream' */
2134 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2136 if (dwReserved != 0)
2138 ERR("dwReserved != 0\n");
2139 SetLastError(ERROR_INVALID_PARAMETER);
2140 return FALSE;
2143 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2145 SetLastError(ERROR_INVALID_HANDLE);
2146 return FALSE;
2149 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
2150 return FALSE;
2151 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL);
2154 /***********************************************************************
2155 * RetrieveUrlCacheEntryStreamA (WININET.@)
2158 HANDLE WINAPI RetrieveUrlCacheEntryStreamA(
2159 IN LPCSTR lpszUrlName,
2160 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2161 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2162 IN BOOL fRandomRead,
2163 IN DWORD dwReserved
2166 /* NOTE: this is not the same as the way that the native
2167 * version allocates 'stream' handles. I did it this way
2168 * as it is much easier and no applications should depend
2169 * on this behaviour. (Native version appears to allocate
2170 * indices into a table)
2172 STREAM_HANDLE * pStream;
2173 HANDLE hFile;
2175 TRACE( "(%s, %p, %p, %x, 0x%08lx)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
2176 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2178 if (!RetrieveUrlCacheEntryFileA(lpszUrlName,
2179 lpCacheEntryInfo,
2180 lpdwCacheEntryInfoBufferSize,
2181 dwReserved))
2183 return NULL;
2186 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName,
2187 GENERIC_READ,
2188 FILE_SHARE_READ,
2189 NULL,
2190 OPEN_EXISTING,
2191 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0,
2192 NULL);
2193 if (hFile == INVALID_HANDLE_VALUE)
2194 return FALSE;
2196 /* allocate handle storage space */
2197 pStream = HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR));
2198 if (!pStream)
2200 CloseHandle(hFile);
2201 SetLastError(ERROR_OUTOFMEMORY);
2202 return FALSE;
2205 pStream->hFile = hFile;
2206 strcpy(pStream->lpszUrl, lpszUrlName);
2207 return (HANDLE)pStream;
2210 /***********************************************************************
2211 * RetrieveUrlCacheEntryStreamW (WININET.@)
2214 HANDLE WINAPI RetrieveUrlCacheEntryStreamW(
2215 IN LPCWSTR lpszUrlName,
2216 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2217 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize,
2218 IN BOOL fRandomRead,
2219 IN DWORD dwReserved
2222 FIXME( "(%s, %p, %p, %x, 0x%08lx)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
2223 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved );
2224 return NULL;
2227 /***********************************************************************
2228 * UnlockUrlCacheEntryStream (WININET.@)
2231 BOOL WINAPI UnlockUrlCacheEntryStream(
2232 IN HANDLE hUrlCacheStream,
2233 IN DWORD dwReserved
2236 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream;
2238 if (dwReserved != 0)
2240 ERR("dwReserved != 0\n");
2241 SetLastError(ERROR_INVALID_PARAMETER);
2242 return FALSE;
2245 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH))
2247 SetLastError(ERROR_INVALID_HANDLE);
2248 return FALSE;
2251 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0))
2252 return FALSE;
2254 /* close file handle */
2255 CloseHandle(pStream->hFile);
2257 /* free allocated space */
2258 HeapFree(GetProcessHeap(), 0, pStream);
2260 return TRUE;
2264 /***********************************************************************
2265 * DeleteUrlCacheEntryA (WININET.@)
2268 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
2270 URLCACHECONTAINER * pContainer;
2271 LPURLCACHE_HEADER pHeader;
2272 CACHEFILE_ENTRY * pEntry;
2273 DWORD dwStartBlock;
2274 DWORD dwBlock;
2275 BYTE * AllocationTable;
2277 TRACE("(%s)\n", debugstr_a(lpszUrlName));
2279 if (!URLCacheContainers_FindContainerA(lpszUrlName, &pContainer))
2280 return FALSE;
2282 if (!URLCacheContainer_OpenIndex(pContainer))
2283 return FALSE;
2285 if (!(pHeader = URLCacheContainer_LockIndex(pContainer)))
2286 return FALSE;
2288 if (!URLCache_FindEntryInHash(pHeader, lpszUrlName, &pEntry))
2290 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2291 TRACE("entry %s not found!\n", lpszUrlName);
2292 SetLastError(ERROR_FILE_NOT_FOUND);
2293 return FALSE;
2296 AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET;
2298 /* update allocation table */
2299 dwStartBlock = ((DWORD)pEntry - (DWORD)pHeader) / BLOCKSIZE;
2300 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++)
2301 URLCache_Allocation_BlockFree(AllocationTable, dwBlock);
2303 URLCache_DeleteEntry(pEntry);
2305 URLCache_DeleteEntryFromHash(pHeader, lpszUrlName);
2307 URLCacheContainer_UnlockIndex(pContainer, pHeader);
2309 return TRUE;
2312 /***********************************************************************
2313 * DeleteUrlCacheEntryW (WININET.@)
2316 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
2318 FIXME("(%s) stub\n", debugstr_w(lpszUrlName));
2319 return TRUE;
2322 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
2324 FIXME("(0x%08lx, 0x%08lx) stub\n", d1, d2);
2325 return TRUE;
2328 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
2330 FIXME("(0x%08lx, 0x%08lx) stub\n", d1, d2);
2331 return TRUE;
2334 /***********************************************************************
2335 * CreateCacheContainerA (WININET.@)
2337 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2338 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2340 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) stub\n",
2341 d1, d2, d3, d4, d5, d6, d7, d8);
2342 return TRUE;
2345 /***********************************************************************
2346 * CreateCacheContainerW (WININET.@)
2348 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
2349 DWORD d5, DWORD d6, DWORD d7, DWORD d8)
2351 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx) stub\n",
2352 d1, d2, d3, d4, d5, d6, d7, d8);
2353 return TRUE;
2356 /***********************************************************************
2357 * FindCloseUrlCache (WININET.@)
2359 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
2361 FIXME("(%p) stub\n", hEnumHandle);
2362 return TRUE;
2365 /***********************************************************************
2366 * FindFirstUrlCacheContainerA (WININET.@)
2368 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2370 FIXME("(%p, %p, %p, 0x%08lx) stub\n", p1, p2, p3, d1 );
2371 return NULL;
2374 /***********************************************************************
2375 * FindFirstUrlCacheContainerW (WININET.@)
2377 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
2379 FIXME("(%p, %p, %p, 0x%08lx) stub\n", p1, p2, p3, d1 );
2380 return NULL;
2383 /***********************************************************************
2384 * FindNextUrlCacheContainerA (WININET.@)
2386 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
2388 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2389 return FALSE;
2392 /***********************************************************************
2393 * FindNextUrlCacheContainerW (WININET.@)
2395 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
2397 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
2398 return FALSE;
2401 HANDLE WINAPI FindFirstUrlCacheEntryExA(
2402 LPCSTR lpszUrlSearchPattern,
2403 DWORD dwFlags,
2404 DWORD dwFilter,
2405 GROUPID GroupId,
2406 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2407 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2408 LPVOID lpReserved,
2409 LPDWORD pcbReserved2,
2410 LPVOID lpReserved3
2413 FIXME("(%s, 0x%08lx, 0x%08lx, 0x%08lx%08lx, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
2414 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2415 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2416 SetLastError(ERROR_FILE_NOT_FOUND);
2417 return NULL;
2420 HANDLE WINAPI FindFirstUrlCacheEntryExW(
2421 LPCWSTR lpszUrlSearchPattern,
2422 DWORD dwFlags,
2423 DWORD dwFilter,
2424 GROUPID GroupId,
2425 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2426 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2427 LPVOID lpReserved,
2428 LPDWORD pcbReserved2,
2429 LPVOID lpReserved3
2432 FIXME("(%s, 0x%08lx, 0x%08lx, 0x%08lx%08lx, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
2433 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo,
2434 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
2435 SetLastError(ERROR_FILE_NOT_FOUND);
2436 return NULL;
2439 /***********************************************************************
2440 * FindFirstUrlCacheEntryA (WININET.@)
2443 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
2444 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2446 FIXME("(%s, %p, %p): stub\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2447 SetLastError(ERROR_FILE_NOT_FOUND);
2448 return 0;
2451 /***********************************************************************
2452 * FindFirstUrlCacheEntryW (WININET.@)
2455 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
2456 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
2458 FIXME("(%s, %p, %p): stub\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
2459 return 0;
2462 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
2463 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
2465 FIXME("(0x%08lx, 0x%08lx, %p, 0x%08lx, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
2466 dwSearchCondition, lpGroupId, lpReserved);
2467 return NULL;
2470 BOOL WINAPI FindNextUrlCacheEntryA(
2471 HANDLE hEnumHandle,
2472 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
2473 LPDWORD lpdwNextCacheEntryInfoBufferSize
2476 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2477 return FALSE;
2480 BOOL WINAPI FindNextUrlCacheEntryW(
2481 HANDLE hEnumHandle,
2482 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
2483 LPDWORD lpdwNextCacheEntryInfoBufferSize
2486 FIXME("(%p, %p, %p) stub\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
2487 return FALSE;
2490 BOOL WINAPI FindNextUrlCacheEntryExA(
2491 HANDLE hEnumHandle,
2492 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
2493 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2494 LPVOID lpReserved,
2495 LPDWORD pcbReserved2,
2496 LPVOID lpReserved3
2499 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2500 lpReserved, pcbReserved2, lpReserved3);
2501 return FALSE;
2504 BOOL WINAPI FindNextUrlCacheEntryExW(
2505 HANDLE hEnumHandle,
2506 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
2507 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
2508 LPVOID lpReserved,
2509 LPDWORD pcbReserved2,
2510 LPVOID lpReserved3
2513 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
2514 lpReserved, pcbReserved2, lpReserved3);
2515 return FALSE;
2518 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
2520 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
2521 return FALSE;
2524 /***********************************************************************
2525 * CreateUrlCacheGroup (WININET.@)
2528 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
2530 FIXME("(0x%08lx, %p): stub\n", dwFlags, lpReserved);
2531 return FALSE;
2534 /***********************************************************************
2535 * DeleteUrlCacheGroup (WININET.@)
2538 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
2540 FIXME("(0x%08lx%08lx, 0x%08lx, %p) stub\n",
2541 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved);
2542 return FALSE;
2545 /***********************************************************************
2546 * SetUrlCacheEntryGroupA (WININET.@)
2549 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
2550 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2551 LPVOID lpReserved)
2553 FIXME("(%s, 0x%08lx, 0x%08lx%08lx, %p, 0x%08lx, %p) stub\n",
2554 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2555 pbGroupAttributes, cbGroupAttributes, lpReserved);
2556 SetLastError(ERROR_FILE_NOT_FOUND);
2557 return FALSE;
2560 /***********************************************************************
2561 * SetUrlCacheEntryGroupW (WININET.@)
2564 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
2565 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
2566 LPVOID lpReserved)
2568 FIXME("(%s, 0x%08lx, 0x%08lx%08lx, %p, 0x%08lx, %p) stub\n",
2569 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId,
2570 pbGroupAttributes, cbGroupAttributes, lpReserved);
2571 SetLastError(ERROR_FILE_NOT_FOUND);
2572 return FALSE;
2575 /***********************************************************************
2576 * GetUrlCacheConfigInfoW (WININET.@)
2578 BOOL WINAPI GetUrlCacheConfigInfoW(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2580 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2581 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2582 return FALSE;
2585 /***********************************************************************
2586 * GetUrlCacheConfigInfoA (WININET.@)
2588 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
2590 BOOL WINAPI GetUrlCacheConfigInfoA(LPDWORD CacheInfo, LPDWORD size, DWORD bitmask)
2592 FIXME("(%p, %p, %lx)\n", CacheInfo, size, bitmask);
2593 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2594 return FALSE;
2597 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2598 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
2599 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2601 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p, %p) stub\n",
2602 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2603 lpdwGroupInfo, lpReserved);
2604 return FALSE;
2607 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2608 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
2609 LPDWORD lpdwGroupInfo, LPVOID lpReserved )
2611 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p, %p) stub\n",
2612 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo,
2613 lpdwGroupInfo, lpReserved);
2614 return FALSE;
2617 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2618 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
2620 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p) stub\n",
2621 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2622 return TRUE;
2625 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
2626 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
2628 FIXME("(0x%08lx%08lx, 0x%08lx, 0x%08lx, %p, %p) stub\n",
2629 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved);
2630 return TRUE;
2633 BOOL WINAPI SetUrlCacheConfigInfoA( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2635 FIXME("(%p, 0x%08lx) stub\n", lpCacheConfigInfo, dwFieldControl);
2636 return TRUE;
2639 BOOL WINAPI SetUrlCacheConfigInfoW( LPDWORD lpCacheConfigInfo, DWORD dwFieldControl )
2641 FIXME("(%p, 0x%08lx) stub\n", lpCacheConfigInfo, dwFieldControl);
2642 return TRUE;
2645 /***********************************************************************
2646 * DeleteIE3Cache (WININET.@)
2648 * Deletes the files used by the IE3 URL caching system.
2650 * PARAMS
2651 * hWnd [I] A dummy window.
2652 * hInst [I] Instance of process calling the function.
2653 * lpszCmdLine [I] Options used by function.
2654 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
2656 * RETURNS
2657 * nothing
2659 void WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
2661 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);