2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003-2008 Robert Shearman
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
31 #if defined(__MINGW32__) || defined (_MSC_VER)
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
56 #include "wine/unicode.h"
57 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
61 #define ENTRY_START_OFFSET 0x4000
64 #define HASHTABLE_SIZE 448
65 #define HASHTABLE_BLOCKSIZE 7
66 #define HASHTABLE_FREE 3
67 #define ALLOCATION_TABLE_OFFSET 0x250
68 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
69 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
70 #define NEWFILE_NUM_BLOCKS 0xd80
71 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
73 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
74 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
75 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
76 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
77 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
79 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
81 typedef struct _CACHEFILE_ENTRY
85 DWORD dwSignature
; /* e.g. "URL " */
86 /* CHAR szSignature[4];
88 DWORD dwBlocksUsed
; /* number of 128byte blocks used by this entry */
91 typedef struct _URL_CACHEFILE_ENTRY
93 CACHEFILE_ENTRY CacheFileEntry
;
94 FILETIME LastModifiedTime
;
95 FILETIME LastAccessTime
;
96 WORD wExpiredDate
; /* expire date in dos format */
97 WORD wExpiredTime
; /* expire time in dos format */
98 DWORD dwUnknown1
; /* usually zero */
99 DWORD dwSizeLow
; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
100 DWORD dwSizeHigh
; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
101 DWORD dwUnknown2
; /* usually zero */
102 DWORD dwExemptDelta
; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
103 DWORD dwUnknown3
; /* usually 0x60 */
104 DWORD dwOffsetUrl
; /* offset of start of url from start of entry */
105 BYTE CacheDir
; /* index of cache directory this url is stored in */
106 BYTE Unknown4
; /* usually zero */
107 WORD wUnknown5
; /* usually 0x1010 */
108 DWORD dwOffsetLocalName
; /* offset of start of local filename from start of entry */
109 DWORD CacheEntryType
; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
110 DWORD dwOffsetHeaderInfo
; /* offset of start of header info from start of entry */
111 DWORD dwHeaderInfoSize
;
112 DWORD dwOffsetFileExtension
; /* offset of start of file extension from start of entry */
113 WORD wLastSyncDate
; /* last sync date in dos format */
114 WORD wLastSyncTime
; /* last sync time in dos format */
115 DWORD dwHitRate
; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
116 DWORD dwUseCount
; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
117 WORD wUnknownDate
; /* usually same as wLastSyncDate */
118 WORD wUnknownTime
; /* usually same as wLastSyncTime */
119 DWORD dwUnknown7
; /* usually zero */
120 DWORD dwUnknown8
; /* usually zero */
121 /* packing to dword align start of next field */
122 /* CHAR szSourceUrlName[]; (url) */
123 /* packing to dword align start of next field */
124 /* CHAR szLocalFileName[]; (local file name excluding path) */
125 /* packing to dword align start of next field */
126 /* CHAR szHeaderInfo[]; (header info) */
127 } URL_CACHEFILE_ENTRY
;
135 typedef struct _HASH_CACHEFILE_ENTRY
137 CACHEFILE_ENTRY CacheFileEntry
;
139 DWORD dwHashTableNumber
;
140 struct _HASH_ENTRY HashTable
[HASHTABLE_SIZE
];
141 } HASH_CACHEFILE_ENTRY
;
143 typedef struct _DIRECTORY_DATA
146 char filename
[DIR_LENGTH
];
149 typedef struct _URLCACHE_HEADER
151 char szSignature
[28];
153 DWORD dwOffsetFirstHashTable
;
154 DWORD dwIndexCapacityInBlocks
;
157 DWORD dwCacheLimitLow
; /* disk space limit for cache */
158 DWORD dwCacheLimitHigh
; /* disk space limit for cache */
159 DWORD dwUnknown4
; /* current disk space usage for cache */
160 DWORD dwUnknown5
; /* current disk space usage for cache */
161 DWORD dwUnknown6
; /* possibly a flag? */
163 BYTE DirectoryCount
; /* number of directory_data's */
164 BYTE Unknown8
[3]; /* just padding? */
165 DIRECTORY_DATA directory_data
[1]; /* first directory entry */
166 } URLCACHE_HEADER
, *LPURLCACHE_HEADER
;
167 typedef const URLCACHE_HEADER
*LPCURLCACHE_HEADER
;
169 typedef struct _STREAM_HANDLE
175 typedef struct _URLCACHECONTAINER
177 struct list entry
; /* part of a list */
178 LPWSTR cache_prefix
; /* string that has to be prefixed for this container to be used */
179 LPWSTR path
; /* path to url container directory */
180 HANDLE hMapping
; /* handle of file mapping */
181 DWORD file_size
; /* size of file when mapping was opened */
182 HANDLE hMutex
; /* handle of mutex */
186 /* List of all containers available */
187 static struct list UrlContainers
= LIST_INIT(UrlContainers
);
189 static DWORD
URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader
, HASH_CACHEFILE_ENTRY
*pPrevHash
, HASH_CACHEFILE_ENTRY
**ppHash
);
191 /***********************************************************************
192 * URLCache_PathToObjectName (Internal)
194 * Converts a path to a name suitable for use as a Win32 object name.
195 * Replaces '\\' characters in-place with the specified character
196 * (usually '_' or '!')
202 static void URLCache_PathToObjectName(LPWSTR lpszPath
, WCHAR replace
)
204 for (; *lpszPath
; lpszPath
++)
206 if (*lpszPath
== '\\')
211 /***********************************************************************
212 * URLCacheContainer_OpenIndex (Internal)
214 * Opens the index file and saves mapping handle in hCacheIndexMapping
217 * ERROR_SUCCESS if succeeded
218 * Any other Win32 error code if failed
221 static DWORD
URLCacheContainer_OpenIndex(URLCACHECONTAINER
* pContainer
)
224 WCHAR wszFilePath
[MAX_PATH
];
227 static const WCHAR wszIndex
[] = {'i','n','d','e','x','.','d','a','t',0};
228 static const WCHAR wszMappingFormat
[] = {'%','s','%','s','_','%','l','u',0};
230 if (pContainer
->hMapping
)
231 return ERROR_SUCCESS
;
233 strcpyW(wszFilePath
, pContainer
->path
);
234 strcatW(wszFilePath
, wszIndex
);
236 hFile
= CreateFileW(wszFilePath
, GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, 0, NULL
);
237 if (hFile
== INVALID_HANDLE_VALUE
)
239 /* Maybe the directory wasn't there? Try to create it */
240 if (CreateDirectoryW(pContainer
->path
, 0))
241 hFile
= CreateFileW(wszFilePath
, GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, 0, NULL
);
243 if (hFile
== INVALID_HANDLE_VALUE
)
245 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath
));
246 return GetLastError();
249 /* At this stage we need the mutex because we may be about to create the
252 WaitForSingleObject(pContainer
->hMutex
, INFINITE
);
254 dwFileSize
= GetFileSize(hFile
, NULL
);
255 if (dwFileSize
== INVALID_FILE_SIZE
)
257 ReleaseMutex(pContainer
->hMutex
);
258 return GetLastError();
263 static const CHAR szCacheContent
[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content";
265 char achZeroes
[0x1000];
267 DWORD dwError
= ERROR_SUCCESS
;
269 /* Write zeroes to the entire file so we can safely map it without
270 * fear of getting a SEGV because the disk is full.
272 memset(achZeroes
, 0, sizeof(achZeroes
));
273 for (dwOffset
= 0; dwOffset
< NEWFILE_SIZE
; dwOffset
+= sizeof(achZeroes
))
275 DWORD dwWrite
= sizeof(achZeroes
);
278 if (NEWFILE_SIZE
- dwOffset
< dwWrite
)
279 dwWrite
= NEWFILE_SIZE
- dwOffset
;
280 if (!WriteFile(hFile
, achZeroes
, dwWrite
, &dwWritten
, 0) ||
281 dwWritten
!= dwWrite
)
283 /* If we fail to write, we need to return the error that
284 * cause the problem and also make sure the file is no
285 * longer there, if possible.
287 dwError
= GetLastError();
293 if (dwError
== ERROR_SUCCESS
)
295 HANDLE hMapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READWRITE
, 0, NEWFILE_SIZE
, NULL
);
299 URLCACHE_HEADER
*pHeader
= MapViewOfFile(hMapping
, FILE_MAP_WRITE
, 0, 0, NEWFILE_SIZE
);
304 WCHAR wszDirPath
[MAX_PATH
];
307 HASH_CACHEFILE_ENTRY
*pHashEntry
;
309 dwFileSize
= NEWFILE_SIZE
;
311 /* First set some constants and defaults in the header */
312 strcpy(pHeader
->szSignature
, "WINE URLCache Ver 0.2005001");
313 pHeader
->dwFileSize
= dwFileSize
;
314 pHeader
->dwIndexCapacityInBlocks
= NEWFILE_NUM_BLOCKS
;
315 /* 127MB - taken from default for Windows 2000 */
316 pHeader
->dwCacheLimitHigh
= 0;
317 pHeader
->dwCacheLimitLow
= 0x07ff5400;
318 /* Copied from a Windows 2000 cache index */
319 pHeader
->DirectoryCount
= 4;
321 /* If the registry has a cache size set, use the registry value */
322 if (RegOpenKeyA(HKEY_CURRENT_USER
, szCacheContent
, &key
) == ERROR_SUCCESS
)
325 DWORD len
= sizeof(dw
);
328 if (RegQueryValueExA(key
, "CacheLimit", NULL
, &keytype
,
329 (BYTE
*) &dw
, &len
) == ERROR_SUCCESS
&&
330 keytype
== REG_DWORD
)
332 pHeader
->dwCacheLimitHigh
= (dw
>> 22);
333 pHeader
->dwCacheLimitLow
= dw
<< 10;
338 URLCache_CreateHashTable(pHeader
, NULL
, &pHashEntry
);
340 /* Last step - create the directories */
342 strcpyW(wszDirPath
, pContainer
->path
);
343 pwchDir
= wszDirPath
+ strlenW(wszDirPath
);
346 GetSystemTimeAsFileTime(&ft
);
348 for (i
= 0; !dwError
&& i
< pHeader
->DirectoryCount
; ++i
)
350 /* The following values were copied from a Windows index.
351 * I don't know what the values are supposed to mean but
352 * have made them the same in the hope that this will
353 * be better for compatibility
355 pHeader
->directory_data
[i
].dwUnknown
= (i
> 1) ? 0xfe : 0xff;
359 ULONGLONG n
= ft
.dwHighDateTime
;
361 /* Generate a file name to attempt to create.
362 * This algorithm will create what will appear
363 * to be random and unrelated directory names
364 * of up to 9 characters in length.
367 n
+= ft
.dwLowDateTime
;
368 n
^= ((ULONGLONG
) i
<< 56) | ((ULONGLONG
) j
<< 48);
370 for (k
= 0; k
< 8; ++k
)
374 /* Dividing by a prime greater than 36 helps
375 * with the appearance of randomness
380 pwchDir
[k
] = '0' + r
;
382 pwchDir
[k
] = 'A' + (r
- 10);
385 if (CreateDirectoryW(wszDirPath
, 0))
387 /* The following is OK because we generated an
388 * 8 character directory name made from characters
389 * [A-Z0-9], which are equivalent for all code
390 * pages and for UTF-16
392 for (k
= 0; k
< 8; ++k
)
393 pHeader
->directory_data
[i
].filename
[k
] = pwchDir
[k
];
398 /* Give up. The most likely cause of this
399 * is a full disk, but whatever the cause
400 * is, it should be more than apparent that
403 dwError
= GetLastError();
409 UnmapViewOfFile(pHeader
);
413 dwError
= GetLastError();
415 CloseHandle(hMapping
);
419 dwError
= GetLastError();
426 DeleteFileW(wszFilePath
);
427 ReleaseMutex(pContainer
->hMutex
);
433 ReleaseMutex(pContainer
->hMutex
);
435 wsprintfW(wszFilePath
, wszMappingFormat
, pContainer
->path
, wszIndex
, dwFileSize
);
436 URLCache_PathToObjectName(wszFilePath
, '_');
437 pContainer
->hMapping
= OpenFileMappingW(FILE_MAP_WRITE
, FALSE
, wszFilePath
);
438 if (!pContainer
->hMapping
)
439 pContainer
->hMapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READWRITE
, 0, 0, wszFilePath
);
441 if (!pContainer
->hMapping
)
443 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
444 return GetLastError();
447 return ERROR_SUCCESS
;
450 /***********************************************************************
451 * URLCacheContainer_CloseIndex (Internal)
459 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER
* pContainer
)
461 CloseHandle(pContainer
->hMapping
);
462 pContainer
->hMapping
= NULL
;
465 static BOOL
URLCacheContainers_AddContainer(LPCWSTR cache_prefix
, LPCWSTR path
, LPWSTR mutex_name
)
467 URLCACHECONTAINER
* pContainer
= HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER
));
468 int path_len
= strlenW(path
);
469 int cache_prefix_len
= strlenW(cache_prefix
);
476 pContainer
->hMapping
= NULL
;
477 pContainer
->file_size
= 0;
479 pContainer
->path
= HeapAlloc(GetProcessHeap(), 0, (path_len
+ 1) * sizeof(WCHAR
));
480 if (!pContainer
->path
)
482 HeapFree(GetProcessHeap(), 0, pContainer
);
486 memcpy(pContainer
->path
, path
, (path_len
+ 1) * sizeof(WCHAR
));
488 pContainer
->cache_prefix
= HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len
+ 1) * sizeof(WCHAR
));
489 if (!pContainer
->cache_prefix
)
491 HeapFree(GetProcessHeap(), 0, pContainer
->path
);
492 HeapFree(GetProcessHeap(), 0, pContainer
);
496 memcpy(pContainer
->cache_prefix
, cache_prefix
, (cache_prefix_len
+ 1) * sizeof(WCHAR
));
498 CharLowerW(mutex_name
);
499 URLCache_PathToObjectName(mutex_name
, '!');
501 if ((pContainer
->hMutex
= CreateMutexW(NULL
, FALSE
, mutex_name
)) == NULL
)
503 ERR("couldn't create mutex (error is %d)\n", GetLastError());
504 HeapFree(GetProcessHeap(), 0, pContainer
->path
);
505 HeapFree(GetProcessHeap(), 0, pContainer
);
509 list_add_head(&UrlContainers
, &pContainer
->entry
);
514 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER
* pContainer
)
516 list_remove(&pContainer
->entry
);
518 URLCacheContainer_CloseIndex(pContainer
);
519 CloseHandle(pContainer
->hMutex
);
520 HeapFree(GetProcessHeap(), 0, pContainer
->path
);
521 HeapFree(GetProcessHeap(), 0, pContainer
->cache_prefix
);
522 HeapFree(GetProcessHeap(), 0, pContainer
);
525 void URLCacheContainers_CreateDefaults(void)
527 static const WCHAR UrlSuffix
[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
528 static const WCHAR UrlPrefix
[] = {0};
529 static const WCHAR HistorySuffix
[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
530 static const WCHAR HistoryPrefix
[] = {'V','i','s','i','t','e','d',':',0};
531 static const WCHAR CookieSuffix
[] = {0};
532 static const WCHAR CookiePrefix
[] = {'C','o','o','k','i','e',':',0};
535 int nFolder
; /* CSIDL_* constant */
536 const WCHAR
* shpath_suffix
; /* suffix on path returned by SHGetSpecialFolderPath */
537 const WCHAR
* cache_prefix
; /* prefix used to reference the container */
538 } DefaultContainerData
[] =
540 { CSIDL_INTERNET_CACHE
, UrlSuffix
, UrlPrefix
},
541 { CSIDL_HISTORY
, HistorySuffix
, HistoryPrefix
},
542 { CSIDL_COOKIES
, CookieSuffix
, CookiePrefix
},
546 for (i
= 0; i
< sizeof(DefaultContainerData
) / sizeof(DefaultContainerData
[0]); i
++)
548 WCHAR wszCachePath
[MAX_PATH
];
549 WCHAR wszMutexName
[MAX_PATH
];
550 int path_len
, suffix_len
;
552 if (!SHGetSpecialFolderPathW(NULL
, wszCachePath
, DefaultContainerData
[i
].nFolder
, TRUE
))
554 ERR("Couldn't get path for default container %u\n", i
);
557 path_len
= strlenW(wszCachePath
);
558 suffix_len
= strlenW(DefaultContainerData
[i
].shpath_suffix
);
560 if (path_len
+ suffix_len
+ 2 > MAX_PATH
)
562 ERR("Path too long\n");
566 wszCachePath
[path_len
] = '\\';
567 wszCachePath
[path_len
+1] = 0;
569 strcpyW(wszMutexName
, wszCachePath
);
573 memcpy(wszCachePath
+ path_len
+ 1, DefaultContainerData
[i
].shpath_suffix
, (suffix_len
+ 1) * sizeof(WCHAR
));
574 wszCachePath
[path_len
+ suffix_len
+ 1] = '\\';
575 wszCachePath
[path_len
+ suffix_len
+ 2] = '\0';
578 URLCacheContainers_AddContainer(DefaultContainerData
[i
].cache_prefix
, wszCachePath
, wszMutexName
);
582 void URLCacheContainers_DeleteAll(void)
584 while(!list_empty(&UrlContainers
))
585 URLCacheContainer_DeleteContainer(
586 LIST_ENTRY(list_head(&UrlContainers
), URLCACHECONTAINER
, entry
)
590 static DWORD
URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl
, URLCACHECONTAINER
** ppContainer
)
592 URLCACHECONTAINER
* pContainer
;
594 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl
));
596 LIST_FOR_EACH_ENTRY(pContainer
, &UrlContainers
, URLCACHECONTAINER
, entry
)
598 int prefix_len
= strlenW(pContainer
->cache_prefix
);
599 if (!strncmpW(pContainer
->cache_prefix
, lpwszUrl
, prefix_len
))
601 TRACE("found container with prefix %s for URL %s\n", debugstr_w(pContainer
->cache_prefix
), debugstr_w(lpwszUrl
));
602 *ppContainer
= pContainer
;
603 return ERROR_SUCCESS
;
606 ERR("no container found\n");
607 return ERROR_FILE_NOT_FOUND
;
610 static DWORD
URLCacheContainers_FindContainerA(LPCSTR lpszUrl
, URLCACHECONTAINER
** ppContainer
)
614 int url_len
= MultiByteToWideChar(CP_ACP
, 0, lpszUrl
, -1, NULL
, 0);
615 if (url_len
&& (lpwszUrl
= HeapAlloc(GetProcessHeap(), 0, url_len
* sizeof(WCHAR
))))
617 MultiByteToWideChar(CP_ACP
, 0, lpszUrl
, -1, lpwszUrl
, url_len
);
618 ret
= URLCacheContainers_FindContainerW(lpwszUrl
, ppContainer
);
619 HeapFree(GetProcessHeap(), 0, lpwszUrl
);
622 return GetLastError();
625 static BOOL
URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern
, DWORD dwIndex
, URLCACHECONTAINER
** ppContainer
)
628 URLCACHECONTAINER
* pContainer
;
630 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern
));
632 /* non-NULL search pattern only returns one container ever */
633 if (lpwszSearchPattern
&& dwIndex
> 0)
636 LIST_FOR_EACH_ENTRY(pContainer
, &UrlContainers
, URLCACHECONTAINER
, entry
)
638 if (lpwszSearchPattern
)
640 if (!strcmpW(pContainer
->cache_prefix
, lpwszSearchPattern
))
642 TRACE("found container with prefix %s\n", debugstr_w(pContainer
->cache_prefix
));
643 *ppContainer
= pContainer
;
651 TRACE("found container with prefix %s\n", debugstr_w(pContainer
->cache_prefix
));
652 *ppContainer
= pContainer
;
661 /***********************************************************************
662 * URLCacheContainer_LockIndex (Internal)
664 * Locks the index for system-wide exclusive access.
667 * Cache file header if successful
668 * NULL if failed and calls SetLastError.
670 static LPURLCACHE_HEADER
URLCacheContainer_LockIndex(URLCACHECONTAINER
* pContainer
)
674 URLCACHE_HEADER
* pHeader
;
678 WaitForSingleObject(pContainer
->hMutex
, INFINITE
);
680 pIndexData
= MapViewOfFile(pContainer
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
684 ReleaseMutex(pContainer
->hMutex
);
685 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
688 pHeader
= (URLCACHE_HEADER
*)pIndexData
;
690 /* file has grown - we need to remap to prevent us getting
691 * access violations when we try and access beyond the end
692 * of the memory mapped file */
693 if (pHeader
->dwFileSize
!= pContainer
->file_size
)
695 UnmapViewOfFile( pHeader
);
696 URLCacheContainer_CloseIndex(pContainer
);
697 error
= URLCacheContainer_OpenIndex(pContainer
);
698 if (error
!= ERROR_SUCCESS
)
700 ReleaseMutex(pContainer
->hMutex
);
704 pIndexData
= MapViewOfFile(pContainer
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
708 ReleaseMutex(pContainer
->hMutex
);
709 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
712 pHeader
= (URLCACHE_HEADER
*)pIndexData
;
715 TRACE("Signature: %s, file size: %d bytes\n", pHeader
->szSignature
, pHeader
->dwFileSize
);
717 for (index
= 0; index
< pHeader
->DirectoryCount
; index
++)
719 TRACE("Directory[%d] = \"%.8s\"\n", index
, pHeader
->directory_data
[index
].filename
);
725 /***********************************************************************
726 * URLCacheContainer_UnlockIndex (Internal)
729 static BOOL
URLCacheContainer_UnlockIndex(URLCACHECONTAINER
* pContainer
, LPURLCACHE_HEADER pHeader
)
732 ReleaseMutex(pContainer
->hMutex
);
733 return UnmapViewOfFile(pHeader
);
738 #define CHAR_BIT (8 * sizeof(CHAR))
741 /***********************************************************************
742 * URLCache_Allocation_BlockIsFree (Internal)
744 * Is the specified block number free?
751 static inline BYTE
URLCache_Allocation_BlockIsFree(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
753 BYTE mask
= 1 << (dwBlockNumber
% CHAR_BIT
);
754 return (AllocationTable
[dwBlockNumber
/ CHAR_BIT
] & mask
) == 0;
757 /***********************************************************************
758 * URLCache_Allocation_BlockFree (Internal)
760 * Marks the specified block as free
766 static inline void URLCache_Allocation_BlockFree(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
768 BYTE mask
= ~(1 << (dwBlockNumber
% CHAR_BIT
));
769 AllocationTable
[dwBlockNumber
/ CHAR_BIT
] &= mask
;
772 /***********************************************************************
773 * URLCache_Allocation_BlockAllocate (Internal)
775 * Marks the specified block as allocated
781 static inline void URLCache_Allocation_BlockAllocate(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
783 BYTE mask
= 1 << (dwBlockNumber
% CHAR_BIT
);
784 AllocationTable
[dwBlockNumber
/ CHAR_BIT
] |= mask
;
787 /***********************************************************************
788 * URLCache_FindFirstFreeEntry (Internal)
790 * Finds and allocates the first block of free space big enough and
791 * sets ppEntry to point to it.
794 * TRUE if it had enough space
795 * FALSE if it couldn't find enough space
798 static BOOL
URLCache_FindFirstFreeEntry(URLCACHE_HEADER
* pHeader
, DWORD dwBlocksNeeded
, CACHEFILE_ENTRY
** ppEntry
)
800 LPBYTE AllocationTable
= (LPBYTE
)pHeader
+ ALLOCATION_TABLE_OFFSET
;
803 for (dwBlockNumber
= 0; dwBlockNumber
< pHeader
->dwIndexCapacityInBlocks
; dwBlockNumber
++)
805 for (dwFreeCounter
= 0;
806 dwFreeCounter
< dwBlocksNeeded
&&
807 dwFreeCounter
+ dwBlockNumber
< pHeader
->dwIndexCapacityInBlocks
&&
808 URLCache_Allocation_BlockIsFree(AllocationTable
, dwBlockNumber
+ dwFreeCounter
);
810 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber
, ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
812 if (dwFreeCounter
== dwBlocksNeeded
)
815 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber
, ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
816 for (index
= 0; index
< dwBlocksNeeded
; index
++)
817 URLCache_Allocation_BlockAllocate(AllocationTable
, dwBlockNumber
+ index
);
818 *ppEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
819 (*ppEntry
)->dwBlocksUsed
= dwBlocksNeeded
;
823 FIXME("Grow file\n");
827 /***********************************************************************
828 * URLCache_DeleteEntry (Internal)
830 * Deletes the specified entry and frees the space allocated to it
833 * TRUE if it succeeded
837 static BOOL
URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader
, CACHEFILE_ENTRY
* pEntry
)
841 BYTE
* AllocationTable
= (LPBYTE
)pHeader
+ ALLOCATION_TABLE_OFFSET
;
843 /* update allocation table */
844 dwStartBlock
= ((DWORD
)((BYTE
*)pEntry
- (BYTE
*)pHeader
)) / BLOCKSIZE
;
845 for (dwBlock
= dwStartBlock
; dwBlock
< dwStartBlock
+ pEntry
->dwBlocksUsed
; dwBlock
++)
846 URLCache_Allocation_BlockFree(AllocationTable
, dwBlock
);
848 ZeroMemory(pEntry
, pEntry
->dwBlocksUsed
* BLOCKSIZE
);
852 /***********************************************************************
853 * URLCache_LocalFileNameToPathW (Internal)
855 * Copies the full path to the specified buffer given the local file
856 * name and the index of the directory it is in. Always sets value in
857 * lpBufferSize to the required buffer size (in bytes).
860 * TRUE if the buffer was big enough
861 * FALSE if the buffer was too small
864 static BOOL
URLCache_LocalFileNameToPathW(
865 const URLCACHECONTAINER
* pContainer
,
866 LPCURLCACHE_HEADER pHeader
,
867 LPCSTR szLocalFileName
,
873 int path_len
= strlenW(pContainer
->path
);
874 int file_name_len
= MultiByteToWideChar(CP_ACP
, 0, szLocalFileName
, -1, NULL
, 0);
875 if (Directory
>= pHeader
->DirectoryCount
)
881 nRequired
= (path_len
+ DIR_LENGTH
+ file_name_len
+ 1) * sizeof(WCHAR
);
882 if (nRequired
< *lpBufferSize
)
886 memcpy(wszPath
, pContainer
->path
, path_len
* sizeof(WCHAR
));
887 dir_len
= MultiByteToWideChar(CP_ACP
, 0, pHeader
->directory_data
[Directory
].filename
, DIR_LENGTH
, wszPath
+ path_len
, DIR_LENGTH
);
888 wszPath
[dir_len
+ path_len
] = '\\';
889 MultiByteToWideChar(CP_ACP
, 0, szLocalFileName
, -1, wszPath
+ dir_len
+ path_len
+ 1, file_name_len
);
890 *lpBufferSize
= nRequired
;
893 *lpBufferSize
= nRequired
;
897 /***********************************************************************
898 * URLCache_LocalFileNameToPathA (Internal)
900 * Copies the full path to the specified buffer given the local file
901 * name and the index of the directory it is in. Always sets value in
902 * lpBufferSize to the required buffer size.
905 * TRUE if the buffer was big enough
906 * FALSE if the buffer was too small
909 static BOOL
URLCache_LocalFileNameToPathA(
910 const URLCACHECONTAINER
* pContainer
,
911 LPCURLCACHE_HEADER pHeader
,
912 LPCSTR szLocalFileName
,
918 int path_len
, file_name_len
, dir_len
;
920 if (Directory
>= pHeader
->DirectoryCount
)
926 path_len
= WideCharToMultiByte(CP_ACP
, 0, pContainer
->path
, -1, NULL
, 0, NULL
, NULL
) - 1;
927 file_name_len
= strlen(szLocalFileName
) + 1 /* for nul-terminator */;
928 dir_len
= DIR_LENGTH
;
930 nRequired
= (path_len
+ dir_len
+ 1 + file_name_len
) * sizeof(char);
931 if (nRequired
< *lpBufferSize
)
933 WideCharToMultiByte(CP_ACP
, 0, pContainer
->path
, -1, szPath
, path_len
, NULL
, NULL
);
934 memcpy(szPath
+path_len
, pHeader
->directory_data
[Directory
].filename
, dir_len
);
935 szPath
[path_len
+ dir_len
] = '\\';
936 memcpy(szPath
+ path_len
+ dir_len
+ 1, szLocalFileName
, file_name_len
);
937 *lpBufferSize
= nRequired
;
940 *lpBufferSize
= nRequired
;
944 /***********************************************************************
945 * URLCache_CopyEntry (Internal)
947 * Copies an entry from the cache index file to the Win32 structure
950 * ERROR_SUCCESS if the buffer was big enough
951 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
954 static DWORD
URLCache_CopyEntry(
955 URLCACHECONTAINER
* pContainer
,
956 LPCURLCACHE_HEADER pHeader
,
957 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
958 LPDWORD lpdwBufferSize
,
959 const URL_CACHEFILE_ENTRY
* pUrlEntry
,
963 DWORD dwRequiredSize
= sizeof(*lpCacheEntryInfo
);
965 if (*lpdwBufferSize
>= dwRequiredSize
)
967 lpCacheEntryInfo
->lpHeaderInfo
= NULL
;
968 lpCacheEntryInfo
->lpszFileExtension
= NULL
;
969 lpCacheEntryInfo
->lpszLocalFileName
= NULL
;
970 lpCacheEntryInfo
->lpszSourceUrlName
= NULL
;
971 lpCacheEntryInfo
->CacheEntryType
= pUrlEntry
->CacheEntryType
;
972 lpCacheEntryInfo
->u
.dwExemptDelta
= pUrlEntry
->dwExemptDelta
;
973 lpCacheEntryInfo
->dwHeaderInfoSize
= pUrlEntry
->dwHeaderInfoSize
;
974 lpCacheEntryInfo
->dwHitRate
= pUrlEntry
->dwHitRate
;
975 lpCacheEntryInfo
->dwSizeHigh
= pUrlEntry
->dwSizeHigh
;
976 lpCacheEntryInfo
->dwSizeLow
= pUrlEntry
->dwSizeLow
;
977 lpCacheEntryInfo
->dwStructSize
= sizeof(*lpCacheEntryInfo
);
978 lpCacheEntryInfo
->dwUseCount
= pUrlEntry
->dwUseCount
;
979 DosDateTimeToFileTime(pUrlEntry
->wExpiredDate
, pUrlEntry
->wExpiredTime
, &lpCacheEntryInfo
->ExpireTime
);
980 lpCacheEntryInfo
->LastAccessTime
.dwHighDateTime
= pUrlEntry
->LastAccessTime
.dwHighDateTime
;
981 lpCacheEntryInfo
->LastAccessTime
.dwLowDateTime
= pUrlEntry
->LastAccessTime
.dwLowDateTime
;
982 lpCacheEntryInfo
->LastModifiedTime
.dwHighDateTime
= pUrlEntry
->LastModifiedTime
.dwHighDateTime
;
983 lpCacheEntryInfo
->LastModifiedTime
.dwLowDateTime
= pUrlEntry
->LastModifiedTime
.dwLowDateTime
;
984 DosDateTimeToFileTime(pUrlEntry
->wLastSyncDate
, pUrlEntry
->wLastSyncTime
, &lpCacheEntryInfo
->LastSyncTime
);
987 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
988 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
989 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
991 lenUrl
= MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, -1, NULL
, 0);
993 lenUrl
= strlen((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
994 dwRequiredSize
+= (lenUrl
+ 1) * (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
996 /* FIXME: is source url optional? */
997 if (*lpdwBufferSize
>= dwRequiredSize
)
999 DWORD lenUrlBytes
= (lenUrl
+1) * (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
1001 lpCacheEntryInfo
->lpszSourceUrlName
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
- lenUrlBytes
;
1003 MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, -1, (LPWSTR
)lpCacheEntryInfo
->lpszSourceUrlName
, lenUrl
+ 1);
1005 memcpy(lpCacheEntryInfo
->lpszSourceUrlName
, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, lenUrlBytes
);
1008 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1009 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1010 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1012 if (pUrlEntry
->dwOffsetLocalName
)
1014 LONG nLocalFilePathSize
;
1015 LPSTR lpszLocalFileName
;
1016 lpszLocalFileName
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
;
1017 nLocalFilePathSize
= *lpdwBufferSize
- dwRequiredSize
;
1018 if ((bUnicode
&& URLCache_LocalFileNameToPathW(pContainer
, pHeader
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
, pUrlEntry
->CacheDir
, (LPWSTR
)lpszLocalFileName
, &nLocalFilePathSize
)) ||
1019 (!bUnicode
&& URLCache_LocalFileNameToPathA(pContainer
, pHeader
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
, pUrlEntry
->CacheDir
, lpszLocalFileName
, &nLocalFilePathSize
)))
1021 lpCacheEntryInfo
->lpszLocalFileName
= lpszLocalFileName
;
1023 dwRequiredSize
+= nLocalFilePathSize
* (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
)) ;
1025 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1026 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1027 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1029 dwRequiredSize
+= pUrlEntry
->dwHeaderInfoSize
+ 1;
1031 if (*lpdwBufferSize
>= dwRequiredSize
)
1033 lpCacheEntryInfo
->lpHeaderInfo
= (LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
- pUrlEntry
->dwHeaderInfoSize
- 1;
1034 memcpy(lpCacheEntryInfo
->lpHeaderInfo
, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
, pUrlEntry
->dwHeaderInfoSize
);
1035 ((LPBYTE
)lpCacheEntryInfo
)[dwRequiredSize
- 1] = '\0';
1037 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1038 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1039 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1041 if (pUrlEntry
->dwOffsetFileExtension
)
1046 lenExtension
= MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, -1, NULL
, 0);
1048 lenExtension
= strlen((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
) + 1;
1049 dwRequiredSize
+= lenExtension
* (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
1051 if (*lpdwBufferSize
>= dwRequiredSize
)
1053 lpCacheEntryInfo
->lpszFileExtension
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
- lenExtension
;
1055 MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, -1, (LPWSTR
)lpCacheEntryInfo
->lpszSourceUrlName
, lenExtension
);
1057 memcpy(lpCacheEntryInfo
->lpszFileExtension
, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, lenExtension
* sizeof(CHAR
));
1060 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1061 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1062 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1065 if (dwRequiredSize
> *lpdwBufferSize
)
1067 *lpdwBufferSize
= dwRequiredSize
;
1068 return ERROR_INSUFFICIENT_BUFFER
;
1070 *lpdwBufferSize
= dwRequiredSize
;
1071 return ERROR_SUCCESS
;
1075 /***********************************************************************
1076 * URLCache_SetEntryInfo (Internal)
1078 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1079 * according to the flags set by dwFieldControl.
1082 * ERROR_SUCCESS if the buffer was big enough
1083 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1086 static DWORD
URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY
* pUrlEntry
, const INTERNET_CACHE_ENTRY_INFOW
* lpCacheEntryInfo
, DWORD dwFieldControl
)
1088 if (dwFieldControl
& CACHE_ENTRY_ACCTIME_FC
)
1089 pUrlEntry
->LastAccessTime
= lpCacheEntryInfo
->LastAccessTime
;
1090 if (dwFieldControl
& CACHE_ENTRY_ATTRIBUTE_FC
)
1091 pUrlEntry
->CacheEntryType
= lpCacheEntryInfo
->CacheEntryType
;
1092 if (dwFieldControl
& CACHE_ENTRY_EXEMPT_DELTA_FC
)
1093 pUrlEntry
->dwExemptDelta
= lpCacheEntryInfo
->u
.dwExemptDelta
;
1094 if (dwFieldControl
& CACHE_ENTRY_EXPTIME_FC
)
1095 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1096 if (dwFieldControl
& CACHE_ENTRY_HEADERINFO_FC
)
1097 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1098 if (dwFieldControl
& CACHE_ENTRY_HITRATE_FC
)
1099 pUrlEntry
->dwHitRate
= lpCacheEntryInfo
->dwHitRate
;
1100 if (dwFieldControl
& CACHE_ENTRY_MODTIME_FC
)
1101 pUrlEntry
->LastModifiedTime
= lpCacheEntryInfo
->LastModifiedTime
;
1102 if (dwFieldControl
& CACHE_ENTRY_SYNCTIME_FC
)
1103 FileTimeToDosDateTime(&lpCacheEntryInfo
->LastAccessTime
, &pUrlEntry
->wLastSyncDate
, &pUrlEntry
->wLastSyncTime
);
1105 return ERROR_SUCCESS
;
1108 /***********************************************************************
1109 * URLCache_HashKey (Internal)
1111 * Returns the hash key for a given string
1114 * hash key for the string
1117 static DWORD
URLCache_HashKey(LPCSTR lpszKey
)
1119 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1120 * but the algorithm and result are not the same!
1122 static const unsigned char lookupTable
[256] =
1124 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1125 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1126 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1127 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1128 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1129 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1130 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1131 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1132 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1133 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1134 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1135 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1136 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1137 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1138 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1139 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1140 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1141 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1142 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1143 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1144 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1145 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1146 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1147 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1148 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1149 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1150 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1151 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1152 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1153 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1154 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1155 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1160 for (i
= 0; i
< sizeof(key
) / sizeof(key
[0]); i
++)
1161 key
[i
] = lookupTable
[i
];
1163 for (lpszKey
++; *lpszKey
&& ((lpszKey
[0] != '/') || (lpszKey
[1] != 0)); lpszKey
++)
1165 for (i
= 0; i
< sizeof(key
) / sizeof(key
[0]); i
++)
1166 key
[i
] = lookupTable
[*lpszKey
^ key
[i
]];
1169 return *(DWORD
*)key
;
1172 static inline HASH_CACHEFILE_ENTRY
* URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader
, DWORD dwOffset
)
1174 return (HASH_CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ dwOffset
);
1177 static inline BOOL
URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader
, const HASH_CACHEFILE_ENTRY
*pHashEntry
)
1179 /* check pHashEntry located within acceptable bounds in the URL cache mapping */
1180 return ((DWORD
)((LPBYTE
)pHashEntry
- (LPBYTE
)pHeader
) >= ENTRY_START_OFFSET
) &&
1181 ((DWORD
)((LPBYTE
)pHashEntry
- (LPBYTE
)pHeader
) < pHeader
->dwFileSize
);
1184 static BOOL
URLCache_FindHash(LPCURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, struct _HASH_ENTRY
** ppHashEntry
)
1186 /* structure of hash table:
1187 * 448 entries divided into 64 blocks
1188 * each block therefore contains a chain of 7 key/offset pairs
1189 * how position in table is calculated:
1190 * 1. the url is hashed in helper function
1191 * 2. the key % 64 * 8 is the offset
1192 * 3. the key in the hash table is the hash key aligned to 64
1195 * there can be multiple hash tables in the file and the offset to
1196 * the next one is stored in the header of the hash table
1198 DWORD key
= URLCache_HashKey(lpszUrl
);
1199 DWORD offset
= (key
% HASHTABLE_NUM_ENTRIES
) * sizeof(struct _HASH_ENTRY
);
1200 HASH_CACHEFILE_ENTRY
* pHashEntry
;
1201 DWORD dwHashTableNumber
= 0;
1203 key
= (key
/ HASHTABLE_NUM_ENTRIES
) * HASHTABLE_NUM_ENTRIES
;
1205 for (pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1206 URLCache_IsHashEntryValid(pHeader
, pHashEntry
);
1207 pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHashEntry
->dwAddressNext
))
1210 if (pHashEntry
->dwHashTableNumber
!= dwHashTableNumber
++)
1212 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry
->dwHashTableNumber
, dwHashTableNumber
);
1215 /* make sure that it is in fact a hash entry */
1216 if (pHashEntry
->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1218 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&pHashEntry
->CacheFileEntry
.dwSignature
);
1222 for (i
= 0; i
< HASHTABLE_BLOCKSIZE
; i
++)
1224 struct _HASH_ENTRY
* pHashElement
= &pHashEntry
->HashTable
[offset
+ i
];
1225 if (key
== (pHashElement
->dwHashKey
/ HASHTABLE_NUM_ENTRIES
) * HASHTABLE_NUM_ENTRIES
)
1227 /* FIXME: we should make sure that this is the right element
1228 * before returning and claiming that it is. We can do this
1229 * by doing a simple compare between the URL we were given
1230 * and the URL stored in the entry. However, this assumes
1231 * we know the format of all the entries stored in the
1233 *ppHashEntry
= pHashElement
;
1241 static BOOL
URLCache_FindHashW(LPCURLCACHE_HEADER pHeader
, LPCWSTR lpszUrl
, struct _HASH_ENTRY
** ppHashEntry
)
1247 url_len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrl
, -1, NULL
, 0, NULL
, NULL
);
1248 urlA
= HeapAlloc(GetProcessHeap(), 0, url_len
* sizeof(CHAR
));
1251 SetLastError(ERROR_OUTOFMEMORY
);
1254 WideCharToMultiByte(CP_ACP
, 0, lpszUrl
, -1, urlA
, url_len
, NULL
, NULL
);
1255 ret
= URLCache_FindHash(pHeader
, urlA
, ppHashEntry
);
1256 HeapFree(GetProcessHeap(), 0, urlA
);
1260 /***********************************************************************
1261 * URLCache_HashEntrySetUse (Internal)
1263 * Searches all the hash tables in the index for the given URL and
1264 * sets the use count (stored or'ed with key)
1267 * TRUE if the entry was found
1268 * FALSE if the entry could not be found
1271 static BOOL
URLCache_HashEntrySetUse(struct _HASH_ENTRY
* pHashEntry
, DWORD dwUseCount
)
1273 pHashEntry
->dwHashKey
= dwUseCount
| (pHashEntry
->dwHashKey
/ HASHTABLE_NUM_ENTRIES
) * HASHTABLE_NUM_ENTRIES
;
1277 /***********************************************************************
1278 * URLCache_DeleteEntryFromHash (Internal)
1280 * Searches all the hash tables in the index for the given URL and
1281 * then if found deletes the entry.
1284 * TRUE if the entry was found
1285 * FALSE if the entry could not be found
1288 static BOOL
URLCache_DeleteEntryFromHash(struct _HASH_ENTRY
* pHashEntry
)
1290 pHashEntry
->dwHashKey
= HASHTABLE_FREE
;
1291 pHashEntry
->dwOffsetEntry
= HASHTABLE_FREE
;
1295 /***********************************************************************
1296 * URLCache_AddEntryToHash (Internal)
1298 * Searches all the hash tables for a free slot based on the offset
1299 * generated from the hash key. If a free slot is found, the offset and
1300 * key are entered into the hash table.
1303 * ERROR_SUCCESS if the entry was added
1304 * Any other Win32 error code if the entry could not be added
1307 static DWORD
URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, DWORD dwOffsetEntry
)
1309 /* see URLCache_FindEntryInHash for structure of hash tables */
1311 DWORD key
= URLCache_HashKey(lpszUrl
);
1312 DWORD offset
= (key
% HASHTABLE_NUM_ENTRIES
) * sizeof(struct _HASH_ENTRY
);
1313 HASH_CACHEFILE_ENTRY
* pHashEntry
;
1314 DWORD dwHashTableNumber
= 0;
1317 key
= (key
/ HASHTABLE_NUM_ENTRIES
) * HASHTABLE_NUM_ENTRIES
;
1319 for (pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1320 URLCache_IsHashEntryValid(pHeader
, pHashEntry
);
1321 pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHashEntry
->dwAddressNext
))
1324 if (pHashEntry
->dwHashTableNumber
!= dwHashTableNumber
++)
1326 ERR("not right hash table number (%d) expected %d\n", pHashEntry
->dwHashTableNumber
, dwHashTableNumber
);
1329 /* make sure that it is in fact a hash entry */
1330 if (pHashEntry
->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1332 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&pHashEntry
->CacheFileEntry
.dwSignature
);
1336 for (i
= 0; i
< HASHTABLE_BLOCKSIZE
; i
++)
1338 struct _HASH_ENTRY
* pHashElement
= &pHashEntry
->HashTable
[offset
+ i
];
1339 if (pHashElement
->dwHashKey
== HASHTABLE_FREE
) /* if the slot is free */
1341 pHashElement
->dwHashKey
= key
;
1342 pHashElement
->dwOffsetEntry
= dwOffsetEntry
;
1343 return ERROR_SUCCESS
;
1347 error
= URLCache_CreateHashTable(pHeader
, pHashEntry
, &pHashEntry
);
1348 if (error
!= ERROR_SUCCESS
)
1351 pHashEntry
->HashTable
[offset
].dwHashKey
= key
;
1352 pHashEntry
->HashTable
[offset
].dwOffsetEntry
= dwOffsetEntry
;
1353 return ERROR_SUCCESS
;
1356 /***********************************************************************
1357 * URLCache_CreateHashTable (Internal)
1359 * Creates a new hash table in free space and adds it to the chain of existing
1363 * ERROR_SUCCESS if the hash table was created
1364 * ERROR_DISK_FULL if the hash table could not be created
1367 static DWORD
URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader
, HASH_CACHEFILE_ENTRY
*pPrevHash
, HASH_CACHEFILE_ENTRY
**ppHash
)
1372 if (!URLCache_FindFirstFreeEntry(pHeader
, 0x20, (CACHEFILE_ENTRY
**)ppHash
))
1374 FIXME("no free space for hash table\n");
1375 return ERROR_DISK_FULL
;
1378 dwOffset
= (BYTE
*)*ppHash
- (BYTE
*)pHeader
;
1381 pPrevHash
->dwAddressNext
= dwOffset
;
1383 pHeader
->dwOffsetFirstHashTable
= dwOffset
;
1384 (*ppHash
)->CacheFileEntry
.dwSignature
= HASH_SIGNATURE
;
1385 (*ppHash
)->CacheFileEntry
.dwBlocksUsed
= 0x20;
1386 (*ppHash
)->dwHashTableNumber
= pPrevHash
? pPrevHash
->dwHashTableNumber
+ 1 : 0;
1387 for (i
= 0; i
< HASHTABLE_SIZE
; i
++)
1389 (*ppHash
)->HashTable
[i
].dwOffsetEntry
= 0;
1390 (*ppHash
)->HashTable
[i
].dwHashKey
= HASHTABLE_FREE
;
1392 return ERROR_SUCCESS
;
1395 /***********************************************************************
1396 * URLCache_EnumHashTables (Internal)
1398 * Enumerates the hash tables in a container.
1401 * TRUE if an entry was found
1402 * FALSE if there are no more tables to enumerate.
1405 static BOOL
URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader
, DWORD
*pdwHashTableNumber
, HASH_CACHEFILE_ENTRY
** ppHashEntry
)
1407 for (*ppHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1408 URLCache_IsHashEntryValid(pHeader
, *ppHashEntry
);
1409 *ppHashEntry
= URLCache_HashEntryFromOffset(pHeader
, (*ppHashEntry
)->dwAddressNext
))
1411 TRACE("looking at hash table number %d\n", (*ppHashEntry
)->dwHashTableNumber
);
1412 if ((*ppHashEntry
)->dwHashTableNumber
!= *pdwHashTableNumber
)
1414 /* make sure that it is in fact a hash entry */
1415 if ((*ppHashEntry
)->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1417 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&(*ppHashEntry
)->CacheFileEntry
.dwSignature
);
1418 (*pdwHashTableNumber
)++;
1422 TRACE("hash table number %d found\n", *pdwHashTableNumber
);
1428 /***********************************************************************
1429 * URLCache_EnumHashTableEntries (Internal)
1431 * Enumerates entries in a hash table and returns the next non-free entry.
1434 * TRUE if an entry was found
1435 * FALSE if the hash table is empty or there are no more entries to
1439 static BOOL
URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader
, const HASH_CACHEFILE_ENTRY
* pHashEntry
,
1440 DWORD
* index
, const struct _HASH_ENTRY
** ppHashEntry
)
1442 for (; *index
< HASHTABLE_SIZE
; (*index
)++)
1444 if (pHashEntry
->HashTable
[*index
].dwHashKey
== HASHTABLE_FREE
)
1447 *ppHashEntry
= &pHashEntry
->HashTable
[*index
];
1448 TRACE("entry found %d\n", *index
);
1451 TRACE("no more entries (%d)\n", *index
);
1455 /***********************************************************************
1456 * GetUrlCacheEntryInfoExA (WININET.@)
1459 BOOL WINAPI
GetUrlCacheEntryInfoExA(
1461 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1462 LPDWORD lpdwCacheEntryInfoBufSize
,
1464 LPDWORD lpdwReserved
,
1468 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1469 debugstr_a(lpszUrl
),
1471 lpdwCacheEntryInfoBufSize
,
1477 if ((lpszReserved
!= NULL
) ||
1478 (lpdwReserved
!= NULL
) ||
1479 (lpReserved
!= NULL
))
1481 ERR("Reserved value was not 0\n");
1482 SetLastError(ERROR_INVALID_PARAMETER
);
1486 FIXME("Undocumented flag(s): %x\n", dwFlags
);
1487 return GetUrlCacheEntryInfoA(lpszUrl
, lpCacheEntryInfo
, lpdwCacheEntryInfoBufSize
);
1490 /***********************************************************************
1491 * GetUrlCacheEntryInfoA (WININET.@)
1494 BOOL WINAPI
GetUrlCacheEntryInfoA(
1495 IN LPCSTR lpszUrlName
,
1496 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1497 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1500 LPURLCACHE_HEADER pHeader
;
1501 struct _HASH_ENTRY
* pHashEntry
;
1502 const CACHEFILE_ENTRY
* pEntry
;
1503 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
1504 URLCACHECONTAINER
* pContainer
;
1507 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
, lpdwCacheEntryInfoBufferSize
);
1509 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
1510 if (error
!= ERROR_SUCCESS
)
1512 SetLastError(error
);
1516 error
= URLCacheContainer_OpenIndex(pContainer
);
1517 if (error
!= ERROR_SUCCESS
)
1519 SetLastError(error
);
1523 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1526 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
1528 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1529 WARN("entry %s not found!\n", debugstr_a(lpszUrlName
));
1530 SetLastError(ERROR_FILE_NOT_FOUND
);
1534 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1535 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1537 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1538 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1539 SetLastError(ERROR_FILE_NOT_FOUND
);
1543 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
1544 TRACE("Found URL: %s\n", debugstr_a((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
));
1545 if (pUrlEntry
->dwOffsetHeaderInfo
)
1546 TRACE("Header info: %s\n", debugstr_a((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
1548 if (lpdwCacheEntryInfoBufferSize
)
1550 if (!lpCacheEntryInfo
)
1551 *lpdwCacheEntryInfoBufferSize
= 0;
1553 error
= URLCache_CopyEntry(
1557 lpdwCacheEntryInfoBufferSize
,
1560 if (error
!= ERROR_SUCCESS
)
1562 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1563 SetLastError(error
);
1566 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
1569 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1574 /***********************************************************************
1575 * GetUrlCacheEntryInfoW (WININET.@)
1578 BOOL WINAPI
GetUrlCacheEntryInfoW(LPCWSTR lpszUrl
,
1579 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1580 LPDWORD lpdwCacheEntryInfoBufferSize
)
1582 LPURLCACHE_HEADER pHeader
;
1583 struct _HASH_ENTRY
* pHashEntry
;
1584 const CACHEFILE_ENTRY
* pEntry
;
1585 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
1586 URLCACHECONTAINER
* pContainer
;
1589 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl
), lpCacheEntryInfo
, lpdwCacheEntryInfoBufferSize
);
1591 error
= URLCacheContainers_FindContainerW(lpszUrl
, &pContainer
);
1592 if (error
!= ERROR_SUCCESS
)
1594 SetLastError(error
);
1598 error
= URLCacheContainer_OpenIndex(pContainer
);
1599 if (error
!= ERROR_SUCCESS
)
1601 SetLastError(error
);
1605 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1608 if (!URLCache_FindHashW(pHeader
, lpszUrl
, &pHashEntry
))
1610 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1611 WARN("entry %s not found!\n", debugstr_w(lpszUrl
));
1612 SetLastError(ERROR_FILE_NOT_FOUND
);
1616 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1617 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1619 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1620 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1621 SetLastError(ERROR_FILE_NOT_FOUND
);
1625 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
1626 TRACE("Found URL: %s\n", debugstr_a((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
));
1627 TRACE("Header info: %s\n", debugstr_a((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
1629 if (lpdwCacheEntryInfoBufferSize
)
1631 if (!lpCacheEntryInfo
)
1632 *lpdwCacheEntryInfoBufferSize
= 0;
1634 error
= URLCache_CopyEntry(
1637 (LPINTERNET_CACHE_ENTRY_INFOA
)lpCacheEntryInfo
,
1638 lpdwCacheEntryInfoBufferSize
,
1640 TRUE
/* UNICODE */);
1641 if (error
!= ERROR_SUCCESS
)
1643 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1644 SetLastError(error
);
1647 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
1650 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1655 /***********************************************************************
1656 * GetUrlCacheEntryInfoExW (WININET.@)
1659 BOOL WINAPI
GetUrlCacheEntryInfoExW(
1661 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1662 LPDWORD lpdwCacheEntryInfoBufSize
,
1663 LPWSTR lpszReserved
,
1664 LPDWORD lpdwReserved
,
1668 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1669 debugstr_w(lpszUrl
),
1671 lpdwCacheEntryInfoBufSize
,
1677 if ((lpszReserved
!= NULL
) ||
1678 (lpdwReserved
!= NULL
) ||
1679 (lpReserved
!= NULL
))
1681 ERR("Reserved value was not 0\n");
1682 SetLastError(ERROR_INVALID_PARAMETER
);
1686 FIXME("Undocumented flag(s): %x\n", dwFlags
);
1687 return GetUrlCacheEntryInfoW(lpszUrl
, lpCacheEntryInfo
, lpdwCacheEntryInfoBufSize
);
1690 /***********************************************************************
1691 * SetUrlCacheEntryInfoA (WININET.@)
1693 BOOL WINAPI
SetUrlCacheEntryInfoA(
1695 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1696 DWORD dwFieldControl
)
1698 LPURLCACHE_HEADER pHeader
;
1699 struct _HASH_ENTRY
* pHashEntry
;
1700 CACHEFILE_ENTRY
* pEntry
;
1701 URLCACHECONTAINER
* pContainer
;
1704 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
, dwFieldControl
);
1706 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
1707 if (error
!= ERROR_SUCCESS
)
1709 SetLastError(error
);
1713 error
= URLCacheContainer_OpenIndex(pContainer
);
1714 if (error
!= ERROR_SUCCESS
)
1716 SetLastError(error
);
1720 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1723 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
1725 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1726 WARN("entry %s not found!\n", debugstr_a(lpszUrlName
));
1727 SetLastError(ERROR_FILE_NOT_FOUND
);
1731 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1732 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1734 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1735 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1736 SetLastError(ERROR_FILE_NOT_FOUND
);
1740 URLCache_SetEntryInfo(
1741 (URL_CACHEFILE_ENTRY
*)pEntry
,
1742 (const INTERNET_CACHE_ENTRY_INFOW
*)lpCacheEntryInfo
,
1745 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1750 /***********************************************************************
1751 * SetUrlCacheEntryInfoW (WININET.@)
1753 BOOL WINAPI
SetUrlCacheEntryInfoW(LPCWSTR lpszUrl
, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
, DWORD dwFieldControl
)
1755 LPURLCACHE_HEADER pHeader
;
1756 struct _HASH_ENTRY
* pHashEntry
;
1757 CACHEFILE_ENTRY
* pEntry
;
1758 URLCACHECONTAINER
* pContainer
;
1761 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl
), lpCacheEntryInfo
, dwFieldControl
);
1763 error
= URLCacheContainers_FindContainerW(lpszUrl
, &pContainer
);
1764 if (error
!= ERROR_SUCCESS
)
1766 SetLastError(error
);
1770 error
= URLCacheContainer_OpenIndex(pContainer
);
1771 if (error
!= ERROR_SUCCESS
)
1773 SetLastError(error
);
1777 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1780 if (!URLCache_FindHashW(pHeader
, lpszUrl
, &pHashEntry
))
1782 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1783 WARN("entry %s not found!\n", debugstr_w(lpszUrl
));
1784 SetLastError(ERROR_FILE_NOT_FOUND
);
1788 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1789 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1791 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1792 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1793 SetLastError(ERROR_FILE_NOT_FOUND
);
1797 URLCache_SetEntryInfo(
1798 (URL_CACHEFILE_ENTRY
*)pEntry
,
1802 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1807 /***********************************************************************
1808 * RetrieveUrlCacheEntryFileA (WININET.@)
1811 BOOL WINAPI
RetrieveUrlCacheEntryFileA(
1812 IN LPCSTR lpszUrlName
,
1813 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1814 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
1818 LPURLCACHE_HEADER pHeader
;
1819 struct _HASH_ENTRY
* pHashEntry
;
1820 CACHEFILE_ENTRY
* pEntry
;
1821 URL_CACHEFILE_ENTRY
* pUrlEntry
;
1822 URLCACHECONTAINER
* pContainer
;
1825 TRACE("(%s, %p, %p, 0x%08x)\n",
1826 debugstr_a(lpszUrlName
),
1828 lpdwCacheEntryInfoBufferSize
,
1831 if (!lpszUrlName
|| !lpdwCacheEntryInfoBufferSize
||
1832 (!lpCacheEntryInfo
&& *lpdwCacheEntryInfoBufferSize
))
1834 SetLastError(ERROR_INVALID_PARAMETER
);
1838 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
1839 if (error
!= ERROR_SUCCESS
)
1841 SetLastError(error
);
1845 error
= URLCacheContainer_OpenIndex(pContainer
);
1846 if (error
!= ERROR_SUCCESS
)
1848 SetLastError(error
);
1852 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1855 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
1857 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1858 TRACE("entry %s not found!\n", lpszUrlName
);
1859 SetLastError(ERROR_FILE_NOT_FOUND
);
1863 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1864 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1866 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1867 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1868 SetLastError(ERROR_FILE_NOT_FOUND
);
1872 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
1873 TRACE("Found URL: %s\n", (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
1874 TRACE("Header info: %s\n", (LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
);
1876 pUrlEntry
->dwHitRate
++;
1877 pUrlEntry
->dwUseCount
++;
1878 URLCache_HashEntrySetUse(pHashEntry
, pUrlEntry
->dwUseCount
);
1880 error
= URLCache_CopyEntry(pContainer
, pHeader
, lpCacheEntryInfo
,
1881 lpdwCacheEntryInfoBufferSize
, pUrlEntry
,
1883 if (error
!= ERROR_SUCCESS
)
1885 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1886 SetLastError(error
);
1889 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
1891 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1896 /***********************************************************************
1897 * RetrieveUrlCacheEntryFileW (WININET.@)
1900 BOOL WINAPI
RetrieveUrlCacheEntryFileW(
1901 IN LPCWSTR lpszUrlName
,
1902 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1903 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
1907 LPURLCACHE_HEADER pHeader
;
1908 struct _HASH_ENTRY
* pHashEntry
;
1909 CACHEFILE_ENTRY
* pEntry
;
1910 URL_CACHEFILE_ENTRY
* pUrlEntry
;
1911 URLCACHECONTAINER
* pContainer
;
1914 TRACE("(%s, %p, %p, 0x%08x)\n",
1915 debugstr_w(lpszUrlName
),
1917 lpdwCacheEntryInfoBufferSize
,
1920 if (!lpszUrlName
|| !lpdwCacheEntryInfoBufferSize
||
1921 (!lpCacheEntryInfo
&& *lpdwCacheEntryInfoBufferSize
))
1923 SetLastError(ERROR_INVALID_PARAMETER
);
1927 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
1928 if (error
!= ERROR_SUCCESS
)
1930 SetLastError(error
);
1934 error
= URLCacheContainer_OpenIndex(pContainer
);
1935 if (error
!= ERROR_SUCCESS
)
1937 SetLastError(error
);
1941 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1944 if (!URLCache_FindHashW(pHeader
, lpszUrlName
, &pHashEntry
))
1946 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1947 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName
));
1948 SetLastError(ERROR_FILE_NOT_FOUND
);
1952 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1953 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1955 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1956 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1957 SetLastError(ERROR_FILE_NOT_FOUND
);
1961 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
1962 TRACE("Found URL: %s\n", (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
1963 TRACE("Header info: %s\n", (LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
);
1965 pUrlEntry
->dwHitRate
++;
1966 pUrlEntry
->dwUseCount
++;
1967 URLCache_HashEntrySetUse(pHashEntry
, pUrlEntry
->dwUseCount
);
1969 error
= URLCache_CopyEntry(
1972 (LPINTERNET_CACHE_ENTRY_INFOA
)lpCacheEntryInfo
,
1973 lpdwCacheEntryInfoBufferSize
,
1975 TRUE
/* UNICODE */);
1976 if (error
!= ERROR_SUCCESS
)
1978 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1979 SetLastError(error
);
1982 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
1984 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1989 /***********************************************************************
1990 * UnlockUrlCacheEntryFileA (WININET.@)
1993 BOOL WINAPI
UnlockUrlCacheEntryFileA(
1994 IN LPCSTR lpszUrlName
,
1998 LPURLCACHE_HEADER pHeader
;
1999 struct _HASH_ENTRY
* pHashEntry
;
2000 CACHEFILE_ENTRY
* pEntry
;
2001 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2002 URLCACHECONTAINER
* pContainer
;
2005 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName
), dwReserved
);
2009 ERR("dwReserved != 0\n");
2010 SetLastError(ERROR_INVALID_PARAMETER
);
2014 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
2015 if (error
!= ERROR_SUCCESS
)
2017 SetLastError(error
);
2021 error
= URLCacheContainer_OpenIndex(pContainer
);
2022 if (error
!= ERROR_SUCCESS
)
2024 SetLastError(error
);
2028 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2031 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
2033 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2034 TRACE("entry %s not found!\n", lpszUrlName
);
2035 SetLastError(ERROR_FILE_NOT_FOUND
);
2039 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2040 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2042 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2043 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2044 SetLastError(ERROR_FILE_NOT_FOUND
);
2048 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2050 if (pUrlEntry
->dwUseCount
== 0)
2052 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2055 pUrlEntry
->dwUseCount
--;
2056 URLCache_HashEntrySetUse(pHashEntry
, pUrlEntry
->dwUseCount
);
2058 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2063 /***********************************************************************
2064 * UnlockUrlCacheEntryFileW (WININET.@)
2067 BOOL WINAPI
UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName
, DWORD dwReserved
)
2069 LPURLCACHE_HEADER pHeader
;
2070 struct _HASH_ENTRY
* pHashEntry
;
2071 CACHEFILE_ENTRY
* pEntry
;
2072 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2073 URLCACHECONTAINER
* pContainer
;
2076 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName
), dwReserved
);
2080 ERR("dwReserved != 0\n");
2081 SetLastError(ERROR_INVALID_PARAMETER
);
2085 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2086 if (error
!= ERROR_SUCCESS
)
2088 SetLastError(error
);
2092 error
= URLCacheContainer_OpenIndex(pContainer
);
2093 if (error
!= ERROR_SUCCESS
)
2095 SetLastError(error
);
2099 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2102 if (!URLCache_FindHashW(pHeader
, lpszUrlName
, &pHashEntry
))
2104 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2105 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName
));
2106 SetLastError(ERROR_FILE_NOT_FOUND
);
2110 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2111 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2113 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2114 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2115 SetLastError(ERROR_FILE_NOT_FOUND
);
2119 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2121 if (pUrlEntry
->dwUseCount
== 0)
2123 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2126 pUrlEntry
->dwUseCount
--;
2127 URLCache_HashEntrySetUse(pHashEntry
, pUrlEntry
->dwUseCount
);
2129 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2134 /***********************************************************************
2135 * CreateUrlCacheEntryA (WININET.@)
2138 BOOL WINAPI
CreateUrlCacheEntryA(
2139 IN LPCSTR lpszUrlName
,
2140 IN DWORD dwExpectedFileSize
,
2141 IN LPCSTR lpszFileExtension
,
2142 OUT LPSTR lpszFileName
,
2148 WCHAR
*file_extension
;
2149 WCHAR file_name
[MAX_PATH
];
2150 BOOL bSuccess
= FALSE
;
2153 if ((len
= MultiByteToWideChar(CP_ACP
, 0, lpszUrlName
, -1, NULL
, 0)) != 0 &&
2154 (url_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))) != 0)
2156 MultiByteToWideChar(CP_ACP
, 0, lpszUrlName
, -1, url_name
, len
);
2157 if ((len
= MultiByteToWideChar(CP_ACP
, 0, lpszFileExtension
, -1, NULL
, 0)) != 0 &&
2158 (file_extension
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))) != 0)
2160 MultiByteToWideChar(CP_ACP
, 0, lpszFileExtension
, -1, file_extension
, len
);
2161 if (CreateUrlCacheEntryW(url_name
, dwExpectedFileSize
, file_extension
, file_name
, dwReserved
))
2163 if (WideCharToMultiByte(CP_ACP
, 0, file_name
, -1, lpszFileName
, MAX_PATH
, NULL
, NULL
) < MAX_PATH
)
2169 dwError
= GetLastError();
2174 dwError
= GetLastError();
2176 HeapFree(GetProcessHeap(), 0, file_extension
);
2180 dwError
= GetLastError();
2182 HeapFree(GetProcessHeap(), 0, url_name
);
2184 SetLastError(dwError
);
2188 /***********************************************************************
2189 * CreateUrlCacheEntryW (WININET.@)
2192 BOOL WINAPI
CreateUrlCacheEntryW(
2193 IN LPCWSTR lpszUrlName
,
2194 IN DWORD dwExpectedFileSize
,
2195 IN LPCWSTR lpszFileExtension
,
2196 OUT LPWSTR lpszFileName
,
2200 URLCACHECONTAINER
* pContainer
;
2201 LPURLCACHE_HEADER pHeader
;
2202 CHAR szFile
[MAX_PATH
];
2203 WCHAR szExtension
[MAX_PATH
];
2204 LPCWSTR lpszUrlPart
;
2206 LPCWSTR lpszFileNameExtension
;
2207 LPWSTR lpszFileNameNoPath
;
2209 int countnoextension
;
2212 BOOL bFound
= FALSE
;
2215 static const WCHAR szWWW
[] = {'w','w','w',0};
2217 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2218 debugstr_w(lpszUrlName
),
2220 debugstr_w(lpszFileExtension
),
2226 ERR("dwReserved != 0\n");
2227 SetLastError(ERROR_INVALID_PARAMETER
);
2231 lpszUrlEnd
= lpszUrlName
+ strlenW(lpszUrlName
);
2233 if (((lpszUrlEnd
- lpszUrlName
) > 1) && (*(lpszUrlEnd
- 1) == '/' || *(lpszUrlEnd
- 1) == '\\'))
2236 for (lpszUrlPart
= lpszUrlEnd
;
2237 (lpszUrlPart
>= lpszUrlName
);
2240 if ((*lpszUrlPart
== '/' || *lpszUrlPart
== '\\') && ((lpszUrlEnd
- lpszUrlPart
) > 1))
2246 else if(*lpszUrlPart
== '?' || *lpszUrlPart
== '#')
2248 lpszUrlEnd
= lpszUrlPart
;
2251 if (!lstrcmpW(lpszUrlPart
, szWWW
))
2253 lpszUrlPart
+= lstrlenW(szWWW
);
2256 count
= lpszUrlEnd
- lpszUrlPart
;
2258 if (bFound
&& (count
< MAX_PATH
))
2260 int len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlPart
, count
, szFile
, sizeof(szFile
) - 1, NULL
, NULL
);
2264 while(len
&& szFile
[--len
] == '/') szFile
[len
] = '\0';
2266 /* FIXME: get rid of illegal characters like \, / and : */
2270 FIXME("need to generate a random filename\n");
2273 TRACE("File name: %s\n", debugstr_a(szFile
));
2275 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2276 if (error
!= ERROR_SUCCESS
)
2278 SetLastError(error
);
2282 error
= URLCacheContainer_OpenIndex(pContainer
);
2283 if (error
!= ERROR_SUCCESS
)
2285 SetLastError(error
);
2289 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2292 CacheDir
= (BYTE
)(rand() % pHeader
->DirectoryCount
);
2294 lBufferSize
= MAX_PATH
* sizeof(WCHAR
);
2295 URLCache_LocalFileNameToPathW(pContainer
, pHeader
, szFile
, CacheDir
, lpszFileName
, &lBufferSize
);
2297 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2299 for (lpszFileNameNoPath
= lpszFileName
+ lBufferSize
/ sizeof(WCHAR
) - 2;
2300 lpszFileNameNoPath
>= lpszFileName
;
2301 --lpszFileNameNoPath
)
2303 if (*lpszFileNameNoPath
== '/' || *lpszFileNameNoPath
== '\\')
2307 countnoextension
= lstrlenW(lpszFileNameNoPath
);
2308 lpszFileNameExtension
= PathFindExtensionW(lpszFileNameNoPath
);
2309 if (lpszFileNameExtension
)
2310 countnoextension
-= lstrlenW(lpszFileNameExtension
);
2311 *szExtension
= '\0';
2313 if (lpszFileExtension
)
2315 szExtension
[0] = '.';
2316 lstrcpyW(szExtension
+1, lpszFileExtension
);
2319 for (i
= 0; i
< 255; i
++)
2321 static const WCHAR szFormat
[] = {'[','%','u',']','%','s',0};
2325 wsprintfW(lpszFileNameNoPath
+ countnoextension
, szFormat
, i
, szExtension
);
2326 for (p
= lpszFileNameNoPath
+ 1; *p
; p
++)
2332 case '/': case '\\':
2339 if (p
[-1] == ' ' || p
[-1] == '.') p
[-1] = '_';
2341 TRACE("Trying: %s\n", debugstr_w(lpszFileName
));
2342 hFile
= CreateFileW(lpszFileName
, GENERIC_READ
, 0, NULL
, CREATE_NEW
, 0, NULL
);
2343 if (hFile
!= INVALID_HANDLE_VALUE
)
2354 /***********************************************************************
2355 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2357 * The bug we are compensating for is that some drongo at Microsoft
2358 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2359 * As a consequence, CommitUrlCacheEntryA has been effectively
2360 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2361 * is still defined as LPCWSTR. The result (other than madness) is
2362 * that we always need to store lpHeaderInfo in CP_ACP rather than
2363 * in UTF16, and we need to avoid converting lpHeaderInfo in
2364 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2365 * result will lose data for arbitrary binary data.
2368 static BOOL
CommitUrlCacheEntryInternal(
2369 IN LPCWSTR lpszUrlName
,
2370 IN LPCWSTR lpszLocalFileName
,
2371 IN FILETIME ExpireTime
,
2372 IN FILETIME LastModifiedTime
,
2373 IN DWORD CacheEntryType
,
2374 IN LPBYTE lpHeaderInfo
,
2375 IN DWORD dwHeaderSize
,
2376 IN LPCWSTR lpszFileExtension
,
2377 IN LPCWSTR lpszOriginalUrl
2380 URLCACHECONTAINER
* pContainer
;
2381 LPURLCACHE_HEADER pHeader
;
2382 struct _HASH_ENTRY
* pHashEntry
;
2383 CACHEFILE_ENTRY
* pEntry
;
2384 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2385 DWORD dwBytesNeeded
= DWORD_ALIGN(sizeof(*pUrlEntry
));
2386 DWORD dwOffsetLocalFileName
= 0;
2387 DWORD dwOffsetHeader
= 0;
2388 DWORD dwOffsetFileExtension
= 0;
2389 DWORD dwFileSizeLow
= 0;
2390 DWORD dwFileSizeHigh
= 0;
2391 BYTE cDirectory
= 0;
2393 char achFile
[MAX_PATH
];
2394 LPSTR lpszUrlNameA
= NULL
;
2395 LPSTR lpszFileExtensionA
= NULL
;
2396 char *pchLocalFileName
= 0;
2399 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2400 debugstr_w(lpszUrlName
),
2401 debugstr_w(lpszLocalFileName
),
2405 debugstr_w(lpszFileExtension
),
2406 debugstr_w(lpszOriginalUrl
));
2408 if (lpszOriginalUrl
)
2409 WARN(": lpszOriginalUrl ignored\n");
2411 if (lpszLocalFileName
)
2415 hFile
= CreateFileW(lpszLocalFileName
, FILE_READ_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2416 if (hFile
== INVALID_HANDLE_VALUE
)
2418 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName
), GetLastError());
2423 dwFileSizeLow
= GetFileSize(hFile
, &dwFileSizeHigh
);
2424 if ((dwFileSizeLow
== INVALID_FILE_SIZE
) && (GetLastError() != NO_ERROR
))
2426 ERR("couldn't get file size (error is %d)\n", GetLastError());
2434 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2435 if (error
!= ERROR_SUCCESS
)
2437 SetLastError(error
);
2441 error
= URLCacheContainer_OpenIndex(pContainer
);
2442 if (error
!= ERROR_SUCCESS
)
2444 SetLastError(error
);
2448 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2451 len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, NULL
, 0, NULL
, NULL
);
2452 lpszUrlNameA
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(char));
2455 error
= GetLastError();
2458 WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, lpszUrlNameA
, len
, NULL
, NULL
);
2460 if (lpszFileExtension
)
2462 len
= WideCharToMultiByte(CP_ACP
, 0, lpszFileExtension
, -1, NULL
, 0, NULL
, NULL
);
2463 lpszFileExtensionA
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(char));
2464 if (!lpszFileExtensionA
)
2466 error
= GetLastError();
2469 WideCharToMultiByte(CP_ACP
, 0, lpszFileExtension
, -1, lpszFileExtensionA
, len
, NULL
, NULL
);
2472 if (URLCache_FindHash(pHeader
, lpszUrlNameA
, &pHashEntry
))
2474 FIXME("entry already in cache - don't know what to do!\n");
2476 * SetLastError(ERROR_FILE_NOT_FOUND);
2482 if (lpszLocalFileName
)
2484 BOOL bFound
= FALSE
;
2486 if (strncmpW(lpszLocalFileName
, pContainer
->path
, lstrlenW(pContainer
->path
)))
2488 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName
), debugstr_w(pContainer
->path
));
2489 error
= ERROR_INVALID_PARAMETER
;
2493 /* skip container path prefix */
2494 lpszLocalFileName
+= lstrlenW(pContainer
->path
);
2496 WideCharToMultiByte(CP_ACP
, 0, lpszLocalFileName
, -1, achFile
, MAX_PATH
, NULL
, NULL
);
2497 pchLocalFileName
= achFile
;
2499 for (cDirectory
= 0; cDirectory
< pHeader
->DirectoryCount
; cDirectory
++)
2501 if (!strncmp(pHeader
->directory_data
[cDirectory
].filename
, pchLocalFileName
, DIR_LENGTH
))
2510 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName
));
2511 error
= ERROR_INVALID_PARAMETER
;
2515 lpszLocalFileName
+= (DIR_LENGTH
+ 1); /* "1234WXYZ\" */
2518 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(lpszUrlNameA
) + 1);
2519 if (lpszLocalFileName
)
2521 len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, NULL
, 0, NULL
, NULL
);
2522 dwOffsetLocalFileName
= dwBytesNeeded
;
2523 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(pchLocalFileName
) + 1);
2527 dwOffsetHeader
= dwBytesNeeded
;
2528 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ dwHeaderSize
);
2530 if (lpszFileExtensionA
)
2532 dwOffsetFileExtension
= dwBytesNeeded
;
2533 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(lpszFileExtensionA
) + 1);
2536 /* round up to next block */
2537 if (dwBytesNeeded
% BLOCKSIZE
)
2539 dwBytesNeeded
-= dwBytesNeeded
% BLOCKSIZE
;
2540 dwBytesNeeded
+= BLOCKSIZE
;
2543 if (!URLCache_FindFirstFreeEntry(pHeader
, dwBytesNeeded
/ BLOCKSIZE
, &pEntry
))
2545 ERR("no free entries\n");
2546 error
= ERROR_DISK_FULL
;
2550 /* FindFirstFreeEntry fills in blocks used */
2551 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2552 pUrlEntry
->CacheFileEntry
.dwSignature
= URL_SIGNATURE
;
2553 pUrlEntry
->CacheDir
= cDirectory
;
2554 pUrlEntry
->CacheEntryType
= CacheEntryType
;
2555 pUrlEntry
->dwHeaderInfoSize
= dwHeaderSize
;
2556 pUrlEntry
->dwExemptDelta
= 0;
2557 pUrlEntry
->dwHitRate
= 0;
2558 pUrlEntry
->dwOffsetFileExtension
= dwOffsetFileExtension
;
2559 pUrlEntry
->dwOffsetHeaderInfo
= dwOffsetHeader
;
2560 pUrlEntry
->dwOffsetLocalName
= dwOffsetLocalFileName
;
2561 pUrlEntry
->dwOffsetUrl
= DWORD_ALIGN(sizeof(*pUrlEntry
));
2562 pUrlEntry
->dwSizeHigh
= 0;
2563 pUrlEntry
->dwSizeLow
= dwFileSizeLow
;
2564 pUrlEntry
->dwSizeHigh
= dwFileSizeHigh
;
2565 pUrlEntry
->dwUseCount
= 0;
2566 GetSystemTimeAsFileTime(&pUrlEntry
->LastAccessTime
);
2567 pUrlEntry
->LastModifiedTime
= LastModifiedTime
;
2568 FileTimeToDosDateTime(&pUrlEntry
->LastAccessTime
, &pUrlEntry
->wLastSyncDate
, &pUrlEntry
->wLastSyncTime
);
2569 FileTimeToDosDateTime(&ExpireTime
, &pUrlEntry
->wExpiredDate
, &pUrlEntry
->wExpiredTime
);
2570 pUrlEntry
->wUnknownDate
= pUrlEntry
->wLastSyncDate
;
2571 pUrlEntry
->wUnknownTime
= pUrlEntry
->wLastSyncTime
;
2574 pUrlEntry
->dwUnknown1
= 0;
2575 pUrlEntry
->dwUnknown2
= 0;
2576 pUrlEntry
->dwUnknown3
= 0x60;
2577 pUrlEntry
->Unknown4
= 0;
2578 pUrlEntry
->wUnknown5
= 0x1010;
2579 pUrlEntry
->dwUnknown7
= 0;
2580 pUrlEntry
->dwUnknown8
= 0;
2583 strcpy((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, lpszUrlNameA
);
2584 if (dwOffsetLocalFileName
)
2585 strcpy((LPSTR
)((LPBYTE
)pUrlEntry
+ dwOffsetLocalFileName
), pchLocalFileName
+ DIR_LENGTH
+ 1);
2587 memcpy((LPBYTE
)pUrlEntry
+ dwOffsetHeader
, lpHeaderInfo
, dwHeaderSize
);
2588 if (dwOffsetFileExtension
)
2589 strcpy((LPSTR
)((LPBYTE
)pUrlEntry
+ dwOffsetFileExtension
), lpszFileExtensionA
);
2591 error
= URLCache_AddEntryToHash(pHeader
, lpszUrlNameA
,
2592 (DWORD
)((LPBYTE
)pUrlEntry
- (LPBYTE
)pHeader
));
2593 if (error
!= ERROR_SUCCESS
)
2594 URLCache_DeleteEntry(pHeader
, &pUrlEntry
->CacheFileEntry
);
2597 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2598 HeapFree(GetProcessHeap(), 0, lpszUrlNameA
);
2599 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA
);
2601 if (error
== ERROR_SUCCESS
)
2605 SetLastError(error
);
2610 /***********************************************************************
2611 * CommitUrlCacheEntryA (WININET.@)
2614 BOOL WINAPI
CommitUrlCacheEntryA(
2615 IN LPCSTR lpszUrlName
,
2616 IN LPCSTR lpszLocalFileName
,
2617 IN FILETIME ExpireTime
,
2618 IN FILETIME LastModifiedTime
,
2619 IN DWORD CacheEntryType
,
2620 IN LPBYTE lpHeaderInfo
,
2621 IN DWORD dwHeaderSize
,
2622 IN LPCSTR lpszFileExtension
,
2623 IN LPCSTR lpszOriginalUrl
2627 WCHAR
*url_name
= NULL
;
2628 WCHAR
*local_file_name
= NULL
;
2629 WCHAR
*original_url
= NULL
;
2630 WCHAR
*file_extension
= NULL
;
2631 BOOL bSuccess
= FALSE
;
2633 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2634 debugstr_a(lpszUrlName
),
2635 debugstr_a(lpszLocalFileName
),
2639 debugstr_a(lpszFileExtension
),
2640 debugstr_a(lpszOriginalUrl
));
2642 len
= MultiByteToWideChar(CP_ACP
, 0, lpszUrlName
, -1, NULL
, 0);
2643 url_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2646 MultiByteToWideChar(CP_ACP
, 0, lpszUrlName
, -1, url_name
, len
);
2648 if (lpszLocalFileName
)
2650 len
= MultiByteToWideChar(CP_ACP
, 0, lpszLocalFileName
, -1, NULL
, 0);
2651 local_file_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2652 if (!local_file_name
)
2654 MultiByteToWideChar(CP_ACP
, 0, lpszLocalFileName
, -1, local_file_name
, len
);
2656 if (lpszFileExtension
)
2658 len
= MultiByteToWideChar(CP_ACP
, 0, lpszFileExtension
, -1, NULL
, 0);
2659 file_extension
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2660 if (!file_extension
)
2662 MultiByteToWideChar(CP_ACP
, 0, lpszFileExtension
, -1, file_extension
, len
);
2664 if (lpszOriginalUrl
)
2666 len
= MultiByteToWideChar(CP_ACP
, 0, lpszOriginalUrl
, -1, NULL
, 0);
2667 original_url
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2670 MultiByteToWideChar(CP_ACP
, 0, lpszOriginalUrl
, -1, original_url
, len
);
2673 bSuccess
= CommitUrlCacheEntryInternal(url_name
, local_file_name
, ExpireTime
, LastModifiedTime
,
2674 CacheEntryType
, lpHeaderInfo
, dwHeaderSize
,
2675 file_extension
, original_url
);
2678 HeapFree(GetProcessHeap(), 0, original_url
);
2679 HeapFree(GetProcessHeap(), 0, file_extension
);
2680 HeapFree(GetProcessHeap(), 0, local_file_name
);
2681 HeapFree(GetProcessHeap(), 0, url_name
);
2686 /***********************************************************************
2687 * CommitUrlCacheEntryW (WININET.@)
2690 BOOL WINAPI
CommitUrlCacheEntryW(
2691 IN LPCWSTR lpszUrlName
,
2692 IN LPCWSTR lpszLocalFileName
,
2693 IN FILETIME ExpireTime
,
2694 IN FILETIME LastModifiedTime
,
2695 IN DWORD CacheEntryType
,
2696 IN LPWSTR lpHeaderInfo
,
2697 IN DWORD dwHeaderSize
,
2698 IN LPCWSTR lpszFileExtension
,
2699 IN LPCWSTR lpszOriginalUrl
2703 BOOL bSuccess
= FALSE
;
2705 CHAR
*header_info
= NULL
;
2707 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2708 debugstr_w(lpszUrlName
),
2709 debugstr_w(lpszLocalFileName
),
2713 debugstr_w(lpszFileExtension
),
2714 debugstr_w(lpszOriginalUrl
));
2716 if (!lpHeaderInfo
||
2717 ((len
= WideCharToMultiByte(CP_ACP
, 0, lpHeaderInfo
, -1, NULL
, 0, NULL
, NULL
)) != 0 &&
2718 (header_info
= HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR
) * len
)) != 0))
2721 WideCharToMultiByte(CP_ACP
, 0, lpHeaderInfo
, -1, header_info
, len
, NULL
, NULL
);
2722 if (CommitUrlCacheEntryInternal(lpszUrlName
, lpszLocalFileName
, ExpireTime
, LastModifiedTime
,
2723 CacheEntryType
, (LPBYTE
)header_info
, len
, lpszFileExtension
, lpszOriginalUrl
))
2729 dwError
= GetLastError();
2733 HeapFree(GetProcessHeap(), 0, header_info
);
2735 SetLastError(dwError
);
2741 /***********************************************************************
2742 * ReadUrlCacheEntryStream (WININET.@)
2745 BOOL WINAPI
ReadUrlCacheEntryStream(
2746 IN HANDLE hUrlCacheStream
,
2747 IN DWORD dwLocation
,
2748 IN OUT LPVOID lpBuffer
,
2749 IN OUT LPDWORD lpdwLen
,
2753 /* Get handle to file from 'stream' */
2754 STREAM_HANDLE
* pStream
= (STREAM_HANDLE
*)hUrlCacheStream
;
2756 if (dwReserved
!= 0)
2758 ERR("dwReserved != 0\n");
2759 SetLastError(ERROR_INVALID_PARAMETER
);
2763 if (IsBadReadPtr(pStream
, sizeof(*pStream
)) || IsBadStringPtrA(pStream
->lpszUrl
, INTERNET_MAX_URL_LENGTH
))
2765 SetLastError(ERROR_INVALID_HANDLE
);
2769 if (SetFilePointer(pStream
->hFile
, dwLocation
, NULL
, FILE_CURRENT
) == INVALID_SET_FILE_POINTER
)
2771 return ReadFile(pStream
->hFile
, lpBuffer
, *lpdwLen
, lpdwLen
, NULL
);
2774 /***********************************************************************
2775 * RetrieveUrlCacheEntryStreamA (WININET.@)
2778 HANDLE WINAPI
RetrieveUrlCacheEntryStreamA(
2779 IN LPCSTR lpszUrlName
,
2780 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
2781 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
2782 IN BOOL fRandomRead
,
2786 /* NOTE: this is not the same as the way that the native
2787 * version allocates 'stream' handles. I did it this way
2788 * as it is much easier and no applications should depend
2789 * on this behaviour. (Native version appears to allocate
2790 * indices into a table)
2792 STREAM_HANDLE
* pStream
;
2795 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
,
2796 lpdwCacheEntryInfoBufferSize
, fRandomRead
, dwReserved
);
2798 if (!RetrieveUrlCacheEntryFileA(lpszUrlName
,
2800 lpdwCacheEntryInfoBufferSize
,
2806 hFile
= CreateFileA(lpCacheEntryInfo
->lpszLocalFileName
,
2811 fRandomRead
? FILE_FLAG_RANDOM_ACCESS
: 0,
2813 if (hFile
== INVALID_HANDLE_VALUE
)
2816 /* allocate handle storage space */
2817 pStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE
) + strlen(lpszUrlName
) * sizeof(CHAR
));
2821 SetLastError(ERROR_OUTOFMEMORY
);
2825 pStream
->hFile
= hFile
;
2826 strcpy(pStream
->lpszUrl
, lpszUrlName
);
2830 /***********************************************************************
2831 * RetrieveUrlCacheEntryStreamW (WININET.@)
2834 HANDLE WINAPI
RetrieveUrlCacheEntryStreamW(
2835 IN LPCWSTR lpszUrlName
,
2836 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
2837 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
2838 IN BOOL fRandomRead
,
2842 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName
), lpCacheEntryInfo
,
2843 lpdwCacheEntryInfoBufferSize
, fRandomRead
, dwReserved
);
2847 /***********************************************************************
2848 * UnlockUrlCacheEntryStream (WININET.@)
2851 BOOL WINAPI
UnlockUrlCacheEntryStream(
2852 IN HANDLE hUrlCacheStream
,
2856 STREAM_HANDLE
* pStream
= (STREAM_HANDLE
*)hUrlCacheStream
;
2858 if (dwReserved
!= 0)
2860 ERR("dwReserved != 0\n");
2861 SetLastError(ERROR_INVALID_PARAMETER
);
2865 if (IsBadReadPtr(pStream
, sizeof(*pStream
)) || IsBadStringPtrA(pStream
->lpszUrl
, INTERNET_MAX_URL_LENGTH
))
2867 SetLastError(ERROR_INVALID_HANDLE
);
2871 if (!UnlockUrlCacheEntryFileA(pStream
->lpszUrl
, 0))
2874 /* close file handle */
2875 CloseHandle(pStream
->hFile
);
2877 /* free allocated space */
2878 HeapFree(GetProcessHeap(), 0, pStream
);
2884 /***********************************************************************
2885 * DeleteUrlCacheEntryA (WININET.@)
2888 BOOL WINAPI
DeleteUrlCacheEntryA(LPCSTR lpszUrlName
)
2890 URLCACHECONTAINER
* pContainer
;
2891 LPURLCACHE_HEADER pHeader
;
2892 struct _HASH_ENTRY
* pHashEntry
;
2893 CACHEFILE_ENTRY
* pEntry
;
2896 TRACE("(%s)\n", debugstr_a(lpszUrlName
));
2898 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
2899 if (error
!= ERROR_SUCCESS
)
2901 SetLastError(error
);
2905 error
= URLCacheContainer_OpenIndex(pContainer
);
2906 if (error
!= ERROR_SUCCESS
)
2908 SetLastError(error
);
2912 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2915 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
2917 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2918 TRACE("entry %s not found!\n", lpszUrlName
);
2919 SetLastError(ERROR_FILE_NOT_FOUND
);
2923 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2924 URLCache_DeleteEntry(pHeader
, pEntry
);
2926 URLCache_DeleteEntryFromHash(pHashEntry
);
2928 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2933 /***********************************************************************
2934 * DeleteUrlCacheEntryW (WININET.@)
2937 BOOL WINAPI
DeleteUrlCacheEntryW(LPCWSTR lpszUrlName
)
2939 URLCACHECONTAINER
* pContainer
;
2940 LPURLCACHE_HEADER pHeader
;
2941 struct _HASH_ENTRY
* pHashEntry
;
2942 CACHEFILE_ENTRY
* pEntry
;
2947 TRACE("(%s)\n", debugstr_w(lpszUrlName
));
2949 url_len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, NULL
, 0, NULL
, NULL
);
2950 urlA
= HeapAlloc(GetProcessHeap(), 0, url_len
* sizeof(CHAR
));
2953 SetLastError(ERROR_OUTOFMEMORY
);
2956 WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, urlA
, url_len
, NULL
, NULL
);
2958 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2959 if (error
!= ERROR_SUCCESS
)
2961 HeapFree(GetProcessHeap(), 0, urlA
);
2962 SetLastError(error
);
2966 error
= URLCacheContainer_OpenIndex(pContainer
);
2967 if (error
!= ERROR_SUCCESS
)
2969 HeapFree(GetProcessHeap(), 0, urlA
);
2970 SetLastError(error
);
2974 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2976 HeapFree(GetProcessHeap(), 0, urlA
);
2980 if (!URLCache_FindHash(pHeader
, urlA
, &pHashEntry
))
2982 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2983 TRACE("entry %s not found!\n", debugstr_a(urlA
));
2984 HeapFree(GetProcessHeap(), 0, urlA
);
2985 SetLastError(ERROR_FILE_NOT_FOUND
);
2989 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2990 URLCache_DeleteEntry(pHeader
, pEntry
);
2992 URLCache_DeleteEntryFromHash(pHashEntry
);
2994 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2996 HeapFree(GetProcessHeap(), 0, urlA
);
3000 BOOL WINAPI
DeleteUrlCacheContainerA(DWORD d1
, DWORD d2
)
3002 FIXME("(0x%08x, 0x%08x) stub\n", d1
, d2
);
3006 BOOL WINAPI
DeleteUrlCacheContainerW(DWORD d1
, DWORD d2
)
3008 FIXME("(0x%08x, 0x%08x) stub\n", d1
, d2
);
3012 /***********************************************************************
3013 * CreateCacheContainerA (WININET.@)
3015 BOOL WINAPI
CreateUrlCacheContainerA(DWORD d1
, DWORD d2
, DWORD d3
, DWORD d4
,
3016 DWORD d5
, DWORD d6
, DWORD d7
, DWORD d8
)
3018 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3019 d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
);
3023 /***********************************************************************
3024 * CreateCacheContainerW (WININET.@)
3026 BOOL WINAPI
CreateUrlCacheContainerW(DWORD d1
, DWORD d2
, DWORD d3
, DWORD d4
,
3027 DWORD d5
, DWORD d6
, DWORD d7
, DWORD d8
)
3029 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3030 d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
);
3034 /***********************************************************************
3035 * FindFirstUrlCacheContainerA (WININET.@)
3037 HANDLE WINAPI
FindFirstUrlCacheContainerA( LPVOID p1
, LPVOID p2
, LPVOID p3
, DWORD d1
)
3039 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1
, p2
, p3
, d1
);
3043 /***********************************************************************
3044 * FindFirstUrlCacheContainerW (WININET.@)
3046 HANDLE WINAPI
FindFirstUrlCacheContainerW( LPVOID p1
, LPVOID p2
, LPVOID p3
, DWORD d1
)
3048 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1
, p2
, p3
, d1
);
3052 /***********************************************************************
3053 * FindNextUrlCacheContainerA (WININET.@)
3055 BOOL WINAPI
FindNextUrlCacheContainerA( HANDLE handle
, LPVOID p1
, LPVOID p2
)
3057 FIXME("(%p, %p, %p) stub\n", handle
, p1
, p2
);
3061 /***********************************************************************
3062 * FindNextUrlCacheContainerW (WININET.@)
3064 BOOL WINAPI
FindNextUrlCacheContainerW( HANDLE handle
, LPVOID p1
, LPVOID p2
)
3066 FIXME("(%p, %p, %p) stub\n", handle
, p1
, p2
);
3070 HANDLE WINAPI
FindFirstUrlCacheEntryExA(
3071 LPCSTR lpszUrlSearchPattern
,
3075 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
,
3076 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3078 LPDWORD pcbReserved2
,
3082 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern
),
3083 dwFlags
, dwFilter
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, lpFirstCacheEntryInfo
,
3084 lpdwFirstCacheEntryInfoBufferSize
, lpReserved
, pcbReserved2
,lpReserved3
);
3085 SetLastError(ERROR_FILE_NOT_FOUND
);
3089 HANDLE WINAPI
FindFirstUrlCacheEntryExW(
3090 LPCWSTR lpszUrlSearchPattern
,
3094 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
,
3095 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3097 LPDWORD pcbReserved2
,
3101 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern
),
3102 dwFlags
, dwFilter
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, lpFirstCacheEntryInfo
,
3103 lpdwFirstCacheEntryInfoBufferSize
, lpReserved
, pcbReserved2
,lpReserved3
);
3104 SetLastError(ERROR_FILE_NOT_FOUND
);
3108 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3110 typedef struct URLCacheFindEntryHandle
3113 LPWSTR lpszUrlSearchPattern
;
3114 DWORD dwContainerIndex
;
3115 DWORD dwHashTableIndex
;
3116 DWORD dwHashEntryIndex
;
3117 } URLCacheFindEntryHandle
;
3119 /***********************************************************************
3120 * FindFirstUrlCacheEntryA (WININET.@)
3123 INTERNETAPI HANDLE WINAPI
FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern
,
3124 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
, LPDWORD lpdwFirstCacheEntryInfoBufferSize
)
3126 URLCacheFindEntryHandle
*pEntryHandle
;
3128 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern
), lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
);
3130 pEntryHandle
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle
));
3134 pEntryHandle
->dwMagic
= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
;
3135 if (lpszUrlSearchPattern
)
3137 int len
= MultiByteToWideChar(CP_ACP
, 0, lpszUrlSearchPattern
, -1, NULL
, 0);
3138 pEntryHandle
->lpszUrlSearchPattern
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3139 if (!pEntryHandle
->lpszUrlSearchPattern
)
3141 HeapFree(GetProcessHeap(), 0, pEntryHandle
);
3144 MultiByteToWideChar(CP_ACP
, 0, lpszUrlSearchPattern
, -1, pEntryHandle
->lpszUrlSearchPattern
, len
);
3147 pEntryHandle
->lpszUrlSearchPattern
= NULL
;
3148 pEntryHandle
->dwContainerIndex
= 0;
3149 pEntryHandle
->dwHashTableIndex
= 0;
3150 pEntryHandle
->dwHashEntryIndex
= 0;
3152 if (!FindNextUrlCacheEntryA(pEntryHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
))
3154 HeapFree(GetProcessHeap(), 0, pEntryHandle
);
3157 return pEntryHandle
;
3160 /***********************************************************************
3161 * FindFirstUrlCacheEntryW (WININET.@)
3164 INTERNETAPI HANDLE WINAPI
FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern
,
3165 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
, LPDWORD lpdwFirstCacheEntryInfoBufferSize
)
3167 URLCacheFindEntryHandle
*pEntryHandle
;
3169 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern
), lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
);
3171 pEntryHandle
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle
));
3175 pEntryHandle
->dwMagic
= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
;
3176 if (lpszUrlSearchPattern
)
3178 int len
= strlenW(lpszUrlSearchPattern
);
3179 pEntryHandle
->lpszUrlSearchPattern
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
3180 if (!pEntryHandle
->lpszUrlSearchPattern
)
3182 HeapFree(GetProcessHeap(), 0, pEntryHandle
);
3185 memcpy(pEntryHandle
->lpszUrlSearchPattern
, lpszUrlSearchPattern
, (len
+ 1) * sizeof(WCHAR
));
3188 pEntryHandle
->lpszUrlSearchPattern
= NULL
;
3189 pEntryHandle
->dwContainerIndex
= 0;
3190 pEntryHandle
->dwHashTableIndex
= 0;
3191 pEntryHandle
->dwHashEntryIndex
= 0;
3193 if (!FindNextUrlCacheEntryW(pEntryHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
))
3195 HeapFree(GetProcessHeap(), 0, pEntryHandle
);
3198 return pEntryHandle
;
3201 /***********************************************************************
3202 * FindNextUrlCacheEntryA (WININET.@)
3204 BOOL WINAPI
FindNextUrlCacheEntryA(
3206 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo
,
3207 LPDWORD lpdwNextCacheEntryInfoBufferSize
)
3209 URLCacheFindEntryHandle
*pEntryHandle
= (URLCacheFindEntryHandle
*)hEnumHandle
;
3210 URLCACHECONTAINER
* pContainer
;
3212 TRACE("(%p, %p, %p)\n", hEnumHandle
, lpNextCacheEntryInfo
, lpdwNextCacheEntryInfoBufferSize
);
3214 if (pEntryHandle
->dwMagic
!= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
)
3216 SetLastError(ERROR_INVALID_HANDLE
);
3220 for (; URLCacheContainers_Enum(pEntryHandle
->lpszUrlSearchPattern
, pEntryHandle
->dwContainerIndex
, &pContainer
);
3221 pEntryHandle
->dwContainerIndex
++, pEntryHandle
->dwHashTableIndex
= 0)
3223 LPURLCACHE_HEADER pHeader
;
3224 HASH_CACHEFILE_ENTRY
*pHashTableEntry
;
3227 error
= URLCacheContainer_OpenIndex(pContainer
);
3228 if (error
!= ERROR_SUCCESS
)
3230 SetLastError(error
);
3234 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3237 for (; URLCache_EnumHashTables(pHeader
, &pEntryHandle
->dwHashTableIndex
, &pHashTableEntry
);
3238 pEntryHandle
->dwHashTableIndex
++, pEntryHandle
->dwHashEntryIndex
= 0)
3240 const struct _HASH_ENTRY
*pHashEntry
= NULL
;
3241 for (; URLCache_EnumHashTableEntries(pHeader
, pHashTableEntry
, &pEntryHandle
->dwHashEntryIndex
, &pHashEntry
);
3242 pEntryHandle
->dwHashEntryIndex
++)
3244 const URL_CACHEFILE_ENTRY
*pUrlEntry
;
3245 const CACHEFILE_ENTRY
*pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3247 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
3250 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
3251 TRACE("Found URL: %s\n", (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
3252 TRACE("Header info: %s\n", (LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
);
3254 error
= URLCache_CopyEntry(
3257 lpNextCacheEntryInfo
,
3258 lpdwNextCacheEntryInfoBufferSize
,
3260 FALSE
/* not UNICODE */);
3261 if (error
!= ERROR_SUCCESS
)
3263 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3264 SetLastError(error
);
3267 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
3269 /* increment the current index so that next time the function
3270 * is called the next entry is returned */
3271 pEntryHandle
->dwHashEntryIndex
++;
3272 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3277 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3280 SetLastError(ERROR_NO_MORE_ITEMS
);
3284 /***********************************************************************
3285 * FindNextUrlCacheEntryW (WININET.@)
3287 BOOL WINAPI
FindNextUrlCacheEntryW(
3289 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo
,
3290 LPDWORD lpdwNextCacheEntryInfoBufferSize
3293 FIXME("(%p, %p, %p) stub\n", hEnumHandle
, lpNextCacheEntryInfo
, lpdwNextCacheEntryInfoBufferSize
);
3294 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3298 /***********************************************************************
3299 * FindCloseUrlCache (WININET.@)
3301 BOOL WINAPI
FindCloseUrlCache(HANDLE hEnumHandle
)
3303 URLCacheFindEntryHandle
*pEntryHandle
= (URLCacheFindEntryHandle
*)hEnumHandle
;
3305 TRACE("(%p)\n", hEnumHandle
);
3307 if (!pEntryHandle
|| pEntryHandle
->dwMagic
!= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
)
3309 SetLastError(ERROR_INVALID_HANDLE
);
3313 pEntryHandle
->dwMagic
= 0;
3314 HeapFree(GetProcessHeap(), 0, pEntryHandle
->lpszUrlSearchPattern
);
3315 HeapFree(GetProcessHeap(), 0, pEntryHandle
);
3320 HANDLE WINAPI
FindFirstUrlCacheGroup( DWORD dwFlags
, DWORD dwFilter
, LPVOID lpSearchCondition
,
3321 DWORD dwSearchCondition
, GROUPID
* lpGroupId
, LPVOID lpReserved
)
3323 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags
, dwFilter
, lpSearchCondition
,
3324 dwSearchCondition
, lpGroupId
, lpReserved
);
3328 BOOL WINAPI
FindNextUrlCacheEntryExA(
3330 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
,
3331 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3333 LPDWORD pcbReserved2
,
3337 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
,
3338 lpReserved
, pcbReserved2
, lpReserved3
);
3342 BOOL WINAPI
FindNextUrlCacheEntryExW(
3344 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
,
3345 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3347 LPDWORD pcbReserved2
,
3351 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
,
3352 lpReserved
, pcbReserved2
, lpReserved3
);
3356 BOOL WINAPI
FindNextUrlCacheGroup( HANDLE hFind
, GROUPID
* lpGroupId
, LPVOID lpReserved
)
3358 FIXME("(%p, %p, %p) stub\n", hFind
, lpGroupId
, lpReserved
);
3362 /***********************************************************************
3363 * CreateUrlCacheGroup (WININET.@)
3366 INTERNETAPI GROUPID WINAPI
CreateUrlCacheGroup(DWORD dwFlags
, LPVOID lpReserved
)
3368 FIXME("(0x%08x, %p): stub\n", dwFlags
, lpReserved
);
3372 /***********************************************************************
3373 * DeleteUrlCacheGroup (WININET.@)
3376 BOOL WINAPI
DeleteUrlCacheGroup(GROUPID GroupId
, DWORD dwFlags
, LPVOID lpReserved
)
3378 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3379 (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, dwFlags
, lpReserved
);
3383 /***********************************************************************
3384 * SetUrlCacheEntryGroupA (WININET.@)
3387 BOOL WINAPI
SetUrlCacheEntryGroupA(LPCSTR lpszUrlName
, DWORD dwFlags
,
3388 GROUPID GroupId
, LPBYTE pbGroupAttributes
, DWORD cbGroupAttributes
,
3391 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3392 debugstr_a(lpszUrlName
), dwFlags
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
,
3393 pbGroupAttributes
, cbGroupAttributes
, lpReserved
);
3394 SetLastError(ERROR_FILE_NOT_FOUND
);
3398 /***********************************************************************
3399 * SetUrlCacheEntryGroupW (WININET.@)
3402 BOOL WINAPI
SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName
, DWORD dwFlags
,
3403 GROUPID GroupId
, LPBYTE pbGroupAttributes
, DWORD cbGroupAttributes
,
3406 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3407 debugstr_w(lpszUrlName
), dwFlags
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
,
3408 pbGroupAttributes
, cbGroupAttributes
, lpReserved
);
3409 SetLastError(ERROR_FILE_NOT_FOUND
);
3413 /***********************************************************************
3414 * GetUrlCacheConfigInfoW (WININET.@)
3416 BOOL WINAPI
GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo
, LPDWORD size
, DWORD bitmask
)
3418 FIXME("(%p, %p, %x)\n", CacheInfo
, size
, bitmask
);
3419 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
3423 /***********************************************************************
3424 * GetUrlCacheConfigInfoA (WININET.@)
3426 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3428 BOOL WINAPI
GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo
, LPDWORD size
, DWORD bitmask
)
3430 FIXME("(%p, %p, %x)\n", CacheInfo
, size
, bitmask
);
3431 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
3435 BOOL WINAPI
GetUrlCacheGroupAttributeA( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3436 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo
,
3437 LPDWORD lpdwGroupInfo
, LPVOID lpReserved
)
3439 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3440 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
,
3441 lpdwGroupInfo
, lpReserved
);
3445 BOOL WINAPI
GetUrlCacheGroupAttributeW( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3446 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo
,
3447 LPDWORD lpdwGroupInfo
, LPVOID lpReserved
)
3449 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3450 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
,
3451 lpdwGroupInfo
, lpReserved
);
3455 BOOL WINAPI
SetUrlCacheGroupAttributeA( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3456 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo
, LPVOID lpReserved
)
3458 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3459 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
, lpReserved
);
3463 BOOL WINAPI
SetUrlCacheGroupAttributeW( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3464 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo
, LPVOID lpReserved
)
3466 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3467 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
, lpReserved
);
3471 BOOL WINAPI
SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo
, DWORD dwFieldControl
)
3473 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo
, dwFieldControl
);
3477 BOOL WINAPI
SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo
, DWORD dwFieldControl
)
3479 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo
, dwFieldControl
);
3483 /***********************************************************************
3484 * DeleteIE3Cache (WININET.@)
3486 * Deletes the files used by the IE3 URL caching system.
3489 * hWnd [I] A dummy window.
3490 * hInst [I] Instance of process calling the function.
3491 * lpszCmdLine [I] Options used by function.
3492 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3494 DWORD WINAPI
DeleteIE3Cache(HWND hWnd
, HINSTANCE hInst
, LPSTR lpszCmdLine
, int nCmdShow
)
3496 FIXME("(%p, %p, %s, %d)\n", hWnd
, hInst
, debugstr_a(lpszCmdLine
), nCmdShow
);
3500 /***********************************************************************
3501 * IsUrlCacheEntryExpiredA (WININET.@)
3505 * dwFlags [I] Unknown
3506 * pftLastModified [O] Last modified time
3508 BOOL WINAPI
IsUrlCacheEntryExpiredA( LPCSTR url
, DWORD dwFlags
, FILETIME
* pftLastModified
)
3510 LPURLCACHE_HEADER pHeader
;
3511 struct _HASH_ENTRY
* pHashEntry
;
3512 const CACHEFILE_ENTRY
* pEntry
;
3513 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
3514 URLCACHECONTAINER
* pContainer
;
3517 TRACE("(%s, %08x, %p)\n", debugstr_a(url
), dwFlags
, pftLastModified
);
3519 error
= URLCacheContainers_FindContainerA(url
, &pContainer
);
3520 if (error
!= ERROR_SUCCESS
)
3522 SetLastError(error
);
3526 error
= URLCacheContainer_OpenIndex(pContainer
);
3527 if (error
!= ERROR_SUCCESS
)
3529 SetLastError(error
);
3533 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3536 if (!URLCache_FindHash(pHeader
, url
, &pHashEntry
))
3538 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3539 TRACE("entry %s not found!\n", url
);
3540 SetLastError(ERROR_FILE_NOT_FOUND
);
3544 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3545 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
3547 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3548 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
3549 SetLastError(ERROR_FILE_NOT_FOUND
);
3553 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
3555 DosDateTimeToFileTime(pUrlEntry
->wExpiredDate
, pUrlEntry
->wExpiredTime
, pftLastModified
);
3557 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3562 /***********************************************************************
3563 * IsUrlCacheEntryExpiredW (WININET.@)
3567 * dwFlags [I] Unknown
3568 * pftLastModified [O] Last modified time
3570 BOOL WINAPI
IsUrlCacheEntryExpiredW( LPCWSTR url
, DWORD dwFlags
, FILETIME
* pftLastModified
)
3572 LPURLCACHE_HEADER pHeader
;
3573 struct _HASH_ENTRY
* pHashEntry
;
3574 const CACHEFILE_ENTRY
* pEntry
;
3575 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
3576 URLCACHECONTAINER
* pContainer
;
3579 TRACE("(%s, %08x, %p)\n", debugstr_w(url
), dwFlags
, pftLastModified
);
3581 error
= URLCacheContainers_FindContainerW(url
, &pContainer
);
3582 if (error
!= ERROR_SUCCESS
)
3584 SetLastError(error
);
3588 error
= URLCacheContainer_OpenIndex(pContainer
);
3589 if (error
!= ERROR_SUCCESS
)
3591 SetLastError(error
);
3595 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3598 if (!URLCache_FindHashW(pHeader
, url
, &pHashEntry
))
3600 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3601 TRACE("entry %s not found!\n", debugstr_w(url
));
3602 SetLastError(ERROR_FILE_NOT_FOUND
);
3606 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3607 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
3609 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3610 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
3611 SetLastError(ERROR_FILE_NOT_FOUND
);
3615 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
3617 DosDateTimeToFileTime(pUrlEntry
->wExpiredDate
, pUrlEntry
->wExpiredTime
, pftLastModified
);
3619 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3624 /***********************************************************************
3625 * GetDiskInfoA (WININET.@)
3627 DWORD WINAPI
GetDiskInfoA(void *p0
, void *p1
, void *p2
, void *p3
)
3629 FIXME("(%p, %p, %p, %p)\n", p0
, p1
, p2
, p3
);
3633 /***********************************************************************
3634 * RegisterUrlCacheNotification (WININET.@)
3636 DWORD WINAPI
RegisterUrlCacheNotification(LPVOID a
, DWORD b
, DWORD c
, DWORD d
, DWORD e
, DWORD f
)
3638 FIXME("(%p %x %x %x %x %x)\n", a
, b
, c
, d
, e
, f
);