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
25 #define WIN32_NO_STATUS
27 #define COM_NO_WINDOWS_H
30 //#include "wine/port.h"
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
39 //#include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
47 //#include "winuser.h"
50 //#include "winerror.h"
56 #if defined(__MINGW32__) || defined (_MSC_VER)
62 //#include "wine/unicode.h"
63 #include <wine/debug.h>
65 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
67 #define ENTRY_START_OFFSET 0x4000
70 #define HASHTABLE_SIZE 448
71 #define HASHTABLE_NUM_ENTRIES 64 /* this needs to be power of 2, that divides HASHTABLE_SIZE */
72 #define HASHTABLE_BLOCKSIZE (HASHTABLE_SIZE / HASHTABLE_NUM_ENTRIES)
73 #define ALLOCATION_TABLE_OFFSET 0x250
74 #define ALLOCATION_TABLE_SIZE (ENTRY_START_OFFSET - ALLOCATION_TABLE_OFFSET)
75 #define MIN_BLOCK_NO 0x80
76 #define MAX_BLOCK_NO (ALLOCATION_TABLE_SIZE * 8)
77 #define FILE_SIZE(blocks) ((blocks) * BLOCKSIZE + ENTRY_START_OFFSET)
79 #define HASHTABLE_URL 0
80 #define HASHTABLE_DEL 1
81 #define HASHTABLE_LOCK 2
82 #define HASHTABLE_FREE 3
83 #define HASHTABLE_REDR 5
84 #define HASHTABLE_FLAG_BITS 5
86 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
87 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
88 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
89 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
90 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
92 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
94 typedef struct _CACHEFILE_ENTRY
98 DWORD dwSignature
; /* e.g. "URL " */
99 /* CHAR szSignature[4];
101 DWORD dwBlocksUsed
; /* number of 128byte blocks used by this entry */
104 typedef struct _URL_CACHEFILE_ENTRY
106 CACHEFILE_ENTRY CacheFileEntry
;
107 FILETIME LastModifiedTime
;
108 FILETIME LastAccessTime
;
109 WORD wExpiredDate
; /* expire date in dos format */
110 WORD wExpiredTime
; /* expire time in dos format */
111 DWORD dwUnknown1
; /* usually zero */
112 ULARGE_INTEGER size
; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow/High */
113 DWORD dwUnknown2
; /* usually zero */
114 DWORD dwExemptDelta
; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
115 DWORD dwUnknown3
; /* usually 0x60 */
116 DWORD dwOffsetUrl
; /* offset of start of url from start of entry */
117 BYTE CacheDir
; /* index of cache directory this url is stored in */
118 BYTE Unknown4
; /* usually zero */
119 WORD wUnknown5
; /* usually 0x1010 */
120 DWORD dwOffsetLocalName
; /* offset of start of local filename from start of entry */
121 DWORD CacheEntryType
; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
122 DWORD dwOffsetHeaderInfo
; /* offset of start of header info from start of entry */
123 DWORD dwHeaderInfoSize
;
124 DWORD dwOffsetFileExtension
; /* offset of start of file extension from start of entry */
125 WORD wLastSyncDate
; /* last sync date in dos format */
126 WORD wLastSyncTime
; /* last sync time in dos format */
127 DWORD dwHitRate
; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
128 DWORD dwUseCount
; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
129 WORD wUnknownDate
; /* usually same as wLastSyncDate */
130 WORD wUnknownTime
; /* usually same as wLastSyncTime */
131 DWORD dwUnknown7
; /* usually zero */
132 DWORD dwUnknown8
; /* usually zero */
133 /* packing to dword align start of next field */
134 /* CHAR szSourceUrlName[]; (url) */
135 /* packing to dword align start of next field */
136 /* CHAR szLocalFileName[]; (local file name excluding path) */
137 /* packing to dword align start of next field */
138 /* CHAR szHeaderInfo[]; (header info) */
139 } URL_CACHEFILE_ENTRY
;
147 typedef struct _HASH_CACHEFILE_ENTRY
149 CACHEFILE_ENTRY CacheFileEntry
;
151 DWORD dwHashTableNumber
;
152 struct _HASH_ENTRY HashTable
[HASHTABLE_SIZE
];
153 } HASH_CACHEFILE_ENTRY
;
155 typedef struct _DIRECTORY_DATA
158 char filename
[DIR_LENGTH
];
161 typedef struct _URLCACHE_HEADER
163 char szSignature
[28];
165 DWORD dwOffsetFirstHashTable
;
166 DWORD dwIndexCapacityInBlocks
;
169 ULARGE_INTEGER CacheLimit
;
170 ULARGE_INTEGER CacheUsage
;
171 ULARGE_INTEGER ExemptUsage
;
172 DWORD DirectoryCount
; /* number of directory_data's */
173 DIRECTORY_DATA directory_data
[1]; /* first directory entry */
174 } URLCACHE_HEADER
, *LPURLCACHE_HEADER
;
175 typedef const URLCACHE_HEADER
*LPCURLCACHE_HEADER
;
177 typedef struct _STREAM_HANDLE
183 typedef struct _URLCACHECONTAINER
185 struct list entry
; /* part of a list */
186 LPWSTR cache_prefix
; /* string that has to be prefixed for this container to be used */
187 LPWSTR path
; /* path to url container directory */
188 HANDLE hMapping
; /* handle of file mapping */
189 DWORD file_size
; /* size of file when mapping was opened */
190 HANDLE hMutex
; /* handle of mutex */
194 /* List of all containers available */
195 static struct list UrlContainers
= LIST_INIT(UrlContainers
);
197 BOOL bDefaultContainersAdded
= FALSE
;
199 static DWORD
URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader
, HASH_CACHEFILE_ENTRY
*pPrevHash
, HASH_CACHEFILE_ENTRY
**ppHash
);
201 /***********************************************************************
202 * URLCache_PathToObjectName (Internal)
204 * Converts a path to a name suitable for use as a Win32 object name.
205 * Replaces '\\' characters in-place with the specified character
206 * (usually '_' or '!')
212 static void URLCache_PathToObjectName(LPWSTR lpszPath
, WCHAR replace
)
214 for (; *lpszPath
; lpszPath
++)
216 if (*lpszPath
== '\\')
221 /***********************************************************************
222 * URLCacheContainer_OpenIndex (Internal)
224 * Opens the index file and saves mapping handle in hCacheIndexMapping
227 * ERROR_SUCCESS if succeeded
228 * Any other Win32 error code if failed
231 static DWORD
URLCacheContainer_OpenIndex(URLCACHECONTAINER
* pContainer
, DWORD blocks_no
)
234 WCHAR wszFilePath
[MAX_PATH
];
235 DWORD dwFileSize
, new_file_size
;
237 static const WCHAR wszIndex
[] = {'i','n','d','e','x','.','d','a','t',0};
238 static const WCHAR wszMappingFormat
[] = {'%','s','%','s','_','%','l','u',0};
240 WaitForSingleObject(pContainer
->hMutex
, INFINITE
);
242 if (pContainer
->hMapping
) {
243 ReleaseMutex(pContainer
->hMutex
);
244 return ERROR_SUCCESS
;
247 strcpyW(wszFilePath
, pContainer
->path
);
248 strcatW(wszFilePath
, wszIndex
);
250 hFile
= CreateFileW(wszFilePath
, GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, 0, NULL
);
251 if (hFile
== INVALID_HANDLE_VALUE
)
253 /* Maybe the directory wasn't there? Try to create it */
254 if (CreateDirectoryW(pContainer
->path
, 0))
255 hFile
= CreateFileW(wszFilePath
, GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, 0, NULL
);
257 if (hFile
== INVALID_HANDLE_VALUE
)
259 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath
));
260 ReleaseMutex(pContainer
->hMutex
);
261 return GetLastError();
264 dwFileSize
= GetFileSize(hFile
, NULL
);
265 if (dwFileSize
== INVALID_FILE_SIZE
)
267 ReleaseMutex(pContainer
->hMutex
);
268 return GetLastError();
271 if (blocks_no
< MIN_BLOCK_NO
)
272 blocks_no
= MIN_BLOCK_NO
;
273 else if (blocks_no
> MAX_BLOCK_NO
)
274 blocks_no
= MAX_BLOCK_NO
;
275 new_file_size
= FILE_SIZE(blocks_no
);
277 if (dwFileSize
< new_file_size
)
279 static const CHAR szCacheContent
[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content";
281 char achZeroes
[0x1000];
283 DWORD dwError
= ERROR_SUCCESS
;
285 if (SetFilePointer(hFile
, 0, NULL
, FILE_END
) == INVALID_SET_FILE_POINTER
)
286 dwError
= GetLastError();
288 /* Write zeroes to the entire file so we can safely map it without
289 * fear of getting a SEGV because the disk is full.
291 memset(achZeroes
, 0, sizeof(achZeroes
));
292 for (dwOffset
= dwFileSize
; dwOffset
<new_file_size
&& dwError
==ERROR_SUCCESS
;
293 dwOffset
+= sizeof(achZeroes
))
295 DWORD dwWrite
= sizeof(achZeroes
);
298 if (new_file_size
- dwOffset
< dwWrite
)
299 dwWrite
= new_file_size
- dwOffset
;
300 if (!WriteFile(hFile
, achZeroes
, dwWrite
, &dwWritten
, 0) ||
301 dwWritten
!= dwWrite
)
303 /* If we fail to write, we need to return the error that
304 * cause the problem and also make sure the file is no
305 * longer there, if possible.
307 dwError
= GetLastError();
311 if (dwError
== ERROR_SUCCESS
)
313 HANDLE hMapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READWRITE
, 0, 0, NULL
);
317 URLCACHE_HEADER
*pHeader
= MapViewOfFile(hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
319 if (pHeader
&& dwFileSize
)
321 pHeader
->dwFileSize
= new_file_size
;
322 pHeader
->dwIndexCapacityInBlocks
= blocks_no
;
327 WCHAR wszDirPath
[MAX_PATH
];
330 HASH_CACHEFILE_ENTRY
*pHashEntry
;
332 /* First set some constants and defaults in the header */
333 strcpy(pHeader
->szSignature
, "WINE URLCache Ver 0.2005001");
334 pHeader
->dwFileSize
= new_file_size
;
335 pHeader
->dwIndexCapacityInBlocks
= blocks_no
;
336 /* 127MB - taken from default for Windows 2000 */
337 pHeader
->CacheLimit
.QuadPart
= 0x07ff5400;
338 /* Copied from a Windows 2000 cache index */
339 pHeader
->DirectoryCount
= 4;
341 /* If the registry has a cache size set, use the registry value */
342 if (RegOpenKeyA(HKEY_CURRENT_USER
, szCacheContent
, &key
) == ERROR_SUCCESS
)
345 DWORD len
= sizeof(dw
);
348 if (RegQueryValueExA(key
, "CacheLimit", NULL
, &keytype
,
349 (BYTE
*) &dw
, &len
) == ERROR_SUCCESS
&&
350 keytype
== REG_DWORD
)
352 pHeader
->CacheLimit
.QuadPart
= (ULONGLONG
)dw
* 1024;
357 URLCache_CreateHashTable(pHeader
, NULL
, &pHashEntry
);
359 /* Last step - create the directories */
361 strcpyW(wszDirPath
, pContainer
->path
);
362 pwchDir
= wszDirPath
+ strlenW(wszDirPath
);
365 GetSystemTimeAsFileTime(&ft
);
367 for (i
= 0; !dwError
&& i
< pHeader
->DirectoryCount
; ++i
)
369 pHeader
->directory_data
[i
].dwNumFiles
= 0;
373 ULONGLONG n
= ft
.dwHighDateTime
;
375 /* Generate a file name to attempt to create.
376 * This algorithm will create what will appear
377 * to be random and unrelated directory names
378 * of up to 9 characters in length.
381 n
+= ft
.dwLowDateTime
;
382 n
^= ((ULONGLONG
) i
<< 56) | ((ULONGLONG
) j
<< 48);
384 for (k
= 0; k
< 8; ++k
)
388 /* Dividing by a prime greater than 36 helps
389 * with the appearance of randomness
394 pwchDir
[k
] = '0' + r
;
396 pwchDir
[k
] = 'A' + (r
- 10);
399 if (CreateDirectoryW(wszDirPath
, 0))
401 /* The following is OK because we generated an
402 * 8 character directory name made from characters
403 * [A-Z0-9], which are equivalent for all code
404 * pages and for UTF-16
406 for (k
= 0; k
< 8; ++k
)
407 pHeader
->directory_data
[i
].filename
[k
] = pwchDir
[k
];
412 /* Give up. The most likely cause of this
413 * is a full disk, but whatever the cause
414 * is, it should be more than apparent that
417 dwError
= GetLastError();
423 UnmapViewOfFile(pHeader
);
427 dwError
= GetLastError();
429 dwFileSize
= new_file_size
;
430 CloseHandle(hMapping
);
434 dwError
= GetLastError();
441 DeleteFileW(wszFilePath
);
442 ReleaseMutex(pContainer
->hMutex
);
448 pContainer
->file_size
= dwFileSize
;
449 wsprintfW(wszFilePath
, wszMappingFormat
, pContainer
->path
, wszIndex
, dwFileSize
);
450 URLCache_PathToObjectName(wszFilePath
, '_');
451 pContainer
->hMapping
= OpenFileMappingW(FILE_MAP_WRITE
, FALSE
, wszFilePath
);
452 if (!pContainer
->hMapping
)
453 pContainer
->hMapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READWRITE
, 0, 0, wszFilePath
);
455 if (!pContainer
->hMapping
)
457 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
458 ReleaseMutex(pContainer
->hMutex
);
459 return GetLastError();
462 ReleaseMutex(pContainer
->hMutex
);
464 return ERROR_SUCCESS
;
467 /***********************************************************************
468 * URLCacheContainer_CloseIndex (Internal)
476 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER
* pContainer
)
478 CloseHandle(pContainer
->hMapping
);
479 pContainer
->hMapping
= NULL
;
482 static BOOL
URLCacheContainers_AddContainer(LPCWSTR cache_prefix
, LPCWSTR path
, LPWSTR mutex_name
)
484 URLCACHECONTAINER
* pContainer
= heap_alloc(sizeof(URLCACHECONTAINER
));
485 int cache_prefix_len
= strlenW(cache_prefix
);
492 pContainer
->hMapping
= NULL
;
493 pContainer
->file_size
= 0;
495 pContainer
->path
= heap_strdupW(path
);
496 if (!pContainer
->path
)
498 heap_free(pContainer
);
502 pContainer
->cache_prefix
= heap_alloc((cache_prefix_len
+ 1) * sizeof(WCHAR
));
503 if (!pContainer
->cache_prefix
)
505 heap_free(pContainer
->path
);
506 heap_free(pContainer
);
510 memcpy(pContainer
->cache_prefix
, cache_prefix
, (cache_prefix_len
+ 1) * sizeof(WCHAR
));
512 CharLowerW(mutex_name
);
513 URLCache_PathToObjectName(mutex_name
, '!');
515 if ((pContainer
->hMutex
= CreateMutexW(NULL
, FALSE
, mutex_name
)) == NULL
)
517 ERR("couldn't create mutex (error is %d)\n", GetLastError());
518 heap_free(pContainer
->path
);
519 heap_free(pContainer
);
523 list_add_head(&UrlContainers
, &pContainer
->entry
);
528 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER
* pContainer
)
530 list_remove(&pContainer
->entry
);
532 URLCacheContainer_CloseIndex(pContainer
);
533 CloseHandle(pContainer
->hMutex
);
534 heap_free(pContainer
->path
);
535 heap_free(pContainer
->cache_prefix
);
536 heap_free(pContainer
);
539 void URLCacheContainers_CreateDefaults(void)
541 static const WCHAR UrlSuffix
[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
542 static const WCHAR UrlPrefix
[] = {0};
543 static const WCHAR HistorySuffix
[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
544 static const WCHAR HistoryPrefix
[] = {'V','i','s','i','t','e','d',':',0};
545 static const WCHAR CookieSuffix
[] = {0};
546 static const WCHAR CookiePrefix
[] = {'C','o','o','k','i','e',':',0};
548 static const WCHAR UserProfile
[] = {'U','S','E','R','P','R','O','F','I','L','E',0};
551 int nFolder
; /* CSIDL_* constant */
552 const WCHAR
* shpath_suffix
; /* suffix on path returned by SHGetSpecialFolderPath */
553 const WCHAR
* cache_prefix
; /* prefix used to reference the container */
554 } DefaultContainerData
[] =
556 { CSIDL_INTERNET_CACHE
, UrlSuffix
, UrlPrefix
},
557 { CSIDL_HISTORY
, HistorySuffix
, HistoryPrefix
},
558 { CSIDL_COOKIES
, CookieSuffix
, CookiePrefix
},
563 if (GetEnvironmentVariableW(UserProfile
, NULL
, 0) == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND
)
565 TRACE("Environment variable 'USERPROFILE' does not exist!\n");
569 for (i
= 0; i
< sizeof(DefaultContainerData
) / sizeof(DefaultContainerData
[0]); i
++)
571 WCHAR wszCachePath
[MAX_PATH
];
572 WCHAR wszMutexName
[MAX_PATH
];
573 int path_len
, suffix_len
;
575 if (!SHGetSpecialFolderPathW(NULL
, wszCachePath
, DefaultContainerData
[i
].nFolder
, TRUE
))
577 ERR("Couldn't get path for default container %u\n", i
);
580 path_len
= strlenW(wszCachePath
);
581 suffix_len
= strlenW(DefaultContainerData
[i
].shpath_suffix
);
583 if (path_len
+ suffix_len
+ 2 > MAX_PATH
)
585 ERR("Path too long\n");
589 wszCachePath
[path_len
] = '\\';
590 wszCachePath
[path_len
+1] = 0;
592 strcpyW(wszMutexName
, wszCachePath
);
596 memcpy(wszCachePath
+ path_len
+ 1, DefaultContainerData
[i
].shpath_suffix
, (suffix_len
+ 1) * sizeof(WCHAR
));
597 wszCachePath
[path_len
+ suffix_len
+ 1] = '\\';
598 wszCachePath
[path_len
+ suffix_len
+ 2] = '\0';
601 URLCacheContainers_AddContainer(DefaultContainerData
[i
].cache_prefix
, wszCachePath
, wszMutexName
);
605 void URLCacheContainers_DeleteAll(void)
607 while(!list_empty(&UrlContainers
))
608 URLCacheContainer_DeleteContainer(
609 LIST_ENTRY(list_head(&UrlContainers
), URLCACHECONTAINER
, entry
)
613 static DWORD
URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl
, URLCACHECONTAINER
** ppContainer
)
615 URLCACHECONTAINER
* pContainer
;
617 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl
));
620 return ERROR_INVALID_PARAMETER
;
623 if (!bDefaultContainersAdded
)
624 URLCacheContainers_CreateDefaults();
626 LIST_FOR_EACH_ENTRY(pContainer
, &UrlContainers
, URLCACHECONTAINER
, entry
)
628 int prefix_len
= strlenW(pContainer
->cache_prefix
);
629 if (!strncmpW(pContainer
->cache_prefix
, lpwszUrl
, prefix_len
))
631 TRACE("found container with prefix %s for URL %s\n", debugstr_w(pContainer
->cache_prefix
), debugstr_w(lpwszUrl
));
632 *ppContainer
= pContainer
;
633 return ERROR_SUCCESS
;
636 ERR("no container found\n");
637 return ERROR_FILE_NOT_FOUND
;
640 static DWORD
URLCacheContainers_FindContainerA(LPCSTR lpszUrl
, URLCACHECONTAINER
** ppContainer
)
645 if (lpszUrl
&& !(url
= heap_strdupAtoW(lpszUrl
)))
646 return ERROR_OUTOFMEMORY
;
648 ret
= URLCacheContainers_FindContainerW(url
, ppContainer
);
653 static BOOL
URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern
, DWORD dwIndex
, URLCACHECONTAINER
** ppContainer
)
656 URLCACHECONTAINER
* pContainer
;
658 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern
));
660 /* non-NULL search pattern only returns one container ever */
661 if (lpwszSearchPattern
&& dwIndex
> 0)
665 if (!bDefaultContainersAdded
)
666 URLCacheContainers_CreateDefaults();
668 LIST_FOR_EACH_ENTRY(pContainer
, &UrlContainers
, URLCACHECONTAINER
, entry
)
670 if (lpwszSearchPattern
)
672 if (!strcmpW(pContainer
->cache_prefix
, lpwszSearchPattern
))
674 TRACE("found container with prefix %s\n", debugstr_w(pContainer
->cache_prefix
));
675 *ppContainer
= pContainer
;
683 TRACE("found container with prefix %s\n", debugstr_w(pContainer
->cache_prefix
));
684 *ppContainer
= pContainer
;
693 /***********************************************************************
694 * URLCacheContainer_LockIndex (Internal)
696 * Locks the index for system-wide exclusive access.
699 * Cache file header if successful
700 * NULL if failed and calls SetLastError.
702 static LPURLCACHE_HEADER
URLCacheContainer_LockIndex(URLCACHECONTAINER
* pContainer
)
706 URLCACHE_HEADER
* pHeader
;
710 WaitForSingleObject(pContainer
->hMutex
, INFINITE
);
712 pIndexData
= MapViewOfFile(pContainer
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
716 ReleaseMutex(pContainer
->hMutex
);
717 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
720 pHeader
= (URLCACHE_HEADER
*)pIndexData
;
722 /* file has grown - we need to remap to prevent us getting
723 * access violations when we try and access beyond the end
724 * of the memory mapped file */
725 if (pHeader
->dwFileSize
!= pContainer
->file_size
)
727 UnmapViewOfFile( pHeader
);
728 URLCacheContainer_CloseIndex(pContainer
);
729 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
730 if (error
!= ERROR_SUCCESS
)
732 ReleaseMutex(pContainer
->hMutex
);
736 pIndexData
= MapViewOfFile(pContainer
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
740 ReleaseMutex(pContainer
->hMutex
);
741 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
744 pHeader
= (URLCACHE_HEADER
*)pIndexData
;
747 TRACE("Signature: %s, file size: %d bytes\n", pHeader
->szSignature
, pHeader
->dwFileSize
);
749 for (index
= 0; index
< pHeader
->DirectoryCount
; index
++)
751 TRACE("Directory[%d] = \"%.8s\"\n", index
, pHeader
->directory_data
[index
].filename
);
757 /***********************************************************************
758 * URLCacheContainer_UnlockIndex (Internal)
761 static BOOL
URLCacheContainer_UnlockIndex(URLCACHECONTAINER
* pContainer
, LPURLCACHE_HEADER pHeader
)
764 ReleaseMutex(pContainer
->hMutex
);
765 return UnmapViewOfFile(pHeader
);
768 /***********************************************************************
769 * URLCacheContainer_CleanIndex (Internal)
771 * This function is meant to make place in index file by removing old
772 * entries and resizing the file.
774 * CAUTION: file view may get mapped to new memory
775 * TODO: implement entries cleaning
778 * ERROR_SUCCESS when new memory is available
779 * error code otherwise
781 static DWORD
URLCacheContainer_CleanIndex(URLCACHECONTAINER
*container
, URLCACHE_HEADER
**file_view
)
783 URLCACHE_HEADER
*header
= *file_view
;
786 FIXME("(%s %s) semi-stub\n", debugstr_w(container
->cache_prefix
), debugstr_w(container
->path
));
788 if(header
->dwFileSize
>= ALLOCATION_TABLE_SIZE
*8*BLOCKSIZE
+ ENTRY_START_OFFSET
) {
789 WARN("index file has maximal size\n");
790 return ERROR_NOT_ENOUGH_MEMORY
;
793 URLCacheContainer_CloseIndex(container
);
794 ret
= URLCacheContainer_OpenIndex(container
, header
->dwIndexCapacityInBlocks
*2);
795 if(ret
!= ERROR_SUCCESS
)
797 header
= MapViewOfFile(container
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
799 return GetLastError();
801 UnmapViewOfFile(*file_view
);
803 return ERROR_SUCCESS
;
807 #define CHAR_BIT (8 * sizeof(CHAR))
810 /***********************************************************************
811 * URLCache_Allocation_BlockIsFree (Internal)
813 * Is the specified block number free?
820 static inline BYTE
URLCache_Allocation_BlockIsFree(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
822 BYTE mask
= 1 << (dwBlockNumber
% CHAR_BIT
);
823 return (AllocationTable
[dwBlockNumber
/ CHAR_BIT
] & mask
) == 0;
826 /***********************************************************************
827 * URLCache_Allocation_BlockFree (Internal)
829 * Marks the specified block as free
835 static inline void URLCache_Allocation_BlockFree(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
837 BYTE mask
= ~(1 << (dwBlockNumber
% CHAR_BIT
));
838 AllocationTable
[dwBlockNumber
/ CHAR_BIT
] &= mask
;
841 /***********************************************************************
842 * URLCache_Allocation_BlockAllocate (Internal)
844 * Marks the specified block as allocated
850 static inline void URLCache_Allocation_BlockAllocate(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
852 BYTE mask
= 1 << (dwBlockNumber
% CHAR_BIT
);
853 AllocationTable
[dwBlockNumber
/ CHAR_BIT
] |= mask
;
856 /***********************************************************************
857 * URLCache_FindFirstFreeEntry (Internal)
859 * Finds and allocates the first block of free space big enough and
860 * sets ppEntry to point to it.
863 * ERROR_SUCCESS when free memory block was found
864 * Any other Win32 error code if the entry could not be added
867 static DWORD
URLCache_FindFirstFreeEntry(URLCACHE_HEADER
* pHeader
, DWORD dwBlocksNeeded
, CACHEFILE_ENTRY
** ppEntry
)
869 LPBYTE AllocationTable
= (LPBYTE
)pHeader
+ ALLOCATION_TABLE_OFFSET
;
872 for (dwBlockNumber
= 0; dwBlockNumber
< pHeader
->dwIndexCapacityInBlocks
; dwBlockNumber
++)
874 for (dwFreeCounter
= 0;
875 dwFreeCounter
< dwBlocksNeeded
&&
876 dwFreeCounter
+ dwBlockNumber
< pHeader
->dwIndexCapacityInBlocks
&&
877 URLCache_Allocation_BlockIsFree(AllocationTable
, dwBlockNumber
+ dwFreeCounter
);
879 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber
, ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
881 if (dwFreeCounter
== dwBlocksNeeded
)
884 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber
, ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
885 for (index
= 0; index
< dwBlocksNeeded
; index
++)
886 URLCache_Allocation_BlockAllocate(AllocationTable
, dwBlockNumber
+ index
);
887 *ppEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
888 for (index
= 0; index
< dwBlocksNeeded
* BLOCKSIZE
/ sizeof(DWORD
); index
++)
889 ((DWORD
*)*ppEntry
)[index
] = 0xdeadbeef;
890 (*ppEntry
)->dwBlocksUsed
= dwBlocksNeeded
;
891 return ERROR_SUCCESS
;
895 return ERROR_HANDLE_DISK_FULL
;
898 /***********************************************************************
899 * URLCache_DeleteEntry (Internal)
901 * Deletes the specified entry and frees the space allocated to it
904 * TRUE if it succeeded
908 static BOOL
URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader
, CACHEFILE_ENTRY
* pEntry
)
912 BYTE
* AllocationTable
= (LPBYTE
)pHeader
+ ALLOCATION_TABLE_OFFSET
;
914 /* update allocation table */
915 dwStartBlock
= ((DWORD
)((BYTE
*)pEntry
- (BYTE
*)pHeader
) - ENTRY_START_OFFSET
) / BLOCKSIZE
;
916 for (dwBlock
= dwStartBlock
; dwBlock
< dwStartBlock
+ pEntry
->dwBlocksUsed
; dwBlock
++)
917 URLCache_Allocation_BlockFree(AllocationTable
, dwBlock
);
922 /***********************************************************************
923 * URLCache_LocalFileNameToPathW (Internal)
925 * Copies the full path to the specified buffer given the local file
926 * name and the index of the directory it is in. Always sets value in
927 * lpBufferSize to the required buffer size (in bytes).
930 * TRUE if the buffer was big enough
931 * FALSE if the buffer was too small
934 static BOOL
URLCache_LocalFileNameToPathW(
935 const URLCACHECONTAINER
* pContainer
,
936 LPCURLCACHE_HEADER pHeader
,
937 LPCSTR szLocalFileName
,
943 int path_len
= strlenW(pContainer
->path
);
944 int file_name_len
= MultiByteToWideChar(CP_ACP
, 0, szLocalFileName
, -1, NULL
, 0);
945 if (Directory
>= pHeader
->DirectoryCount
)
951 nRequired
= (path_len
+ DIR_LENGTH
+ file_name_len
+ 1) * sizeof(WCHAR
);
952 if (nRequired
<= *lpBufferSize
)
956 memcpy(wszPath
, pContainer
->path
, path_len
* sizeof(WCHAR
));
957 dir_len
= MultiByteToWideChar(CP_ACP
, 0, pHeader
->directory_data
[Directory
].filename
, DIR_LENGTH
, wszPath
+ path_len
, DIR_LENGTH
);
958 wszPath
[dir_len
+ path_len
] = '\\';
959 MultiByteToWideChar(CP_ACP
, 0, szLocalFileName
, -1, wszPath
+ dir_len
+ path_len
+ 1, file_name_len
);
960 *lpBufferSize
= nRequired
;
963 *lpBufferSize
= nRequired
;
967 /***********************************************************************
968 * URLCache_LocalFileNameToPathA (Internal)
970 * Copies the full path to the specified buffer given the local file
971 * name and the index of the directory it is in. Always sets value in
972 * lpBufferSize to the required buffer size.
975 * TRUE if the buffer was big enough
976 * FALSE if the buffer was too small
979 static BOOL
URLCache_LocalFileNameToPathA(
980 const URLCACHECONTAINER
* pContainer
,
981 LPCURLCACHE_HEADER pHeader
,
982 LPCSTR szLocalFileName
,
988 int path_len
, file_name_len
, dir_len
;
990 if (Directory
>= pHeader
->DirectoryCount
)
996 path_len
= WideCharToMultiByte(CP_ACP
, 0, pContainer
->path
, -1, NULL
, 0, NULL
, NULL
) - 1;
997 file_name_len
= strlen(szLocalFileName
) + 1 /* for nul-terminator */;
998 dir_len
= DIR_LENGTH
;
1000 nRequired
= (path_len
+ dir_len
+ 1 + file_name_len
) * sizeof(char);
1001 if (nRequired
< *lpBufferSize
)
1003 WideCharToMultiByte(CP_ACP
, 0, pContainer
->path
, -1, szPath
, path_len
, NULL
, NULL
);
1004 memcpy(szPath
+path_len
, pHeader
->directory_data
[Directory
].filename
, dir_len
);
1005 szPath
[path_len
+ dir_len
] = '\\';
1006 memcpy(szPath
+ path_len
+ dir_len
+ 1, szLocalFileName
, file_name_len
);
1007 *lpBufferSize
= nRequired
;
1010 *lpBufferSize
= nRequired
;
1014 /* Just like DosDateTimeToFileTime, except that it also maps the special
1015 * case of a DOS date/time of (0,0) to a filetime of (0,0).
1017 static void URLCache_DosDateTimeToFileTime(WORD fatdate
, WORD fattime
,
1020 if (!fatdate
&& !fattime
)
1021 ft
->dwLowDateTime
= ft
->dwHighDateTime
= 0;
1023 DosDateTimeToFileTime(fatdate
, fattime
, ft
);
1026 /***********************************************************************
1027 * URLCache_CopyEntry (Internal)
1029 * Copies an entry from the cache index file to the Win32 structure
1032 * ERROR_SUCCESS if the buffer was big enough
1033 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1036 static DWORD
URLCache_CopyEntry(
1037 URLCACHECONTAINER
* pContainer
,
1038 LPCURLCACHE_HEADER pHeader
,
1039 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1040 LPDWORD lpdwBufferSize
,
1041 const URL_CACHEFILE_ENTRY
* pUrlEntry
,
1045 DWORD dwRequiredSize
= sizeof(*lpCacheEntryInfo
);
1047 if (*lpdwBufferSize
>= dwRequiredSize
)
1049 lpCacheEntryInfo
->lpHeaderInfo
= NULL
;
1050 lpCacheEntryInfo
->lpszFileExtension
= NULL
;
1051 lpCacheEntryInfo
->lpszLocalFileName
= NULL
;
1052 lpCacheEntryInfo
->lpszSourceUrlName
= NULL
;
1053 lpCacheEntryInfo
->CacheEntryType
= pUrlEntry
->CacheEntryType
;
1054 lpCacheEntryInfo
->u
.dwExemptDelta
= pUrlEntry
->dwExemptDelta
;
1055 lpCacheEntryInfo
->dwHeaderInfoSize
= pUrlEntry
->dwHeaderInfoSize
;
1056 lpCacheEntryInfo
->dwHitRate
= pUrlEntry
->dwHitRate
;
1057 lpCacheEntryInfo
->dwSizeHigh
= pUrlEntry
->size
.u
.HighPart
;
1058 lpCacheEntryInfo
->dwSizeLow
= pUrlEntry
->size
.u
.LowPart
;
1059 lpCacheEntryInfo
->dwStructSize
= sizeof(*lpCacheEntryInfo
);
1060 lpCacheEntryInfo
->dwUseCount
= pUrlEntry
->dwUseCount
;
1061 URLCache_DosDateTimeToFileTime(pUrlEntry
->wExpiredDate
, pUrlEntry
->wExpiredTime
, &lpCacheEntryInfo
->ExpireTime
);
1062 lpCacheEntryInfo
->LastAccessTime
.dwHighDateTime
= pUrlEntry
->LastAccessTime
.dwHighDateTime
;
1063 lpCacheEntryInfo
->LastAccessTime
.dwLowDateTime
= pUrlEntry
->LastAccessTime
.dwLowDateTime
;
1064 lpCacheEntryInfo
->LastModifiedTime
.dwHighDateTime
= pUrlEntry
->LastModifiedTime
.dwHighDateTime
;
1065 lpCacheEntryInfo
->LastModifiedTime
.dwLowDateTime
= pUrlEntry
->LastModifiedTime
.dwLowDateTime
;
1066 URLCache_DosDateTimeToFileTime(pUrlEntry
->wLastSyncDate
, pUrlEntry
->wLastSyncTime
, &lpCacheEntryInfo
->LastSyncTime
);
1069 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1070 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1071 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1073 lenUrl
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, -1, NULL
, 0);
1075 lenUrl
= strlen((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
1076 dwRequiredSize
+= (lenUrl
+ 1) * (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
1078 /* FIXME: is source url optional? */
1079 if (*lpdwBufferSize
>= dwRequiredSize
)
1081 DWORD lenUrlBytes
= (lenUrl
+1) * (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
1083 lpCacheEntryInfo
->lpszSourceUrlName
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
- lenUrlBytes
;
1085 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, -1, (LPWSTR
)lpCacheEntryInfo
->lpszSourceUrlName
, lenUrl
+ 1);
1087 memcpy(lpCacheEntryInfo
->lpszSourceUrlName
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, lenUrlBytes
);
1090 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1091 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1092 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1094 if (pUrlEntry
->dwOffsetLocalName
)
1096 LONG nLocalFilePathSize
;
1097 LPSTR lpszLocalFileName
;
1098 lpszLocalFileName
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
;
1099 nLocalFilePathSize
= *lpdwBufferSize
- dwRequiredSize
;
1100 if ((bUnicode
&& URLCache_LocalFileNameToPathW(pContainer
, pHeader
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
, pUrlEntry
->CacheDir
, (LPWSTR
)lpszLocalFileName
, &nLocalFilePathSize
)) ||
1101 (!bUnicode
&& URLCache_LocalFileNameToPathA(pContainer
, pHeader
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
, pUrlEntry
->CacheDir
, lpszLocalFileName
, &nLocalFilePathSize
)))
1103 lpCacheEntryInfo
->lpszLocalFileName
= lpszLocalFileName
;
1105 dwRequiredSize
+= nLocalFilePathSize
* (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
)) ;
1107 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1108 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1109 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1111 dwRequiredSize
+= pUrlEntry
->dwHeaderInfoSize
+ 1;
1113 if (*lpdwBufferSize
>= dwRequiredSize
)
1115 lpCacheEntryInfo
->lpHeaderInfo
= (LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
- pUrlEntry
->dwHeaderInfoSize
- 1;
1116 memcpy(lpCacheEntryInfo
->lpHeaderInfo
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
, pUrlEntry
->dwHeaderInfoSize
);
1117 ((LPBYTE
)lpCacheEntryInfo
)[dwRequiredSize
- 1] = '\0';
1119 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1120 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1121 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1123 if (pUrlEntry
->dwOffsetFileExtension
)
1128 lenExtension
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, -1, NULL
, 0);
1130 lenExtension
= strlen((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
) + 1;
1131 dwRequiredSize
+= lenExtension
* (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
1133 if (*lpdwBufferSize
>= dwRequiredSize
)
1135 lpCacheEntryInfo
->lpszFileExtension
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
- lenExtension
;
1137 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, -1, (LPWSTR
)lpCacheEntryInfo
->lpszSourceUrlName
, lenExtension
);
1139 memcpy(lpCacheEntryInfo
->lpszFileExtension
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, lenExtension
* sizeof(CHAR
));
1142 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1143 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1144 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1147 if (dwRequiredSize
> *lpdwBufferSize
)
1149 *lpdwBufferSize
= dwRequiredSize
;
1150 return ERROR_INSUFFICIENT_BUFFER
;
1152 *lpdwBufferSize
= dwRequiredSize
;
1153 return ERROR_SUCCESS
;
1156 /* Just like FileTimeToDosDateTime, except that it also maps the special
1157 * case of a filetime of (0,0) to a DOS date/time of (0,0).
1159 static void URLCache_FileTimeToDosDateTime(const FILETIME
*ft
, WORD
*fatdate
,
1162 if (!ft
->dwLowDateTime
&& !ft
->dwHighDateTime
)
1163 *fatdate
= *fattime
= 0;
1165 FileTimeToDosDateTime(ft
, fatdate
, fattime
);
1168 /***********************************************************************
1169 * URLCache_SetEntryInfo (Internal)
1171 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1172 * according to the flags set by dwFieldControl.
1175 * ERROR_SUCCESS if the buffer was big enough
1176 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1179 static DWORD
URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY
* pUrlEntry
, const INTERNET_CACHE_ENTRY_INFOW
* lpCacheEntryInfo
, DWORD dwFieldControl
)
1181 if (dwFieldControl
& CACHE_ENTRY_ACCTIME_FC
)
1182 pUrlEntry
->LastAccessTime
= lpCacheEntryInfo
->LastAccessTime
;
1183 if (dwFieldControl
& CACHE_ENTRY_ATTRIBUTE_FC
)
1184 pUrlEntry
->CacheEntryType
= lpCacheEntryInfo
->CacheEntryType
;
1185 if (dwFieldControl
& CACHE_ENTRY_EXEMPT_DELTA_FC
)
1186 pUrlEntry
->dwExemptDelta
= lpCacheEntryInfo
->u
.dwExemptDelta
;
1187 if (dwFieldControl
& CACHE_ENTRY_EXPTIME_FC
)
1188 URLCache_FileTimeToDosDateTime(&lpCacheEntryInfo
->ExpireTime
, &pUrlEntry
->wExpiredDate
, &pUrlEntry
->wExpiredTime
);
1189 if (dwFieldControl
& CACHE_ENTRY_HEADERINFO_FC
)
1190 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1191 if (dwFieldControl
& CACHE_ENTRY_HITRATE_FC
)
1192 pUrlEntry
->dwHitRate
= lpCacheEntryInfo
->dwHitRate
;
1193 if (dwFieldControl
& CACHE_ENTRY_MODTIME_FC
)
1194 pUrlEntry
->LastModifiedTime
= lpCacheEntryInfo
->LastModifiedTime
;
1195 if (dwFieldControl
& CACHE_ENTRY_SYNCTIME_FC
)
1196 URLCache_FileTimeToDosDateTime(&lpCacheEntryInfo
->LastAccessTime
, &pUrlEntry
->wLastSyncDate
, &pUrlEntry
->wLastSyncTime
);
1198 return ERROR_SUCCESS
;
1201 /***********************************************************************
1202 * URLCache_HashKey (Internal)
1204 * Returns the hash key for a given string
1207 * hash key for the string
1210 static DWORD
URLCache_HashKey(LPCSTR lpszKey
)
1212 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1213 * but the algorithm and result are not the same!
1215 static const unsigned char lookupTable
[256] =
1217 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1218 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1219 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1220 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1221 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1222 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1223 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1224 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1225 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1226 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1227 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1228 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1229 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1230 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1231 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1232 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1233 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1234 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1235 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1236 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1237 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1238 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1239 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1240 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1241 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1242 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1243 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1244 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1245 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1246 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1247 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1248 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1253 for (i
= 0; i
< sizeof(key
) / sizeof(key
[0]); i
++)
1254 key
[i
] = lookupTable
[(*lpszKey
+ i
) & 0xFF];
1256 for (lpszKey
++; *lpszKey
&& ((lpszKey
[0] != '/') || (lpszKey
[1] != 0)); lpszKey
++)
1258 for (i
= 0; i
< sizeof(key
) / sizeof(key
[0]); i
++)
1259 key
[i
] = lookupTable
[*lpszKey
^ key
[i
]];
1262 return *(DWORD
*)key
;
1265 static inline HASH_CACHEFILE_ENTRY
* URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader
, DWORD dwOffset
)
1267 return (HASH_CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ dwOffset
);
1270 static inline BOOL
URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader
, const HASH_CACHEFILE_ENTRY
*pHashEntry
)
1272 /* check pHashEntry located within acceptable bounds in the URL cache mapping */
1273 return ((DWORD
)((const BYTE
*)pHashEntry
- (const BYTE
*)pHeader
) >= ENTRY_START_OFFSET
) &&
1274 ((DWORD
)((const BYTE
*)pHashEntry
- (const BYTE
*)pHeader
) < pHeader
->dwFileSize
);
1277 static BOOL
URLCache_FindHash(LPCURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, struct _HASH_ENTRY
** ppHashEntry
)
1279 /* structure of hash table:
1280 * 448 entries divided into 64 blocks
1281 * each block therefore contains a chain of 7 key/offset pairs
1282 * how position in table is calculated:
1283 * 1. the url is hashed in helper function
1284 * 2. the key % HASHTABLE_NUM_ENTRIES is the bucket number
1285 * 3. bucket number * HASHTABLE_BLOCKSIZE is offset of the bucket
1288 * there can be multiple hash tables in the file and the offset to
1289 * the next one is stored in the header of the hash table
1291 DWORD key
= URLCache_HashKey(lpszUrl
);
1292 DWORD offset
= (key
& (HASHTABLE_NUM_ENTRIES
-1)) * HASHTABLE_BLOCKSIZE
;
1293 HASH_CACHEFILE_ENTRY
* pHashEntry
;
1294 DWORD dwHashTableNumber
= 0;
1296 key
>>= HASHTABLE_FLAG_BITS
;
1298 for (pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1299 URLCache_IsHashEntryValid(pHeader
, pHashEntry
);
1300 pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHashEntry
->dwAddressNext
))
1303 if (pHashEntry
->dwHashTableNumber
!= dwHashTableNumber
++)
1305 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry
->dwHashTableNumber
, dwHashTableNumber
);
1308 /* make sure that it is in fact a hash entry */
1309 if (pHashEntry
->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1311 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&pHashEntry
->CacheFileEntry
.dwSignature
);
1315 for (i
= 0; i
< HASHTABLE_BLOCKSIZE
; i
++)
1317 struct _HASH_ENTRY
* pHashElement
= &pHashEntry
->HashTable
[offset
+ i
];
1318 if (key
== pHashElement
->dwHashKey
>>HASHTABLE_FLAG_BITS
)
1320 /* FIXME: we should make sure that this is the right element
1321 * before returning and claiming that it is. We can do this
1322 * by doing a simple compare between the URL we were given
1323 * and the URL stored in the entry. However, this assumes
1324 * we know the format of all the entries stored in the
1326 *ppHashEntry
= pHashElement
;
1334 static BOOL
URLCache_FindHashW(LPCURLCACHE_HEADER pHeader
, LPCWSTR lpszUrl
, struct _HASH_ENTRY
** ppHashEntry
)
1339 urlA
= heap_strdupWtoA(lpszUrl
);
1342 SetLastError(ERROR_OUTOFMEMORY
);
1346 ret
= URLCache_FindHash(pHeader
, urlA
, ppHashEntry
);
1351 /***********************************************************************
1352 * URLCache_HashEntrySetFlags (Internal)
1354 * Sets special bits in hash key
1360 static void URLCache_HashEntrySetFlags(struct _HASH_ENTRY
* pHashEntry
, DWORD dwFlag
)
1362 pHashEntry
->dwHashKey
= (pHashEntry
->dwHashKey
>> HASHTABLE_FLAG_BITS
<< HASHTABLE_FLAG_BITS
) | dwFlag
;
1365 /***********************************************************************
1366 * URLCache_DeleteEntryFromHash (Internal)
1368 * Searches all the hash tables in the index for the given URL and
1369 * then if found deletes the entry.
1372 * TRUE if the entry was found
1373 * FALSE if the entry could not be found
1376 static BOOL
URLCache_DeleteEntryFromHash(struct _HASH_ENTRY
* pHashEntry
)
1378 pHashEntry
->dwHashKey
= HASHTABLE_DEL
;
1382 /***********************************************************************
1383 * URLCache_AddEntryToHash (Internal)
1385 * Searches all the hash tables for a free slot based on the offset
1386 * generated from the hash key. If a free slot is found, the offset and
1387 * key are entered into the hash table.
1390 * ERROR_SUCCESS if the entry was added
1391 * Any other Win32 error code if the entry could not be added
1394 static DWORD
URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, DWORD dwOffsetEntry
, DWORD dwFieldType
)
1396 /* see URLCache_FindEntryInHash for structure of hash tables */
1398 DWORD key
= URLCache_HashKey(lpszUrl
);
1399 DWORD offset
= (key
& (HASHTABLE_NUM_ENTRIES
-1)) * HASHTABLE_BLOCKSIZE
;
1400 HASH_CACHEFILE_ENTRY
* pHashEntry
, *pHashPrev
= NULL
;
1401 DWORD dwHashTableNumber
= 0;
1404 key
= ((key
>> HASHTABLE_FLAG_BITS
) << HASHTABLE_FLAG_BITS
) + dwFieldType
;
1406 for (pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1407 URLCache_IsHashEntryValid(pHeader
, pHashEntry
);
1408 pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHashEntry
->dwAddressNext
))
1411 pHashPrev
= pHashEntry
;
1413 if (pHashEntry
->dwHashTableNumber
!= dwHashTableNumber
++)
1415 ERR("not right hash table number (%d) expected %d\n", pHashEntry
->dwHashTableNumber
, dwHashTableNumber
);
1418 /* make sure that it is in fact a hash entry */
1419 if (pHashEntry
->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1421 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&pHashEntry
->CacheFileEntry
.dwSignature
);
1425 for (i
= 0; i
< HASHTABLE_BLOCKSIZE
; i
++)
1427 struct _HASH_ENTRY
* pHashElement
= &pHashEntry
->HashTable
[offset
+ i
];
1428 if (pHashElement
->dwHashKey
==HASHTABLE_FREE
|| pHashElement
->dwHashKey
==HASHTABLE_DEL
) /* if the slot is free */
1430 pHashElement
->dwHashKey
= key
;
1431 pHashElement
->dwOffsetEntry
= dwOffsetEntry
;
1432 return ERROR_SUCCESS
;
1436 error
= URLCache_CreateHashTable(pHeader
, pHashPrev
, &pHashEntry
);
1437 if (error
!= ERROR_SUCCESS
)
1440 pHashEntry
->HashTable
[offset
].dwHashKey
= key
;
1441 pHashEntry
->HashTable
[offset
].dwOffsetEntry
= dwOffsetEntry
;
1442 return ERROR_SUCCESS
;
1445 /***********************************************************************
1446 * URLCache_CreateHashTable (Internal)
1448 * Creates a new hash table in free space and adds it to the chain of existing
1452 * ERROR_SUCCESS if the hash table was created
1453 * ERROR_DISK_FULL if the hash table could not be created
1456 static DWORD
URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader
, HASH_CACHEFILE_ENTRY
*pPrevHash
, HASH_CACHEFILE_ENTRY
**ppHash
)
1458 DWORD dwOffset
, error
;
1461 if ((error
= URLCache_FindFirstFreeEntry(pHeader
, 0x20, (CACHEFILE_ENTRY
**)ppHash
)) != ERROR_SUCCESS
)
1464 dwOffset
= (BYTE
*)*ppHash
- (BYTE
*)pHeader
;
1467 pPrevHash
->dwAddressNext
= dwOffset
;
1469 pHeader
->dwOffsetFirstHashTable
= dwOffset
;
1470 (*ppHash
)->CacheFileEntry
.dwSignature
= HASH_SIGNATURE
;
1471 (*ppHash
)->CacheFileEntry
.dwBlocksUsed
= 0x20;
1472 (*ppHash
)->dwAddressNext
= 0;
1473 (*ppHash
)->dwHashTableNumber
= pPrevHash
? pPrevHash
->dwHashTableNumber
+ 1 : 0;
1474 for (i
= 0; i
< HASHTABLE_SIZE
; i
++)
1476 (*ppHash
)->HashTable
[i
].dwOffsetEntry
= HASHTABLE_FREE
;
1477 (*ppHash
)->HashTable
[i
].dwHashKey
= HASHTABLE_FREE
;
1479 return ERROR_SUCCESS
;
1482 /***********************************************************************
1483 * URLCache_EnumHashTables (Internal)
1485 * Enumerates the hash tables in a container.
1488 * TRUE if an entry was found
1489 * FALSE if there are no more tables to enumerate.
1492 static BOOL
URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader
, DWORD
*pdwHashTableNumber
, HASH_CACHEFILE_ENTRY
** ppHashEntry
)
1494 for (*ppHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1495 URLCache_IsHashEntryValid(pHeader
, *ppHashEntry
);
1496 *ppHashEntry
= URLCache_HashEntryFromOffset(pHeader
, (*ppHashEntry
)->dwAddressNext
))
1498 TRACE("looking at hash table number %d\n", (*ppHashEntry
)->dwHashTableNumber
);
1499 if ((*ppHashEntry
)->dwHashTableNumber
!= *pdwHashTableNumber
)
1501 /* make sure that it is in fact a hash entry */
1502 if ((*ppHashEntry
)->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1504 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&(*ppHashEntry
)->CacheFileEntry
.dwSignature
);
1505 (*pdwHashTableNumber
)++;
1509 TRACE("hash table number %d found\n", *pdwHashTableNumber
);
1515 /***********************************************************************
1516 * URLCache_EnumHashTableEntries (Internal)
1518 * Enumerates entries in a hash table and returns the next non-free entry.
1521 * TRUE if an entry was found
1522 * FALSE if the hash table is empty or there are no more entries to
1526 static BOOL
URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader
, const HASH_CACHEFILE_ENTRY
* pHashEntry
,
1527 DWORD
* index
, const struct _HASH_ENTRY
** ppHashEntry
)
1529 for (; *index
< HASHTABLE_SIZE
; (*index
)++)
1531 if (pHashEntry
->HashTable
[*index
].dwHashKey
==HASHTABLE_FREE
|| pHashEntry
->HashTable
[*index
].dwHashKey
==HASHTABLE_DEL
)
1534 *ppHashEntry
= &pHashEntry
->HashTable
[*index
];
1535 TRACE("entry found %d\n", *index
);
1538 TRACE("no more entries (%d)\n", *index
);
1542 /***********************************************************************
1543 * URLCache_DeleteCacheDirectory (Internal)
1545 * Erase a directory containing an URL cache.
1548 * TRUE success, FALSE failure/aborted.
1551 static BOOL
URLCache_DeleteCacheDirectory(LPCWSTR lpszPath
)
1554 WCHAR path
[MAX_PATH
+ 1];
1555 SHFILEOPSTRUCTW shfos
;
1558 path_len
= strlenW(lpszPath
);
1559 if (path_len
>= MAX_PATH
)
1561 strcpyW(path
, lpszPath
);
1562 path
[path_len
+ 1] = 0; /* double-NUL-terminate path */
1565 shfos
.wFunc
= FO_DELETE
;
1569 shfos
.fAnyOperationsAborted
= FALSE
;
1570 ret
= SHFileOperationW(&shfos
);
1572 ERR("SHFileOperationW on %s returned %i\n", debugstr_w(path
), ret
);
1573 return !(ret
|| shfos
.fAnyOperationsAborted
);
1576 /***********************************************************************
1577 * FreeUrlCacheSpaceW (WININET.@)
1579 * Frees up some cache.
1582 * lpszCachePath [I] Which volume to free up from, or NULL if you don't care.
1583 * dwSize [I] How much space to free up.
1584 * dwSizeType [I] How to interpret dwSize.
1587 * TRUE success. FALSE failure.
1590 * This implementation just retrieves the path of the cache directory, and
1591 * deletes its contents from the filesystem. The correct approach would
1592 * probably be to implement and use {FindFirst,FindNext,Delete}UrlCacheGroup().
1594 BOOL WINAPI
FreeUrlCacheSpaceW(LPCWSTR lpszCachePath
, DWORD dwSize
, DWORD dwSizeType
)
1596 URLCACHECONTAINER
* pContainer
;
1598 if (lpszCachePath
!= NULL
|| dwSize
!= 100 || dwSizeType
!= FCS_PERCENT_CACHE_SPACE
)
1600 FIXME("(%s, %x, %x): partial stub!\n", debugstr_w(lpszCachePath
), dwSize
, dwSizeType
);
1601 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1606 if (!bDefaultContainersAdded
)
1607 URLCacheContainers_CreateDefaults();
1609 LIST_FOR_EACH_ENTRY(pContainer
, &UrlContainers
, URLCACHECONTAINER
, entry
)
1611 /* The URL cache has prefix L"" (unlike Cookies and History) */
1612 if (pContainer
->cache_prefix
[0] == 0)
1616 WaitForSingleObject(pContainer
->hMutex
, INFINITE
);
1618 /* unlock, delete, recreate and lock cache */
1619 URLCacheContainer_CloseIndex(pContainer
);
1620 ret_del
= URLCache_DeleteCacheDirectory(pContainer
->path
);
1621 ret_open
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
1623 ReleaseMutex(pContainer
->hMutex
);
1624 return ret_del
&& (ret_open
== ERROR_SUCCESS
);
1630 /***********************************************************************
1631 * FreeUrlCacheSpaceA (WININET.@)
1633 * See FreeUrlCacheSpaceW.
1635 BOOL WINAPI
FreeUrlCacheSpaceA(LPCSTR lpszCachePath
, DWORD dwSize
, DWORD dwSizeType
)
1638 LPWSTR path
= heap_strdupAtoW(lpszCachePath
);
1639 if (lpszCachePath
== NULL
|| path
!= NULL
)
1640 ret
= FreeUrlCacheSpaceW(path
, dwSize
, dwSizeType
);
1645 /***********************************************************************
1646 * GetUrlCacheEntryInfoExA (WININET.@)
1649 BOOL WINAPI
GetUrlCacheEntryInfoExA(
1651 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1652 LPDWORD lpdwCacheEntryInfoBufSize
,
1654 LPDWORD lpdwReserved
,
1658 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1659 debugstr_a(lpszUrl
),
1661 lpdwCacheEntryInfoBufSize
,
1667 if ((lpszReserved
!= NULL
) ||
1668 (lpdwReserved
!= NULL
) ||
1669 (lpReserved
!= NULL
))
1671 ERR("Reserved value was not 0\n");
1672 SetLastError(ERROR_INVALID_PARAMETER
);
1677 FIXME("Undocumented flag(s): %x\n", dwFlags
);
1678 SetLastError(ERROR_FILE_NOT_FOUND
);
1681 return GetUrlCacheEntryInfoA(lpszUrl
, lpCacheEntryInfo
, lpdwCacheEntryInfoBufSize
);
1684 /***********************************************************************
1685 * GetUrlCacheEntryInfoA (WININET.@)
1688 BOOL WINAPI
GetUrlCacheEntryInfoA(
1689 IN LPCSTR lpszUrlName
,
1690 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1691 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1694 LPURLCACHE_HEADER pHeader
;
1695 struct _HASH_ENTRY
* pHashEntry
;
1696 const CACHEFILE_ENTRY
* pEntry
;
1697 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
1698 URLCACHECONTAINER
* pContainer
;
1701 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
, lpdwCacheEntryInfoBufferSize
);
1703 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
1704 if (error
!= ERROR_SUCCESS
)
1706 SetLastError(error
);
1710 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
1711 if (error
!= ERROR_SUCCESS
)
1713 SetLastError(error
);
1717 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1720 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
1722 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1723 WARN("entry %s not found!\n", debugstr_a(lpszUrlName
));
1724 SetLastError(ERROR_FILE_NOT_FOUND
);
1728 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1729 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1731 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1732 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1733 SetLastError(ERROR_FILE_NOT_FOUND
);
1737 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
1738 TRACE("Found URL: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
));
1739 if (pUrlEntry
->dwOffsetHeaderInfo
)
1740 TRACE("Header info: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
1742 if (lpdwCacheEntryInfoBufferSize
)
1744 if (!lpCacheEntryInfo
)
1745 *lpdwCacheEntryInfoBufferSize
= 0;
1747 error
= URLCache_CopyEntry(
1751 lpdwCacheEntryInfoBufferSize
,
1754 if (error
!= ERROR_SUCCESS
)
1756 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1757 SetLastError(error
);
1760 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
1763 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1768 /***********************************************************************
1769 * GetUrlCacheEntryInfoW (WININET.@)
1772 BOOL WINAPI
GetUrlCacheEntryInfoW(LPCWSTR lpszUrl
,
1773 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1774 LPDWORD lpdwCacheEntryInfoBufferSize
)
1776 LPURLCACHE_HEADER pHeader
;
1777 struct _HASH_ENTRY
* pHashEntry
;
1778 const CACHEFILE_ENTRY
* pEntry
;
1779 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
1780 URLCACHECONTAINER
* pContainer
;
1783 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl
), lpCacheEntryInfo
, lpdwCacheEntryInfoBufferSize
);
1785 error
= URLCacheContainers_FindContainerW(lpszUrl
, &pContainer
);
1786 if (error
!= ERROR_SUCCESS
)
1788 SetLastError(error
);
1792 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
1793 if (error
!= ERROR_SUCCESS
)
1795 SetLastError(error
);
1799 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1802 if (!URLCache_FindHashW(pHeader
, lpszUrl
, &pHashEntry
))
1804 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1805 WARN("entry %s not found!\n", debugstr_w(lpszUrl
));
1806 SetLastError(ERROR_FILE_NOT_FOUND
);
1810 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1811 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1813 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1814 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1815 SetLastError(ERROR_FILE_NOT_FOUND
);
1819 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
1820 TRACE("Found URL: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
));
1821 TRACE("Header info: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
1823 if (lpdwCacheEntryInfoBufferSize
)
1825 if (!lpCacheEntryInfo
)
1826 *lpdwCacheEntryInfoBufferSize
= 0;
1828 error
= URLCache_CopyEntry(
1831 (LPINTERNET_CACHE_ENTRY_INFOA
)lpCacheEntryInfo
,
1832 lpdwCacheEntryInfoBufferSize
,
1834 TRUE
/* UNICODE */);
1835 if (error
!= ERROR_SUCCESS
)
1837 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1838 SetLastError(error
);
1841 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
1844 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1849 /***********************************************************************
1850 * GetUrlCacheEntryInfoExW (WININET.@)
1853 BOOL WINAPI
GetUrlCacheEntryInfoExW(
1855 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1856 LPDWORD lpdwCacheEntryInfoBufSize
,
1857 LPWSTR lpszReserved
,
1858 LPDWORD lpdwReserved
,
1862 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1863 debugstr_w(lpszUrl
),
1865 lpdwCacheEntryInfoBufSize
,
1871 if ((lpszReserved
!= NULL
) ||
1872 (lpdwReserved
!= NULL
) ||
1873 (lpReserved
!= NULL
))
1875 ERR("Reserved value was not 0\n");
1876 SetLastError(ERROR_INVALID_PARAMETER
);
1881 FIXME("Undocumented flag(s): %x\n", dwFlags
);
1882 SetLastError(ERROR_FILE_NOT_FOUND
);
1885 return GetUrlCacheEntryInfoW(lpszUrl
, lpCacheEntryInfo
, lpdwCacheEntryInfoBufSize
);
1888 /***********************************************************************
1889 * SetUrlCacheEntryInfoA (WININET.@)
1891 BOOL WINAPI
SetUrlCacheEntryInfoA(
1893 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1894 DWORD dwFieldControl
)
1896 LPURLCACHE_HEADER pHeader
;
1897 struct _HASH_ENTRY
* pHashEntry
;
1898 CACHEFILE_ENTRY
* pEntry
;
1899 URLCACHECONTAINER
* pContainer
;
1902 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
, dwFieldControl
);
1904 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
1905 if (error
!= ERROR_SUCCESS
)
1907 SetLastError(error
);
1911 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
1912 if (error
!= ERROR_SUCCESS
)
1914 SetLastError(error
);
1918 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1921 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
1923 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1924 WARN("entry %s not found!\n", debugstr_a(lpszUrlName
));
1925 SetLastError(ERROR_FILE_NOT_FOUND
);
1929 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1930 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1932 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1933 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1934 SetLastError(ERROR_FILE_NOT_FOUND
);
1938 URLCache_SetEntryInfo(
1939 (URL_CACHEFILE_ENTRY
*)pEntry
,
1940 (const INTERNET_CACHE_ENTRY_INFOW
*)lpCacheEntryInfo
,
1943 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1948 /***********************************************************************
1949 * SetUrlCacheEntryInfoW (WININET.@)
1951 BOOL WINAPI
SetUrlCacheEntryInfoW(LPCWSTR lpszUrl
, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
, DWORD dwFieldControl
)
1953 LPURLCACHE_HEADER pHeader
;
1954 struct _HASH_ENTRY
* pHashEntry
;
1955 CACHEFILE_ENTRY
* pEntry
;
1956 URLCACHECONTAINER
* pContainer
;
1959 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl
), lpCacheEntryInfo
, dwFieldControl
);
1961 error
= URLCacheContainers_FindContainerW(lpszUrl
, &pContainer
);
1962 if (error
!= ERROR_SUCCESS
)
1964 SetLastError(error
);
1968 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
1969 if (error
!= ERROR_SUCCESS
)
1971 SetLastError(error
);
1975 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1978 if (!URLCache_FindHashW(pHeader
, lpszUrl
, &pHashEntry
))
1980 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1981 WARN("entry %s not found!\n", debugstr_w(lpszUrl
));
1982 SetLastError(ERROR_FILE_NOT_FOUND
);
1986 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1987 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1989 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1990 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1991 SetLastError(ERROR_FILE_NOT_FOUND
);
1995 URLCache_SetEntryInfo(
1996 (URL_CACHEFILE_ENTRY
*)pEntry
,
2000 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2005 /***********************************************************************
2006 * RetrieveUrlCacheEntryFileA (WININET.@)
2009 BOOL WINAPI
RetrieveUrlCacheEntryFileA(
2010 IN LPCSTR lpszUrlName
,
2011 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
2012 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
2016 LPURLCACHE_HEADER pHeader
;
2017 struct _HASH_ENTRY
* pHashEntry
;
2018 CACHEFILE_ENTRY
* pEntry
;
2019 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2020 URLCACHECONTAINER
* pContainer
;
2023 TRACE("(%s, %p, %p, 0x%08x)\n",
2024 debugstr_a(lpszUrlName
),
2026 lpdwCacheEntryInfoBufferSize
,
2029 if (!lpszUrlName
|| !lpdwCacheEntryInfoBufferSize
||
2030 (!lpCacheEntryInfo
&& *lpdwCacheEntryInfoBufferSize
))
2032 SetLastError(ERROR_INVALID_PARAMETER
);
2036 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
2037 if (error
!= ERROR_SUCCESS
)
2039 SetLastError(error
);
2043 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2044 if (error
!= ERROR_SUCCESS
)
2046 SetLastError(error
);
2050 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2053 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
2055 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2056 TRACE("entry %s not found!\n", lpszUrlName
);
2057 SetLastError(ERROR_FILE_NOT_FOUND
);
2061 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2062 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2064 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2065 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2066 SetLastError(ERROR_FILE_NOT_FOUND
);
2070 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2071 if (!pUrlEntry
->dwOffsetLocalName
)
2073 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2074 SetLastError(ERROR_INVALID_DATA
);
2078 TRACE("Found URL: %s\n", (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
2079 TRACE("Header info: %s\n", (LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
);
2081 error
= URLCache_CopyEntry(pContainer
, pHeader
, lpCacheEntryInfo
,
2082 lpdwCacheEntryInfoBufferSize
, pUrlEntry
,
2084 if (error
!= ERROR_SUCCESS
)
2086 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2087 SetLastError(error
);
2090 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
2092 pUrlEntry
->dwHitRate
++;
2093 pUrlEntry
->dwUseCount
++;
2094 URLCache_HashEntrySetFlags(pHashEntry
, HASHTABLE_LOCK
);
2095 GetSystemTimeAsFileTime(&pUrlEntry
->LastAccessTime
);
2097 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2102 /***********************************************************************
2103 * RetrieveUrlCacheEntryFileW (WININET.@)
2106 BOOL WINAPI
RetrieveUrlCacheEntryFileW(
2107 IN LPCWSTR lpszUrlName
,
2108 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
2109 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
2113 LPURLCACHE_HEADER pHeader
;
2114 struct _HASH_ENTRY
* pHashEntry
;
2115 CACHEFILE_ENTRY
* pEntry
;
2116 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2117 URLCACHECONTAINER
* pContainer
;
2120 TRACE("(%s, %p, %p, 0x%08x)\n",
2121 debugstr_w(lpszUrlName
),
2123 lpdwCacheEntryInfoBufferSize
,
2126 if (!lpszUrlName
|| !lpdwCacheEntryInfoBufferSize
||
2127 (!lpCacheEntryInfo
&& *lpdwCacheEntryInfoBufferSize
))
2129 SetLastError(ERROR_INVALID_PARAMETER
);
2133 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2134 if (error
!= ERROR_SUCCESS
)
2136 SetLastError(error
);
2140 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2141 if (error
!= ERROR_SUCCESS
)
2143 SetLastError(error
);
2147 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2150 if (!URLCache_FindHashW(pHeader
, lpszUrlName
, &pHashEntry
))
2152 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2153 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName
));
2154 SetLastError(ERROR_FILE_NOT_FOUND
);
2158 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2159 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2161 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2162 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2163 SetLastError(ERROR_FILE_NOT_FOUND
);
2167 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2168 if (!pUrlEntry
->dwOffsetLocalName
)
2170 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2171 SetLastError(ERROR_INVALID_DATA
);
2175 TRACE("Found URL: %s\n", (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
2176 TRACE("Header info: %s\n", (LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
);
2178 error
= URLCache_CopyEntry(
2181 (LPINTERNET_CACHE_ENTRY_INFOA
)lpCacheEntryInfo
,
2182 lpdwCacheEntryInfoBufferSize
,
2184 TRUE
/* UNICODE */);
2185 if (error
!= ERROR_SUCCESS
)
2187 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2188 SetLastError(error
);
2191 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
2193 pUrlEntry
->dwHitRate
++;
2194 pUrlEntry
->dwUseCount
++;
2195 URLCache_HashEntrySetFlags(pHashEntry
, HASHTABLE_LOCK
);
2196 GetSystemTimeAsFileTime(&pUrlEntry
->LastAccessTime
);
2198 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2203 static BOOL
DeleteUrlCacheEntryInternal(LPURLCACHE_HEADER pHeader
,
2204 struct _HASH_ENTRY
*pHashEntry
)
2206 CACHEFILE_ENTRY
* pEntry
;
2207 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2209 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2210 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2212 FIXME("Trying to delete entry of unknown format %s\n",
2213 debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2214 SetLastError(ERROR_FILE_NOT_FOUND
);
2218 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2219 if ((pHashEntry
->dwHashKey
& ((1<<HASHTABLE_FLAG_BITS
)-1)) == HASHTABLE_LOCK
)
2221 /* FIXME: implement timeout object unlocking */
2222 TRACE("Trying to delete locked entry\n");
2223 pUrlEntry
->CacheEntryType
|= DELETED_CACHE_ENTRY
;
2224 SetLastError(ERROR_SHARING_VIOLATION
);
2228 if (pUrlEntry
->CacheDir
< pHeader
->DirectoryCount
)
2230 if (pHeader
->directory_data
[pUrlEntry
->CacheDir
].dwNumFiles
)
2231 pHeader
->directory_data
[pUrlEntry
->CacheDir
].dwNumFiles
--;
2233 if (pUrlEntry
->CacheEntryType
& STICKY_CACHE_ENTRY
)
2235 if (pUrlEntry
->size
.QuadPart
< pHeader
->ExemptUsage
.QuadPart
)
2236 pHeader
->ExemptUsage
.QuadPart
-= pUrlEntry
->size
.QuadPart
;
2238 pHeader
->ExemptUsage
.QuadPart
= 0;
2242 if (pUrlEntry
->size
.QuadPart
< pHeader
->CacheUsage
.QuadPart
)
2243 pHeader
->CacheUsage
.QuadPart
-= pUrlEntry
->size
.QuadPart
;
2245 pHeader
->CacheUsage
.QuadPart
= 0;
2248 URLCache_DeleteEntry(pHeader
, pEntry
);
2250 URLCache_DeleteEntryFromHash(pHashEntry
);
2254 /***********************************************************************
2255 * UnlockUrlCacheEntryFileA (WININET.@)
2258 BOOL WINAPI
UnlockUrlCacheEntryFileA(
2259 IN LPCSTR lpszUrlName
,
2263 LPURLCACHE_HEADER pHeader
;
2264 struct _HASH_ENTRY
* pHashEntry
;
2265 CACHEFILE_ENTRY
* pEntry
;
2266 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2267 URLCACHECONTAINER
* pContainer
;
2270 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName
), dwReserved
);
2274 ERR("dwReserved != 0\n");
2275 SetLastError(ERROR_INVALID_PARAMETER
);
2279 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
2280 if (error
!= ERROR_SUCCESS
)
2282 SetLastError(error
);
2286 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2287 if (error
!= ERROR_SUCCESS
)
2289 SetLastError(error
);
2293 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2296 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
2298 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2299 TRACE("entry %s not found!\n", lpszUrlName
);
2300 SetLastError(ERROR_FILE_NOT_FOUND
);
2304 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2305 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2307 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2308 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2309 SetLastError(ERROR_FILE_NOT_FOUND
);
2313 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2315 if (pUrlEntry
->dwUseCount
== 0)
2317 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2320 pUrlEntry
->dwUseCount
--;
2321 if (!pUrlEntry
->dwUseCount
)
2323 URLCache_HashEntrySetFlags(pHashEntry
, HASHTABLE_URL
);
2324 if (pUrlEntry
->CacheEntryType
& DELETED_CACHE_ENTRY
)
2325 DeleteUrlCacheEntryInternal(pHeader
, pHashEntry
);
2328 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2333 /***********************************************************************
2334 * UnlockUrlCacheEntryFileW (WININET.@)
2337 BOOL WINAPI
UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName
, DWORD dwReserved
)
2339 LPURLCACHE_HEADER pHeader
;
2340 struct _HASH_ENTRY
* pHashEntry
;
2341 CACHEFILE_ENTRY
* pEntry
;
2342 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2343 URLCACHECONTAINER
* pContainer
;
2346 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName
), dwReserved
);
2350 ERR("dwReserved != 0\n");
2351 SetLastError(ERROR_INVALID_PARAMETER
);
2355 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2356 if (error
!= ERROR_SUCCESS
)
2358 SetLastError(error
);
2362 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2363 if (error
!= ERROR_SUCCESS
)
2365 SetLastError(error
);
2369 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2372 if (!URLCache_FindHashW(pHeader
, lpszUrlName
, &pHashEntry
))
2374 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2375 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName
));
2376 SetLastError(ERROR_FILE_NOT_FOUND
);
2380 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2381 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2383 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2384 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2385 SetLastError(ERROR_FILE_NOT_FOUND
);
2389 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2391 if (pUrlEntry
->dwUseCount
== 0)
2393 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2396 pUrlEntry
->dwUseCount
--;
2397 if (!pUrlEntry
->dwUseCount
)
2398 URLCache_HashEntrySetFlags(pHashEntry
, HASHTABLE_URL
);
2400 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2405 /***********************************************************************
2406 * CreateUrlCacheEntryA (WININET.@)
2409 BOOL WINAPI
CreateUrlCacheEntryA(
2410 IN LPCSTR lpszUrlName
,
2411 IN DWORD dwExpectedFileSize
,
2412 IN LPCSTR lpszFileExtension
,
2413 OUT LPSTR lpszFileName
,
2418 WCHAR
*file_extension
= NULL
;
2419 WCHAR file_name
[MAX_PATH
];
2420 BOOL bSuccess
= FALSE
;
2423 TRACE("(%s %d %s %p %d)\n", debugstr_a(lpszUrlName
), dwExpectedFileSize
,
2424 debugstr_a(lpszFileExtension
), lpszFileName
, dwReserved
);
2426 if (lpszUrlName
&& (url_name
= heap_strdupAtoW(lpszUrlName
)))
2428 if (!lpszFileExtension
|| (file_extension
= heap_strdupAtoW(lpszFileExtension
)))
2430 if (CreateUrlCacheEntryW(url_name
, dwExpectedFileSize
, file_extension
, file_name
, dwReserved
))
2432 if (WideCharToMultiByte(CP_ACP
, 0, file_name
, -1, lpszFileName
, MAX_PATH
, NULL
, NULL
) < MAX_PATH
)
2438 dwError
= GetLastError();
2443 dwError
= GetLastError();
2445 heap_free(file_extension
);
2449 dwError
= GetLastError();
2451 heap_free(url_name
);
2452 if (!bSuccess
) SetLastError(dwError
);
2456 /***********************************************************************
2457 * CreateUrlCacheEntryW (WININET.@)
2460 BOOL WINAPI
CreateUrlCacheEntryW(
2461 IN LPCWSTR lpszUrlName
,
2462 IN DWORD dwExpectedFileSize
,
2463 IN LPCWSTR lpszFileExtension
,
2464 OUT LPWSTR lpszFileName
,
2468 URLCACHECONTAINER
* pContainer
;
2469 LPURLCACHE_HEADER pHeader
;
2470 CHAR szFile
[MAX_PATH
];
2471 WCHAR szExtension
[MAX_PATH
];
2472 LPCWSTR lpszUrlPart
;
2474 LPCWSTR lpszFileNameExtension
;
2475 LPWSTR lpszFileNameNoPath
;
2477 int countnoextension
;
2480 BOOL bFound
= FALSE
;
2486 static const WCHAR szWWW
[] = {'w','w','w',0};
2487 static const WCHAR fmt
[] = {'%','0','8','X','%','s',0};
2489 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2490 debugstr_w(lpszUrlName
),
2492 debugstr_w(lpszFileExtension
),
2497 FIXME("dwReserved 0x%08x\n", dwReserved
);
2499 lpszUrlEnd
= lpszUrlName
+ strlenW(lpszUrlName
);
2501 if (((lpszUrlEnd
- lpszUrlName
) > 1) && (*(lpszUrlEnd
- 1) == '/' || *(lpszUrlEnd
- 1) == '\\'))
2504 lpszUrlPart
= memchrW(lpszUrlName
, '?', lpszUrlEnd
- lpszUrlName
);
2506 lpszUrlPart
= memchrW(lpszUrlName
, '#', lpszUrlEnd
- lpszUrlName
);
2508 lpszUrlEnd
= lpszUrlPart
;
2510 for (lpszUrlPart
= lpszUrlEnd
;
2511 (lpszUrlPart
>= lpszUrlName
);
2514 if ((*lpszUrlPart
== '/' || *lpszUrlPart
== '\\') && ((lpszUrlEnd
- lpszUrlPart
) > 1))
2521 if (!lstrcmpW(lpszUrlPart
, szWWW
))
2523 lpszUrlPart
+= lstrlenW(szWWW
);
2526 count
= lpszUrlEnd
- lpszUrlPart
;
2528 if (bFound
&& (count
< MAX_PATH
))
2530 int len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlPart
, count
, szFile
, sizeof(szFile
) - 1, NULL
, NULL
);
2534 while(len
&& szFile
[--len
] == '/') szFile
[len
] = '\0';
2536 /* FIXME: get rid of illegal characters like \, / and : */
2540 FIXME("need to generate a random filename\n");
2543 TRACE("File name: %s\n", debugstr_a(szFile
));
2545 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2546 if (error
!= ERROR_SUCCESS
)
2548 SetLastError(error
);
2552 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2553 if (error
!= ERROR_SUCCESS
)
2555 SetLastError(error
);
2559 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2562 CacheDir
= (BYTE
)(rand() % pHeader
->DirectoryCount
);
2564 lBufferSize
= MAX_PATH
* sizeof(WCHAR
);
2565 if (!URLCache_LocalFileNameToPathW(pContainer
, pHeader
, szFile
, CacheDir
, lpszFileName
, &lBufferSize
))
2567 WARN("Failed to get full path for filename %s, needed %u bytes.\n",
2568 debugstr_a(szFile
), lBufferSize
);
2569 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2573 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2575 for (lpszFileNameNoPath
= lpszFileName
+ lBufferSize
/ sizeof(WCHAR
) - 2;
2576 lpszFileNameNoPath
>= lpszFileName
;
2577 --lpszFileNameNoPath
)
2579 if (*lpszFileNameNoPath
== '/' || *lpszFileNameNoPath
== '\\')
2583 countnoextension
= lstrlenW(lpszFileNameNoPath
);
2584 lpszFileNameExtension
= PathFindExtensionW(lpszFileNameNoPath
);
2585 if (lpszFileNameExtension
)
2586 countnoextension
-= lstrlenW(lpszFileNameExtension
);
2587 *szExtension
= '\0';
2589 if (lpszFileExtension
)
2591 szExtension
[0] = '.';
2592 lstrcpyW(szExtension
+1, lpszFileExtension
);
2595 for (i
= 0; i
< 255; i
++)
2597 static const WCHAR szFormat
[] = {'[','%','u',']','%','s',0};
2600 wsprintfW(lpszFileNameNoPath
+ countnoextension
, szFormat
, i
, szExtension
);
2601 for (p
= lpszFileNameNoPath
+ 1; *p
; p
++)
2607 case '/': case '\\':
2614 if (p
[-1] == ' ' || p
[-1] == '.') p
[-1] = '_';
2616 TRACE("Trying: %s\n", debugstr_w(lpszFileName
));
2617 hFile
= CreateFileW(lpszFileName
, GENERIC_READ
, 0, NULL
, CREATE_NEW
, 0, NULL
);
2618 if (hFile
!= INVALID_HANDLE_VALUE
)
2625 GetSystemTimeAsFileTime(&ft
);
2626 wsprintfW(lpszFileNameNoPath
+ countnoextension
, fmt
, ft
.dwLowDateTime
, szExtension
);
2628 TRACE("Trying: %s\n", debugstr_w(lpszFileName
));
2629 hFile
= CreateFileW(lpszFileName
, GENERIC_READ
, 0, NULL
, CREATE_NEW
, 0, NULL
);
2630 if (hFile
!= INVALID_HANDLE_VALUE
)
2636 WARN("Could not find a unique filename\n");
2641 /***********************************************************************
2642 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2644 * The bug we are compensating for is that some drongo at Microsoft
2645 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2646 * As a consequence, CommitUrlCacheEntryA has been effectively
2647 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2648 * is still defined as LPCWSTR. The result (other than madness) is
2649 * that we always need to store lpHeaderInfo in CP_ACP rather than
2650 * in UTF16, and we need to avoid converting lpHeaderInfo in
2651 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2652 * result will lose data for arbitrary binary data.
2655 static BOOL
CommitUrlCacheEntryInternal(
2656 IN LPCWSTR lpszUrlName
,
2657 IN LPCWSTR lpszLocalFileName
,
2658 IN FILETIME ExpireTime
,
2659 IN FILETIME LastModifiedTime
,
2660 IN DWORD CacheEntryType
,
2661 IN LPBYTE lpHeaderInfo
,
2662 IN DWORD dwHeaderSize
,
2663 IN LPCWSTR lpszFileExtension
,
2664 IN LPCWSTR lpszOriginalUrl
2667 URLCACHECONTAINER
* pContainer
;
2668 LPURLCACHE_HEADER pHeader
;
2669 struct _HASH_ENTRY
* pHashEntry
;
2670 CACHEFILE_ENTRY
* pEntry
;
2671 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2672 DWORD url_entry_offset
;
2673 DWORD dwBytesNeeded
= DWORD_ALIGN(sizeof(*pUrlEntry
));
2674 DWORD dwOffsetLocalFileName
= 0;
2675 DWORD dwOffsetHeader
= 0;
2676 DWORD dwOffsetFileExtension
= 0;
2677 LARGE_INTEGER file_size
;
2678 BYTE cDirectory
= 0;
2679 char achFile
[MAX_PATH
];
2680 LPSTR lpszUrlNameA
= NULL
;
2681 LPSTR lpszFileExtensionA
= NULL
;
2682 char *pchLocalFileName
= 0;
2685 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2686 debugstr_w(lpszUrlName
),
2687 debugstr_w(lpszLocalFileName
),
2691 debugstr_w(lpszFileExtension
),
2692 debugstr_w(lpszOriginalUrl
));
2694 if (CacheEntryType
& STICKY_CACHE_ENTRY
&& !lpszLocalFileName
)
2696 SetLastError(ERROR_INVALID_PARAMETER
);
2699 if (lpszOriginalUrl
)
2700 WARN(": lpszOriginalUrl ignored\n");
2702 file_size
.QuadPart
= 0;
2703 if (lpszLocalFileName
)
2707 hFile
= CreateFileW(lpszLocalFileName
, FILE_READ_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2708 if (hFile
== INVALID_HANDLE_VALUE
)
2710 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName
), GetLastError());
2715 if (!GetFileSizeEx(hFile
, &file_size
))
2717 ERR("couldn't get file size (error is %d)\n", GetLastError());
2725 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2726 if (error
!= ERROR_SUCCESS
)
2728 SetLastError(error
);
2732 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2733 if (error
!= ERROR_SUCCESS
)
2735 SetLastError(error
);
2739 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2742 lpszUrlNameA
= heap_strdupWtoA(lpszUrlName
);
2745 error
= GetLastError();
2749 if (lpszFileExtension
&& !(lpszFileExtensionA
= heap_strdupWtoA(lpszFileExtension
)))
2751 error
= GetLastError();
2755 if (URLCache_FindHash(pHeader
, lpszUrlNameA
, &pHashEntry
))
2757 if ((pHashEntry
->dwHashKey
& ((1<<HASHTABLE_FLAG_BITS
)-1)) == HASHTABLE_LOCK
)
2759 /* FIXME: implement timeout object unlocking */
2760 FIXME("Trying to overwrite locked entry\n");
2761 SetLastError(ERROR_SHARING_VIOLATION
);
2765 FIXME("entry already in cache - don't know what to do!\n");
2767 * SetLastError(ERROR_FILE_NOT_FOUND);
2773 if (lpszLocalFileName
)
2775 BOOL bFound
= FALSE
;
2777 if (strncmpW(lpszLocalFileName
, pContainer
->path
, lstrlenW(pContainer
->path
)))
2779 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName
), debugstr_w(pContainer
->path
));
2780 error
= ERROR_INVALID_PARAMETER
;
2784 /* skip container path prefix */
2785 lpszLocalFileName
+= lstrlenW(pContainer
->path
);
2787 WideCharToMultiByte(CP_ACP
, 0, lpszLocalFileName
, -1, achFile
, MAX_PATH
, NULL
, NULL
);
2788 pchLocalFileName
= achFile
;
2790 for (cDirectory
= 0; cDirectory
< pHeader
->DirectoryCount
; cDirectory
++)
2792 if (!strncmp(pHeader
->directory_data
[cDirectory
].filename
, pchLocalFileName
, DIR_LENGTH
))
2801 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName
));
2802 error
= ERROR_INVALID_PARAMETER
;
2806 lpszLocalFileName
+= DIR_LENGTH
+ 1;
2807 pchLocalFileName
+= DIR_LENGTH
+ 1;
2810 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(lpszUrlNameA
) + 1);
2811 if (lpszLocalFileName
)
2813 dwOffsetLocalFileName
= dwBytesNeeded
;
2814 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(pchLocalFileName
) + 1);
2818 dwOffsetHeader
= dwBytesNeeded
;
2819 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ dwHeaderSize
);
2821 if (lpszFileExtensionA
)
2823 dwOffsetFileExtension
= dwBytesNeeded
;
2824 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(lpszFileExtensionA
) + 1);
2827 /* round up to next block */
2828 if (dwBytesNeeded
% BLOCKSIZE
)
2830 dwBytesNeeded
-= dwBytesNeeded
% BLOCKSIZE
;
2831 dwBytesNeeded
+= BLOCKSIZE
;
2834 error
= URLCache_FindFirstFreeEntry(pHeader
, dwBytesNeeded
/ BLOCKSIZE
, &pEntry
);
2835 while (error
== ERROR_HANDLE_DISK_FULL
)
2837 error
= URLCacheContainer_CleanIndex(pContainer
, &pHeader
);
2838 if (error
== ERROR_SUCCESS
)
2839 error
= URLCache_FindFirstFreeEntry(pHeader
, dwBytesNeeded
/ BLOCKSIZE
, &pEntry
);
2841 if (error
!= ERROR_SUCCESS
)
2844 /* FindFirstFreeEntry fills in blocks used */
2845 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2846 url_entry_offset
= (LPBYTE
)pUrlEntry
- (LPBYTE
)pHeader
;
2847 pUrlEntry
->CacheFileEntry
.dwSignature
= URL_SIGNATURE
;
2848 pUrlEntry
->CacheDir
= cDirectory
;
2849 pUrlEntry
->CacheEntryType
= CacheEntryType
;
2850 pUrlEntry
->dwHeaderInfoSize
= dwHeaderSize
;
2851 if (CacheEntryType
& STICKY_CACHE_ENTRY
)
2853 /* Sticky entries have a default exempt time of one day */
2854 pUrlEntry
->dwExemptDelta
= 86400;
2857 pUrlEntry
->dwExemptDelta
= 0;
2858 pUrlEntry
->dwHitRate
= 0;
2859 pUrlEntry
->dwOffsetFileExtension
= dwOffsetFileExtension
;
2860 pUrlEntry
->dwOffsetHeaderInfo
= dwOffsetHeader
;
2861 pUrlEntry
->dwOffsetLocalName
= dwOffsetLocalFileName
;
2862 pUrlEntry
->dwOffsetUrl
= DWORD_ALIGN(sizeof(*pUrlEntry
));
2863 pUrlEntry
->size
.QuadPart
= file_size
.QuadPart
;
2864 pUrlEntry
->dwUseCount
= 0;
2865 GetSystemTimeAsFileTime(&pUrlEntry
->LastAccessTime
);
2866 pUrlEntry
->LastModifiedTime
= LastModifiedTime
;
2867 URLCache_FileTimeToDosDateTime(&pUrlEntry
->LastAccessTime
, &pUrlEntry
->wLastSyncDate
, &pUrlEntry
->wLastSyncTime
);
2868 URLCache_FileTimeToDosDateTime(&ExpireTime
, &pUrlEntry
->wExpiredDate
, &pUrlEntry
->wExpiredTime
);
2869 pUrlEntry
->wUnknownDate
= pUrlEntry
->wLastSyncDate
;
2870 pUrlEntry
->wUnknownTime
= pUrlEntry
->wLastSyncTime
;
2873 pUrlEntry
->dwUnknown1
= 0;
2874 pUrlEntry
->dwUnknown2
= 0;
2875 pUrlEntry
->dwUnknown3
= 0x60;
2876 pUrlEntry
->Unknown4
= 0;
2877 pUrlEntry
->wUnknown5
= 0x1010;
2878 pUrlEntry
->dwUnknown7
= 0;
2879 pUrlEntry
->dwUnknown8
= 0;
2882 strcpy((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, lpszUrlNameA
);
2883 if (dwOffsetLocalFileName
)
2884 strcpy((LPSTR
)((LPBYTE
)pUrlEntry
+ dwOffsetLocalFileName
), pchLocalFileName
);
2886 memcpy((LPBYTE
)pUrlEntry
+ dwOffsetHeader
, lpHeaderInfo
, dwHeaderSize
);
2887 if (dwOffsetFileExtension
)
2888 strcpy((LPSTR
)((LPBYTE
)pUrlEntry
+ dwOffsetFileExtension
), lpszFileExtensionA
);
2890 error
= URLCache_AddEntryToHash(pHeader
, lpszUrlNameA
, url_entry_offset
, HASHTABLE_URL
);
2891 while (error
== ERROR_HANDLE_DISK_FULL
)
2893 error
= URLCacheContainer_CleanIndex(pContainer
, &pHeader
);
2894 if (error
== ERROR_SUCCESS
)
2896 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ url_entry_offset
);
2897 error
= URLCache_AddEntryToHash(pHeader
, lpszUrlNameA
,
2898 url_entry_offset
, HASHTABLE_URL
);
2901 if (error
!= ERROR_SUCCESS
)
2902 URLCache_DeleteEntry(pHeader
, &pUrlEntry
->CacheFileEntry
);
2905 if (pUrlEntry
->CacheDir
< pHeader
->DirectoryCount
)
2906 pHeader
->directory_data
[pUrlEntry
->CacheDir
].dwNumFiles
++;
2907 if (CacheEntryType
& STICKY_CACHE_ENTRY
)
2908 pHeader
->ExemptUsage
.QuadPart
+= file_size
.QuadPart
;
2910 pHeader
->CacheUsage
.QuadPart
+= file_size
.QuadPart
;
2911 if (pHeader
->CacheUsage
.QuadPart
+ pHeader
->ExemptUsage
.QuadPart
>
2912 pHeader
->CacheLimit
.QuadPart
)
2913 FIXME("file of size %s bytes fills cache\n", wine_dbgstr_longlong(file_size
.QuadPart
));
2917 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2918 heap_free(lpszUrlNameA
);
2919 heap_free(lpszFileExtensionA
);
2921 if (error
== ERROR_SUCCESS
)
2925 SetLastError(error
);
2930 /***********************************************************************
2931 * CommitUrlCacheEntryA (WININET.@)
2934 BOOL WINAPI
CommitUrlCacheEntryA(
2935 IN LPCSTR lpszUrlName
,
2936 IN LPCSTR lpszLocalFileName
,
2937 IN FILETIME ExpireTime
,
2938 IN FILETIME LastModifiedTime
,
2939 IN DWORD CacheEntryType
,
2940 IN LPBYTE lpHeaderInfo
,
2941 IN DWORD dwHeaderSize
,
2942 IN LPCSTR lpszFileExtension
,
2943 IN LPCSTR lpszOriginalUrl
2946 WCHAR
*url_name
= NULL
;
2947 WCHAR
*local_file_name
= NULL
;
2948 WCHAR
*original_url
= NULL
;
2949 WCHAR
*file_extension
= NULL
;
2950 BOOL bSuccess
= FALSE
;
2952 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2953 debugstr_a(lpszUrlName
),
2954 debugstr_a(lpszLocalFileName
),
2958 debugstr_a(lpszFileExtension
),
2959 debugstr_a(lpszOriginalUrl
));
2961 url_name
= heap_strdupAtoW(lpszUrlName
);
2965 if (lpszLocalFileName
)
2967 local_file_name
= heap_strdupAtoW(lpszLocalFileName
);
2968 if (!local_file_name
)
2971 if (lpszFileExtension
)
2973 file_extension
= heap_strdupAtoW(lpszFileExtension
);
2974 if (!file_extension
)
2977 if (lpszOriginalUrl
)
2979 original_url
= heap_strdupAtoW(lpszOriginalUrl
);
2984 bSuccess
= CommitUrlCacheEntryInternal(url_name
, local_file_name
, ExpireTime
, LastModifiedTime
,
2985 CacheEntryType
, lpHeaderInfo
, dwHeaderSize
,
2986 file_extension
, original_url
);
2989 heap_free(original_url
);
2990 heap_free(file_extension
);
2991 heap_free(local_file_name
);
2992 heap_free(url_name
);
2996 /***********************************************************************
2997 * CommitUrlCacheEntryW (WININET.@)
3000 BOOL WINAPI
CommitUrlCacheEntryW(
3001 IN LPCWSTR lpszUrlName
,
3002 IN LPCWSTR lpszLocalFileName
,
3003 IN FILETIME ExpireTime
,
3004 IN FILETIME LastModifiedTime
,
3005 IN DWORD CacheEntryType
,
3006 IN LPWSTR lpHeaderInfo
,
3007 IN DWORD dwHeaderSize
,
3008 IN LPCWSTR lpszFileExtension
,
3009 IN LPCWSTR lpszOriginalUrl
3013 BOOL bSuccess
= FALSE
;
3015 CHAR
*header_info
= NULL
;
3017 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
3018 debugstr_w(lpszUrlName
),
3019 debugstr_w(lpszLocalFileName
),
3023 debugstr_w(lpszFileExtension
),
3024 debugstr_w(lpszOriginalUrl
));
3026 if (!lpHeaderInfo
|| (header_info
= heap_strdupWtoA(lpHeaderInfo
)))
3028 if (CommitUrlCacheEntryInternal(lpszUrlName
, lpszLocalFileName
, ExpireTime
, LastModifiedTime
,
3029 CacheEntryType
, (LPBYTE
)header_info
, len
, lpszFileExtension
, lpszOriginalUrl
))
3035 dwError
= GetLastError();
3039 heap_free(header_info
);
3041 SetLastError(dwError
);
3047 /***********************************************************************
3048 * ReadUrlCacheEntryStream (WININET.@)
3051 BOOL WINAPI
ReadUrlCacheEntryStream(
3052 IN HANDLE hUrlCacheStream
,
3053 IN DWORD dwLocation
,
3054 IN OUT LPVOID lpBuffer
,
3055 IN OUT LPDWORD lpdwLen
,
3059 /* Get handle to file from 'stream' */
3060 STREAM_HANDLE
* pStream
= (STREAM_HANDLE
*)hUrlCacheStream
;
3062 if (dwReserved
!= 0)
3064 ERR("dwReserved != 0\n");
3065 SetLastError(ERROR_INVALID_PARAMETER
);
3069 if (IsBadReadPtr(pStream
, sizeof(*pStream
)) || IsBadStringPtrA(pStream
->lpszUrl
, INTERNET_MAX_URL_LENGTH
))
3071 SetLastError(ERROR_INVALID_HANDLE
);
3075 if (SetFilePointer(pStream
->hFile
, dwLocation
, NULL
, FILE_CURRENT
) == INVALID_SET_FILE_POINTER
)
3077 return ReadFile(pStream
->hFile
, lpBuffer
, *lpdwLen
, lpdwLen
, NULL
);
3080 /***********************************************************************
3081 * RetrieveUrlCacheEntryStreamA (WININET.@)
3084 HANDLE WINAPI
RetrieveUrlCacheEntryStreamA(
3085 IN LPCSTR lpszUrlName
,
3086 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
3087 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
3088 IN BOOL fRandomRead
,
3092 /* NOTE: this is not the same as the way that the native
3093 * version allocates 'stream' handles. I did it this way
3094 * as it is much easier and no applications should depend
3095 * on this behaviour. (Native version appears to allocate
3096 * indices into a table)
3098 STREAM_HANDLE
* pStream
;
3101 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
,
3102 lpdwCacheEntryInfoBufferSize
, fRandomRead
, dwReserved
);
3104 if (!RetrieveUrlCacheEntryFileA(lpszUrlName
,
3106 lpdwCacheEntryInfoBufferSize
,
3112 hFile
= CreateFileA(lpCacheEntryInfo
->lpszLocalFileName
,
3117 fRandomRead
? FILE_FLAG_RANDOM_ACCESS
: 0,
3119 if (hFile
== INVALID_HANDLE_VALUE
)
3122 /* allocate handle storage space */
3123 pStream
= heap_alloc(sizeof(STREAM_HANDLE
) + strlen(lpszUrlName
) * sizeof(CHAR
));
3127 SetLastError(ERROR_OUTOFMEMORY
);
3131 pStream
->hFile
= hFile
;
3132 strcpy(pStream
->lpszUrl
, lpszUrlName
);
3136 /***********************************************************************
3137 * RetrieveUrlCacheEntryStreamW (WININET.@)
3140 HANDLE WINAPI
RetrieveUrlCacheEntryStreamW(
3141 IN LPCWSTR lpszUrlName
,
3142 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
3143 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
3144 IN BOOL fRandomRead
,
3150 /* NOTE: this is not the same as the way that the native
3151 * version allocates 'stream' handles. I did it this way
3152 * as it is much easier and no applications should depend
3153 * on this behaviour. (Native version appears to allocate
3154 * indices into a table)
3156 STREAM_HANDLE
* pStream
;
3159 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName
), lpCacheEntryInfo
,
3160 lpdwCacheEntryInfoBufferSize
, fRandomRead
, dwReserved
);
3162 if (!RetrieveUrlCacheEntryFileW(lpszUrlName
,
3164 lpdwCacheEntryInfoBufferSize
,
3170 hFile
= CreateFileW(lpCacheEntryInfo
->lpszLocalFileName
,
3175 fRandomRead
? FILE_FLAG_RANDOM_ACCESS
: 0,
3177 if (hFile
== INVALID_HANDLE_VALUE
)
3180 /* allocate handle storage space */
3181 size
= sizeof(STREAM_HANDLE
);
3182 url_len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, NULL
, 0, NULL
, NULL
);
3184 pStream
= heap_alloc(size
);
3188 SetLastError(ERROR_OUTOFMEMORY
);
3192 pStream
->hFile
= hFile
;
3193 WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, pStream
->lpszUrl
, url_len
, NULL
, NULL
);
3197 /***********************************************************************
3198 * UnlockUrlCacheEntryStream (WININET.@)
3201 BOOL WINAPI
UnlockUrlCacheEntryStream(
3202 IN HANDLE hUrlCacheStream
,
3206 STREAM_HANDLE
* pStream
= (STREAM_HANDLE
*)hUrlCacheStream
;
3208 if (dwReserved
!= 0)
3210 ERR("dwReserved != 0\n");
3211 SetLastError(ERROR_INVALID_PARAMETER
);
3215 if (IsBadReadPtr(pStream
, sizeof(*pStream
)) || IsBadStringPtrA(pStream
->lpszUrl
, INTERNET_MAX_URL_LENGTH
))
3217 SetLastError(ERROR_INVALID_HANDLE
);
3221 if (!UnlockUrlCacheEntryFileA(pStream
->lpszUrl
, 0))
3224 CloseHandle(pStream
->hFile
);
3230 /***********************************************************************
3231 * DeleteUrlCacheEntryA (WININET.@)
3234 BOOL WINAPI
DeleteUrlCacheEntryA(LPCSTR lpszUrlName
)
3236 URLCACHECONTAINER
* pContainer
;
3237 LPURLCACHE_HEADER pHeader
;
3238 struct _HASH_ENTRY
* pHashEntry
;
3242 TRACE("(%s)\n", debugstr_a(lpszUrlName
));
3244 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
3245 if (error
!= ERROR_SUCCESS
)
3247 SetLastError(error
);
3251 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
3252 if (error
!= ERROR_SUCCESS
)
3254 SetLastError(error
);
3258 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3261 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
3263 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3264 TRACE("entry %s not found!\n", lpszUrlName
);
3265 SetLastError(ERROR_FILE_NOT_FOUND
);
3269 ret
= DeleteUrlCacheEntryInternal(pHeader
, pHashEntry
);
3271 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3276 /***********************************************************************
3277 * DeleteUrlCacheEntryW (WININET.@)
3280 BOOL WINAPI
DeleteUrlCacheEntryW(LPCWSTR lpszUrlName
)
3282 URLCACHECONTAINER
* pContainer
;
3283 LPURLCACHE_HEADER pHeader
;
3284 struct _HASH_ENTRY
* pHashEntry
;
3289 TRACE("(%s)\n", debugstr_w(lpszUrlName
));
3291 urlA
= heap_strdupWtoA(lpszUrlName
);
3294 SetLastError(ERROR_OUTOFMEMORY
);
3298 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
3299 if (error
!= ERROR_SUCCESS
)
3302 SetLastError(error
);
3306 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
3307 if (error
!= ERROR_SUCCESS
)
3310 SetLastError(error
);
3314 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3320 if (!URLCache_FindHash(pHeader
, urlA
, &pHashEntry
))
3322 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3323 TRACE("entry %s not found!\n", debugstr_a(urlA
));
3325 SetLastError(ERROR_FILE_NOT_FOUND
);
3329 ret
= DeleteUrlCacheEntryInternal(pHeader
, pHashEntry
);
3331 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3336 BOOL WINAPI
DeleteUrlCacheContainerA(DWORD d1
, DWORD d2
)
3338 FIXME("(0x%08x, 0x%08x) stub\n", d1
, d2
);
3342 BOOL WINAPI
DeleteUrlCacheContainerW(DWORD d1
, DWORD d2
)
3344 FIXME("(0x%08x, 0x%08x) stub\n", d1
, d2
);
3348 /***********************************************************************
3349 * CreateCacheContainerA (WININET.@)
3351 BOOL WINAPI
CreateUrlCacheContainerA(DWORD d1
, DWORD d2
, DWORD d3
, DWORD d4
,
3352 DWORD d5
, DWORD d6
, DWORD d7
, DWORD d8
)
3354 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3355 d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
);
3359 /***********************************************************************
3360 * CreateCacheContainerW (WININET.@)
3362 BOOL WINAPI
CreateUrlCacheContainerW(DWORD d1
, DWORD d2
, DWORD d3
, DWORD d4
,
3363 DWORD d5
, DWORD d6
, DWORD d7
, DWORD d8
)
3365 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3366 d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
);
3370 /***********************************************************************
3371 * FindFirstUrlCacheContainerA (WININET.@)
3373 HANDLE WINAPI
FindFirstUrlCacheContainerA( LPVOID p1
, LPVOID p2
, LPVOID p3
, DWORD d1
)
3375 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1
, p2
, p3
, d1
);
3379 /***********************************************************************
3380 * FindFirstUrlCacheContainerW (WININET.@)
3382 HANDLE WINAPI
FindFirstUrlCacheContainerW( LPVOID p1
, LPVOID p2
, LPVOID p3
, DWORD d1
)
3384 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1
, p2
, p3
, d1
);
3388 /***********************************************************************
3389 * FindNextUrlCacheContainerA (WININET.@)
3391 BOOL WINAPI
FindNextUrlCacheContainerA( HANDLE handle
, LPVOID p1
, LPVOID p2
)
3393 FIXME("(%p, %p, %p) stub\n", handle
, p1
, p2
);
3397 /***********************************************************************
3398 * FindNextUrlCacheContainerW (WININET.@)
3400 BOOL WINAPI
FindNextUrlCacheContainerW( HANDLE handle
, LPVOID p1
, LPVOID p2
)
3402 FIXME("(%p, %p, %p) stub\n", handle
, p1
, p2
);
3406 HANDLE WINAPI
FindFirstUrlCacheEntryExA(
3407 LPCSTR lpszUrlSearchPattern
,
3411 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
,
3412 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3414 LPDWORD pcbReserved2
,
3418 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern
),
3419 dwFlags
, dwFilter
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, lpFirstCacheEntryInfo
,
3420 lpdwFirstCacheEntryInfoBufferSize
, lpReserved
, pcbReserved2
,lpReserved3
);
3421 SetLastError(ERROR_FILE_NOT_FOUND
);
3425 HANDLE WINAPI
FindFirstUrlCacheEntryExW(
3426 LPCWSTR lpszUrlSearchPattern
,
3430 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
,
3431 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3433 LPDWORD pcbReserved2
,
3437 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern
),
3438 dwFlags
, dwFilter
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, lpFirstCacheEntryInfo
,
3439 lpdwFirstCacheEntryInfoBufferSize
, lpReserved
, pcbReserved2
,lpReserved3
);
3440 SetLastError(ERROR_FILE_NOT_FOUND
);
3444 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3446 typedef struct URLCacheFindEntryHandle
3449 LPWSTR lpszUrlSearchPattern
;
3450 DWORD dwContainerIndex
;
3451 DWORD dwHashTableIndex
;
3452 DWORD dwHashEntryIndex
;
3453 } URLCacheFindEntryHandle
;
3455 /***********************************************************************
3456 * FindFirstUrlCacheEntryA (WININET.@)
3459 INTERNETAPI HANDLE WINAPI
FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern
,
3460 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
, LPDWORD lpdwFirstCacheEntryInfoBufferSize
)
3462 URLCacheFindEntryHandle
*pEntryHandle
;
3464 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern
), lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
);
3466 pEntryHandle
= heap_alloc(sizeof(*pEntryHandle
));
3470 pEntryHandle
->dwMagic
= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
;
3471 if (lpszUrlSearchPattern
)
3473 pEntryHandle
->lpszUrlSearchPattern
= heap_strdupAtoW(lpszUrlSearchPattern
);
3474 if (!pEntryHandle
->lpszUrlSearchPattern
)
3476 heap_free(pEntryHandle
);
3481 pEntryHandle
->lpszUrlSearchPattern
= NULL
;
3482 pEntryHandle
->dwContainerIndex
= 0;
3483 pEntryHandle
->dwHashTableIndex
= 0;
3484 pEntryHandle
->dwHashEntryIndex
= 0;
3486 if (!FindNextUrlCacheEntryA(pEntryHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
))
3488 heap_free(pEntryHandle
);
3491 return pEntryHandle
;
3494 /***********************************************************************
3495 * FindFirstUrlCacheEntryW (WININET.@)
3498 INTERNETAPI HANDLE WINAPI
FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern
,
3499 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
, LPDWORD lpdwFirstCacheEntryInfoBufferSize
)
3501 URLCacheFindEntryHandle
*pEntryHandle
;
3503 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern
), lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
);
3505 pEntryHandle
= heap_alloc(sizeof(*pEntryHandle
));
3509 pEntryHandle
->dwMagic
= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
;
3510 if (lpszUrlSearchPattern
)
3512 pEntryHandle
->lpszUrlSearchPattern
= heap_strdupW(lpszUrlSearchPattern
);
3513 if (!pEntryHandle
->lpszUrlSearchPattern
)
3515 heap_free(pEntryHandle
);
3520 pEntryHandle
->lpszUrlSearchPattern
= NULL
;
3521 pEntryHandle
->dwContainerIndex
= 0;
3522 pEntryHandle
->dwHashTableIndex
= 0;
3523 pEntryHandle
->dwHashEntryIndex
= 0;
3525 if (!FindNextUrlCacheEntryW(pEntryHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
))
3527 heap_free(pEntryHandle
);
3530 return pEntryHandle
;
3533 static BOOL
FindNextUrlCacheEntryInternal(
3535 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo
,
3536 LPDWORD lpdwNextCacheEntryInfoBufferSize
,
3539 URLCacheFindEntryHandle
*pEntryHandle
= (URLCacheFindEntryHandle
*)hEnumHandle
;
3540 URLCACHECONTAINER
* pContainer
;
3542 if (pEntryHandle
->dwMagic
!= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
)
3544 SetLastError(ERROR_INVALID_HANDLE
);
3548 for (; URLCacheContainers_Enum(pEntryHandle
->lpszUrlSearchPattern
, pEntryHandle
->dwContainerIndex
, &pContainer
);
3549 pEntryHandle
->dwContainerIndex
++, pEntryHandle
->dwHashTableIndex
= 0)
3551 LPURLCACHE_HEADER pHeader
;
3552 HASH_CACHEFILE_ENTRY
*pHashTableEntry
;
3555 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
3556 if (error
!= ERROR_SUCCESS
)
3558 SetLastError(error
);
3562 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3565 for (; URLCache_EnumHashTables(pHeader
, &pEntryHandle
->dwHashTableIndex
, &pHashTableEntry
);
3566 pEntryHandle
->dwHashTableIndex
++, pEntryHandle
->dwHashEntryIndex
= 0)
3568 const struct _HASH_ENTRY
*pHashEntry
= NULL
;
3569 for (; URLCache_EnumHashTableEntries(pHeader
, pHashTableEntry
, &pEntryHandle
->dwHashEntryIndex
, &pHashEntry
);
3570 pEntryHandle
->dwHashEntryIndex
++)
3572 const URL_CACHEFILE_ENTRY
*pUrlEntry
;
3573 const CACHEFILE_ENTRY
*pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3575 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
3578 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
3579 TRACE("Found URL: %s\n",
3580 debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
));
3581 TRACE("Header info: %s\n",
3582 debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
3584 error
= URLCache_CopyEntry(
3587 lpNextCacheEntryInfo
,
3588 lpdwNextCacheEntryInfoBufferSize
,
3591 if (error
!= ERROR_SUCCESS
)
3593 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3594 SetLastError(error
);
3597 TRACE("Local File Name: %s\n",
3598 debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
3600 /* increment the current index so that next time the function
3601 * is called the next entry is returned */
3602 pEntryHandle
->dwHashEntryIndex
++;
3603 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3608 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3611 SetLastError(ERROR_NO_MORE_ITEMS
);
3615 /***********************************************************************
3616 * FindNextUrlCacheEntryA (WININET.@)
3618 BOOL WINAPI
FindNextUrlCacheEntryA(
3620 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo
,
3621 LPDWORD lpdwNextCacheEntryInfoBufferSize
)
3623 TRACE("(%p, %p, %p)\n", hEnumHandle
, lpNextCacheEntryInfo
, lpdwNextCacheEntryInfoBufferSize
);
3625 return FindNextUrlCacheEntryInternal(hEnumHandle
, lpNextCacheEntryInfo
,
3626 lpdwNextCacheEntryInfoBufferSize
, FALSE
/* not UNICODE */);
3629 /***********************************************************************
3630 * FindNextUrlCacheEntryW (WININET.@)
3632 BOOL WINAPI
FindNextUrlCacheEntryW(
3634 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo
,
3635 LPDWORD lpdwNextCacheEntryInfoBufferSize
3638 TRACE("(%p, %p, %p)\n", hEnumHandle
, lpNextCacheEntryInfo
, lpdwNextCacheEntryInfoBufferSize
);
3640 return FindNextUrlCacheEntryInternal(hEnumHandle
,
3641 (LPINTERNET_CACHE_ENTRY_INFOA
)lpNextCacheEntryInfo
,
3642 lpdwNextCacheEntryInfoBufferSize
, TRUE
/* UNICODE */);
3645 /***********************************************************************
3646 * FindCloseUrlCache (WININET.@)
3648 BOOL WINAPI
FindCloseUrlCache(HANDLE hEnumHandle
)
3650 URLCacheFindEntryHandle
*pEntryHandle
= (URLCacheFindEntryHandle
*)hEnumHandle
;
3652 TRACE("(%p)\n", hEnumHandle
);
3654 if (!pEntryHandle
|| pEntryHandle
->dwMagic
!= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
)
3656 SetLastError(ERROR_INVALID_HANDLE
);
3660 pEntryHandle
->dwMagic
= 0;
3661 heap_free(pEntryHandle
->lpszUrlSearchPattern
);
3662 heap_free(pEntryHandle
);
3666 HANDLE WINAPI
FindFirstUrlCacheGroup( DWORD dwFlags
, DWORD dwFilter
, LPVOID lpSearchCondition
,
3667 DWORD dwSearchCondition
, GROUPID
* lpGroupId
, LPVOID lpReserved
)
3669 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags
, dwFilter
, lpSearchCondition
,
3670 dwSearchCondition
, lpGroupId
, lpReserved
);
3674 BOOL WINAPI
FindNextUrlCacheEntryExA(
3676 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
,
3677 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3679 LPDWORD pcbReserved2
,
3683 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
,
3684 lpReserved
, pcbReserved2
, lpReserved3
);
3688 BOOL WINAPI
FindNextUrlCacheEntryExW(
3690 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
,
3691 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3693 LPDWORD pcbReserved2
,
3697 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
,
3698 lpReserved
, pcbReserved2
, lpReserved3
);
3702 BOOL WINAPI
FindNextUrlCacheGroup( HANDLE hFind
, GROUPID
* lpGroupId
, LPVOID lpReserved
)
3704 FIXME("(%p, %p, %p) stub\n", hFind
, lpGroupId
, lpReserved
);
3708 /***********************************************************************
3709 * CreateUrlCacheGroup (WININET.@)
3712 INTERNETAPI GROUPID WINAPI
CreateUrlCacheGroup(DWORD dwFlags
, LPVOID lpReserved
)
3714 FIXME("(0x%08x, %p): stub\n", dwFlags
, lpReserved
);
3718 /***********************************************************************
3719 * DeleteUrlCacheGroup (WININET.@)
3722 BOOL WINAPI
DeleteUrlCacheGroup(GROUPID GroupId
, DWORD dwFlags
, LPVOID lpReserved
)
3724 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3725 (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, dwFlags
, lpReserved
);
3729 /***********************************************************************
3730 * SetUrlCacheEntryGroupA (WININET.@)
3733 BOOL WINAPI
SetUrlCacheEntryGroupA(LPCSTR lpszUrlName
, DWORD dwFlags
,
3734 GROUPID GroupId
, LPBYTE pbGroupAttributes
, DWORD cbGroupAttributes
,
3737 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3738 debugstr_a(lpszUrlName
), dwFlags
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
,
3739 pbGroupAttributes
, cbGroupAttributes
, lpReserved
);
3740 SetLastError(ERROR_FILE_NOT_FOUND
);
3744 /***********************************************************************
3745 * SetUrlCacheEntryGroupW (WININET.@)
3748 BOOL WINAPI
SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName
, DWORD dwFlags
,
3749 GROUPID GroupId
, LPBYTE pbGroupAttributes
, DWORD cbGroupAttributes
,
3752 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3753 debugstr_w(lpszUrlName
), dwFlags
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
,
3754 pbGroupAttributes
, cbGroupAttributes
, lpReserved
);
3755 SetLastError(ERROR_FILE_NOT_FOUND
);
3759 /***********************************************************************
3760 * GetUrlCacheConfigInfoW (WININET.@)
3762 BOOL WINAPI
GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo
, LPDWORD size
, DWORD bitmask
)
3764 FIXME("(%p, %p, %x)\n", CacheInfo
, size
, bitmask
);
3765 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
3769 /***********************************************************************
3770 * GetUrlCacheConfigInfoA (WININET.@)
3772 BOOL WINAPI
GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo
, LPDWORD size
, DWORD bitmask
)
3774 FIXME("(%p, %p, %x)\n", CacheInfo
, size
, bitmask
);
3775 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
3779 BOOL WINAPI
GetUrlCacheGroupAttributeA( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3780 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo
,
3781 LPDWORD lpdwGroupInfo
, LPVOID lpReserved
)
3783 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3784 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
,
3785 lpdwGroupInfo
, lpReserved
);
3789 BOOL WINAPI
GetUrlCacheGroupAttributeW( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3790 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo
,
3791 LPDWORD lpdwGroupInfo
, LPVOID lpReserved
)
3793 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3794 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
,
3795 lpdwGroupInfo
, lpReserved
);
3799 BOOL WINAPI
SetUrlCacheGroupAttributeA( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3800 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo
, LPVOID lpReserved
)
3802 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3803 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
, lpReserved
);
3807 BOOL WINAPI
SetUrlCacheGroupAttributeW( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3808 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo
, LPVOID lpReserved
)
3810 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3811 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
, lpReserved
);
3815 BOOL WINAPI
SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo
, DWORD dwFieldControl
)
3817 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo
, dwFieldControl
);
3821 BOOL WINAPI
SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo
, DWORD dwFieldControl
)
3823 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo
, dwFieldControl
);
3827 /***********************************************************************
3828 * DeleteIE3Cache (WININET.@)
3830 * Deletes the files used by the IE3 URL caching system.
3833 * hWnd [I] A dummy window.
3834 * hInst [I] Instance of process calling the function.
3835 * lpszCmdLine [I] Options used by function.
3836 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3838 DWORD WINAPI
DeleteIE3Cache(HWND hWnd
, HINSTANCE hInst
, LPSTR lpszCmdLine
, int nCmdShow
)
3840 FIXME("(%p, %p, %s, %d)\n", hWnd
, hInst
, debugstr_a(lpszCmdLine
), nCmdShow
);
3844 static BOOL
IsUrlCacheEntryExpiredInternal(const URL_CACHEFILE_ENTRY
*pUrlEntry
,
3845 FILETIME
*pftLastModified
)
3848 FILETIME now
, expired
;
3850 *pftLastModified
= pUrlEntry
->LastModifiedTime
;
3851 GetSystemTimeAsFileTime(&now
);
3852 URLCache_DosDateTimeToFileTime(pUrlEntry
->wExpiredDate
,
3853 pUrlEntry
->wExpiredTime
, &expired
);
3854 /* If the expired time is 0, it's interpreted as not expired */
3855 if (!expired
.dwLowDateTime
&& !expired
.dwHighDateTime
)
3858 ret
= CompareFileTime(&expired
, &now
) < 0;
3862 /***********************************************************************
3863 * IsUrlCacheEntryExpiredA (WININET.@)
3867 * dwFlags [I] Unknown
3868 * pftLastModified [O] Last modified time
3870 BOOL WINAPI
IsUrlCacheEntryExpiredA( LPCSTR url
, DWORD dwFlags
, FILETIME
* pftLastModified
)
3872 LPURLCACHE_HEADER pHeader
;
3873 struct _HASH_ENTRY
* pHashEntry
;
3874 const CACHEFILE_ENTRY
* pEntry
;
3875 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
3876 URLCACHECONTAINER
* pContainer
;
3879 TRACE("(%s, %08x, %p)\n", debugstr_a(url
), dwFlags
, pftLastModified
);
3881 if (!url
|| !pftLastModified
)
3884 FIXME("unknown flags 0x%08x\n", dwFlags
);
3886 /* Any error implies that the URL is expired, i.e. not in the cache */
3887 if (URLCacheContainers_FindContainerA(url
, &pContainer
))
3889 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3893 if (URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
))
3895 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3899 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3901 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3905 if (!URLCache_FindHash(pHeader
, url
, &pHashEntry
))
3907 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3908 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3909 TRACE("entry %s not found!\n", url
);
3913 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3914 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
3916 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3917 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3918 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
3922 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
3923 expired
= IsUrlCacheEntryExpiredInternal(pUrlEntry
, pftLastModified
);
3925 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3930 /***********************************************************************
3931 * IsUrlCacheEntryExpiredW (WININET.@)
3935 * dwFlags [I] Unknown
3936 * pftLastModified [O] Last modified time
3938 BOOL WINAPI
IsUrlCacheEntryExpiredW( LPCWSTR url
, DWORD dwFlags
, FILETIME
* pftLastModified
)
3940 LPURLCACHE_HEADER pHeader
;
3941 struct _HASH_ENTRY
* pHashEntry
;
3942 const CACHEFILE_ENTRY
* pEntry
;
3943 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
3944 URLCACHECONTAINER
* pContainer
;
3947 TRACE("(%s, %08x, %p)\n", debugstr_w(url
), dwFlags
, pftLastModified
);
3949 if (!url
|| !pftLastModified
)
3952 FIXME("unknown flags 0x%08x\n", dwFlags
);
3954 /* Any error implies that the URL is expired, i.e. not in the cache */
3955 if (URLCacheContainers_FindContainerW(url
, &pContainer
))
3957 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3961 if (URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
))
3963 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3967 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3969 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3973 if (!URLCache_FindHashW(pHeader
, url
, &pHashEntry
))
3975 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3976 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3977 TRACE("entry %s not found!\n", debugstr_w(url
));
3981 if (!URLCache_FindHashW(pHeader
, url
, &pHashEntry
))
3983 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3984 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3985 TRACE("entry %s not found!\n", debugstr_w(url
));
3989 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3990 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
3992 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3993 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3994 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
3998 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
3999 expired
= IsUrlCacheEntryExpiredInternal(pUrlEntry
, pftLastModified
);
4001 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
4006 /***********************************************************************
4007 * GetDiskInfoA (WININET.@)
4009 BOOL WINAPI
GetDiskInfoA(PCSTR path
, PDWORD cluster_size
, PDWORDLONG free
, PDWORDLONG total
)
4012 ULARGE_INTEGER bytes_free
, bytes_total
;
4014 TRACE("(%s, %p, %p, %p)\n", debugstr_a(path
), cluster_size
, free
, total
);
4018 SetLastError(ERROR_INVALID_PARAMETER
);
4022 if ((ret
= GetDiskFreeSpaceExA(path
, NULL
, &bytes_total
, &bytes_free
)))
4024 if (cluster_size
) *cluster_size
= 1;
4025 if (free
) *free
= bytes_free
.QuadPart
;
4026 if (total
) *total
= bytes_total
.QuadPart
;
4031 /***********************************************************************
4032 * RegisterUrlCacheNotification (WININET.@)
4034 DWORD WINAPI
RegisterUrlCacheNotification(LPVOID a
, DWORD b
, DWORD c
, DWORD d
, DWORD e
, DWORD f
)
4036 FIXME("(%p %x %x %x %x %x)\n", a
, b
, c
, d
, e
, f
);
4040 /***********************************************************************
4041 * IncrementUrlCacheHeaderData (WININET.@)
4043 BOOL WINAPI
IncrementUrlCacheHeaderData(DWORD index
, LPDWORD data
)
4045 FIXME("(%u, %p)\n", index
, data
);
4049 /***********************************************************************
4050 * RunOnceUrlCache (WININET.@)
4053 DWORD WINAPI
RunOnceUrlCache(HWND hwnd
, HINSTANCE hinst
, LPSTR cmd
, int cmdshow
)
4055 FIXME("(%p, %p, %s, %d): stub\n", hwnd
, hinst
, debugstr_a(cmd
), cmdshow
);