2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003-2008 Robert Shearman
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
31 #if defined(__MINGW32__) || defined (_MSC_VER)
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
63 static const char urlcache_ver_prefix
[] = "WINE URLCache Ver ";
64 static const char urlcache_ver
[] = "0.2012001";
66 #define ENTRY_START_OFFSET 0x4000
68 #define MAX_DIR_NO 0x20
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 6
86 #define PENDING_DELETE_CACHE_ENTRY 0x00400000
87 #define INSTALLED_CACHE_ENTRY 0x10000000
88 #define GET_INSTALLED_ENTRY 0x200
89 #define CACHE_CONTAINER_NO_SUBDIR 0xFE
91 #define CACHE_HEADER_DATA_ROOT_LEAK_OFFSET 0x16
93 #define FILETIME_SECOND 10000000
95 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
96 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
97 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
98 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
99 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
101 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
103 typedef struct _CACHEFILE_ENTRY
107 DWORD dwSignature
; /* e.g. "URL " */
108 /* CHAR szSignature[4];
110 DWORD dwBlocksUsed
; /* number of 128byte blocks used by this entry */
113 typedef struct _URL_CACHEFILE_ENTRY
115 CACHEFILE_ENTRY CacheFileEntry
;
116 FILETIME LastModifiedTime
;
117 FILETIME LastAccessTime
;
118 WORD wExpiredDate
; /* expire date in dos format */
119 WORD wExpiredTime
; /* expire time in dos format */
120 DWORD dwUnknown1
; /* usually zero */
121 ULARGE_INTEGER size
; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow/High */
122 DWORD dwUnknown2
; /* usually zero */
123 DWORD dwExemptDelta
; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
124 DWORD dwUnknown3
; /* usually 0x60 */
125 DWORD dwOffsetUrl
; /* offset of start of url from start of entry */
126 BYTE CacheDir
; /* index of cache directory this url is stored in */
127 BYTE Unknown4
; /* usually zero */
128 WORD wUnknown5
; /* usually 0x1010 */
129 DWORD dwOffsetLocalName
; /* offset of start of local filename from start of entry */
130 DWORD CacheEntryType
; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
131 DWORD dwOffsetHeaderInfo
; /* offset of start of header info from start of entry */
132 DWORD dwHeaderInfoSize
;
133 DWORD dwOffsetFileExtension
; /* offset of start of file extension from start of entry */
134 WORD wLastSyncDate
; /* last sync date in dos format */
135 WORD wLastSyncTime
; /* last sync time in dos format */
136 DWORD dwHitRate
; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
137 DWORD dwUseCount
; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
140 DWORD dwUnknown7
; /* usually zero */
141 DWORD dwUnknown8
; /* usually zero */
142 /* packing to dword align start of next field */
143 /* CHAR szSourceUrlName[]; (url) */
144 /* packing to dword align start of next field */
145 /* CHAR szLocalFileName[]; (local file name excluding path) */
146 /* packing to dword align start of next field */
147 /* CHAR szHeaderInfo[]; (header info) */
148 } URL_CACHEFILE_ENTRY
;
156 typedef struct _HASH_CACHEFILE_ENTRY
158 CACHEFILE_ENTRY CacheFileEntry
;
160 DWORD dwHashTableNumber
;
161 struct _HASH_ENTRY HashTable
[HASHTABLE_SIZE
];
162 } HASH_CACHEFILE_ENTRY
;
164 typedef struct _DIRECTORY_DATA
167 char filename
[DIR_LENGTH
];
170 typedef struct _URLCACHE_HEADER
172 char szSignature
[28];
174 DWORD dwOffsetFirstHashTable
;
175 DWORD dwIndexCapacityInBlocks
;
178 ULARGE_INTEGER CacheLimit
;
179 ULARGE_INTEGER CacheUsage
;
180 ULARGE_INTEGER ExemptUsage
;
181 DWORD DirectoryCount
;
182 DIRECTORY_DATA directory_data
[MAX_DIR_NO
];
184 BYTE allocation_table
[ALLOCATION_TABLE_SIZE
];
185 } URLCACHE_HEADER
, *LPURLCACHE_HEADER
;
186 typedef const URLCACHE_HEADER
*LPCURLCACHE_HEADER
;
188 typedef struct _STREAM_HANDLE
194 typedef struct _URLCACHECONTAINER
196 struct list entry
; /* part of a list */
197 LPWSTR cache_prefix
; /* string that has to be prefixed for this container to be used */
198 LPWSTR path
; /* path to url container directory */
199 HANDLE hMapping
; /* handle of file mapping */
200 DWORD file_size
; /* size of file when mapping was opened */
201 HANDLE hMutex
; /* handle of mutex */
202 DWORD default_entry_type
;
206 /* List of all containers available */
207 static struct list UrlContainers
= LIST_INIT(UrlContainers
);
209 static DWORD
URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader
, HASH_CACHEFILE_ENTRY
*pPrevHash
, HASH_CACHEFILE_ENTRY
**ppHash
);
211 /***********************************************************************
212 * URLCache_PathToObjectName (Internal)
214 * Converts a path to a name suitable for use as a Win32 object name.
215 * Replaces '\\' characters in-place with the specified character
216 * (usually '_' or '!')
222 static void URLCache_PathToObjectName(LPWSTR lpszPath
, WCHAR replace
)
224 for (; *lpszPath
; lpszPath
++)
226 if (*lpszPath
== '\\')
231 /***********************************************************************
232 * URLCacheContainer_OpenIndex (Internal)
234 * Opens the index file and saves mapping handle in hCacheIndexMapping
237 * ERROR_SUCCESS if succeeded
238 * Any other Win32 error code if failed
241 static DWORD
URLCacheContainer_OpenIndex(URLCACHECONTAINER
* pContainer
, DWORD blocks_no
)
244 WCHAR wszFilePath
[MAX_PATH
];
245 DWORD dwFileSize
, new_file_size
;
247 static const WCHAR wszIndex
[] = {'i','n','d','e','x','.','d','a','t',0};
248 static const WCHAR wszMappingFormat
[] = {'%','s','%','s','_','%','l','u',0};
250 WaitForSingleObject(pContainer
->hMutex
, INFINITE
);
252 if (pContainer
->hMapping
) {
253 ReleaseMutex(pContainer
->hMutex
);
254 return ERROR_SUCCESS
;
257 strcpyW(wszFilePath
, pContainer
->path
);
258 strcatW(wszFilePath
, wszIndex
);
260 hFile
= CreateFileW(wszFilePath
, GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, 0, NULL
);
261 if (hFile
== INVALID_HANDLE_VALUE
)
263 /* Maybe the directory wasn't there? Try to create it */
264 if (CreateDirectoryW(pContainer
->path
, 0))
265 hFile
= CreateFileW(wszFilePath
, GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, 0, NULL
);
267 if (hFile
== INVALID_HANDLE_VALUE
)
269 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath
));
270 ReleaseMutex(pContainer
->hMutex
);
271 return GetLastError();
274 dwFileSize
= GetFileSize(hFile
, NULL
);
275 if (dwFileSize
== INVALID_FILE_SIZE
)
277 ReleaseMutex(pContainer
->hMutex
);
278 return GetLastError();
281 if (blocks_no
< MIN_BLOCK_NO
)
282 blocks_no
= MIN_BLOCK_NO
;
283 else if (blocks_no
> MAX_BLOCK_NO
)
284 blocks_no
= MAX_BLOCK_NO
;
285 new_file_size
= FILE_SIZE(blocks_no
);
287 if (dwFileSize
< new_file_size
)
289 static const CHAR szCacheContent
[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content";
291 char achZeroes
[0x1000];
293 DWORD dwError
= ERROR_SUCCESS
;
295 if (SetFilePointer(hFile
, 0, NULL
, FILE_END
) == INVALID_SET_FILE_POINTER
)
296 dwError
= GetLastError();
298 /* Write zeroes to the entire file so we can safely map it without
299 * fear of getting a SEGV because the disk is full.
301 memset(achZeroes
, 0, sizeof(achZeroes
));
302 for (dwOffset
= dwFileSize
; dwOffset
<new_file_size
&& dwError
==ERROR_SUCCESS
;
303 dwOffset
+= sizeof(achZeroes
))
305 DWORD dwWrite
= sizeof(achZeroes
);
308 if (new_file_size
- dwOffset
< dwWrite
)
309 dwWrite
= new_file_size
- dwOffset
;
310 if (!WriteFile(hFile
, achZeroes
, dwWrite
, &dwWritten
, 0) ||
311 dwWritten
!= dwWrite
)
313 /* If we fail to write, we need to return the error that
314 * cause the problem and also make sure the file is no
315 * longer there, if possible.
317 dwError
= GetLastError();
321 if (dwError
== ERROR_SUCCESS
)
323 HANDLE hMapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READWRITE
, 0, 0, NULL
);
327 URLCACHE_HEADER
*pHeader
= MapViewOfFile(hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
329 if (pHeader
&& dwFileSize
)
331 pHeader
->dwFileSize
= new_file_size
;
332 pHeader
->dwIndexCapacityInBlocks
= blocks_no
;
337 WCHAR wszDirPath
[MAX_PATH
];
340 HASH_CACHEFILE_ENTRY
*pHashEntry
;
342 /* First set some constants and defaults in the header */
343 memcpy(pHeader
->szSignature
, urlcache_ver_prefix
, sizeof(urlcache_ver_prefix
)-1);
344 memcpy(pHeader
->szSignature
+sizeof(urlcache_ver_prefix
)-1, urlcache_ver
, sizeof(urlcache_ver
)-1);
345 pHeader
->dwFileSize
= new_file_size
;
346 pHeader
->dwIndexCapacityInBlocks
= blocks_no
;
347 /* 127MB - taken from default for Windows 2000 */
348 pHeader
->CacheLimit
.QuadPart
= 0x07ff5400;
349 /* Copied from a Windows 2000 cache index */
350 pHeader
->DirectoryCount
= pContainer
->default_entry_type
==NORMAL_CACHE_ENTRY
? 4 : 0;
352 /* If the registry has a cache size set, use the registry value */
353 if (RegOpenKeyA(HKEY_CURRENT_USER
, szCacheContent
, &key
) == ERROR_SUCCESS
)
356 DWORD len
= sizeof(dw
);
359 if (RegQueryValueExA(key
, "CacheLimit", NULL
, &keytype
,
360 (BYTE
*) &dw
, &len
) == ERROR_SUCCESS
&&
361 keytype
== REG_DWORD
)
363 pHeader
->CacheLimit
.QuadPart
= (ULONGLONG
)dw
* 1024;
368 URLCache_CreateHashTable(pHeader
, NULL
, &pHashEntry
);
370 /* Last step - create the directories */
372 strcpyW(wszDirPath
, pContainer
->path
);
373 pwchDir
= wszDirPath
+ strlenW(wszDirPath
);
376 GetSystemTimeAsFileTime(&ft
);
378 for (i
= 0; !dwError
&& i
< pHeader
->DirectoryCount
; ++i
)
380 pHeader
->directory_data
[i
].dwNumFiles
= 0;
384 ULONGLONG n
= ft
.dwHighDateTime
;
386 /* Generate a file name to attempt to create.
387 * This algorithm will create what will appear
388 * to be random and unrelated directory names
389 * of up to 9 characters in length.
392 n
+= ft
.dwLowDateTime
;
393 n
^= ((ULONGLONG
) i
<< 56) | ((ULONGLONG
) j
<< 48);
395 for (k
= 0; k
< 8; ++k
)
399 /* Dividing by a prime greater than 36 helps
400 * with the appearance of randomness
405 pwchDir
[k
] = '0' + r
;
407 pwchDir
[k
] = 'A' + (r
- 10);
410 if (CreateDirectoryW(wszDirPath
, 0))
412 /* The following is OK because we generated an
413 * 8 character directory name made from characters
414 * [A-Z0-9], which are equivalent for all code
415 * pages and for UTF-16
417 for (k
= 0; k
< 8; ++k
)
418 pHeader
->directory_data
[i
].filename
[k
] = pwchDir
[k
];
423 /* Give up. The most likely cause of this
424 * is a full disk, but whatever the cause
425 * is, it should be more than apparent that
428 dwError
= GetLastError();
434 UnmapViewOfFile(pHeader
);
438 dwError
= GetLastError();
440 dwFileSize
= new_file_size
;
441 CloseHandle(hMapping
);
445 dwError
= GetLastError();
452 DeleteFileW(wszFilePath
);
453 ReleaseMutex(pContainer
->hMutex
);
459 pContainer
->file_size
= dwFileSize
;
460 wsprintfW(wszFilePath
, wszMappingFormat
, pContainer
->path
, wszIndex
, dwFileSize
);
461 URLCache_PathToObjectName(wszFilePath
, '_');
462 pContainer
->hMapping
= OpenFileMappingW(FILE_MAP_WRITE
, FALSE
, wszFilePath
);
463 if (!pContainer
->hMapping
)
465 pContainer
->hMapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READWRITE
, 0, 0, wszFilePath
);
468 /* Validate cache index file on first open */
469 if (pContainer
->hMapping
&& blocks_no
==MIN_BLOCK_NO
)
471 URLCACHE_HEADER
*pHeader
= MapViewOfFile(pContainer
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
474 ERR("MapViewOfFile failed (error is %d)\n", GetLastError());
475 CloseHandle(pContainer
->hMapping
);
476 pContainer
->hMapping
= NULL
;
477 ReleaseMutex(pContainer
->hMutex
);
478 return GetLastError();
481 if (!memcmp(pHeader
->szSignature
, urlcache_ver_prefix
, sizeof(urlcache_ver_prefix
)-1) &&
482 memcmp(pHeader
->szSignature
+sizeof(urlcache_ver_prefix
)-1, urlcache_ver
, sizeof(urlcache_ver
)-1))
484 TRACE("detected wrong version of cache: %s, expected %s\n", pHeader
->szSignature
, urlcache_ver
);
485 UnmapViewOfFile(pHeader
);
487 FreeUrlCacheSpaceW(pContainer
->path
, 100, 0);
491 UnmapViewOfFile(pHeader
);
499 if (!pContainer
->hMapping
)
501 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
502 ReleaseMutex(pContainer
->hMutex
);
503 return GetLastError();
506 ReleaseMutex(pContainer
->hMutex
);
508 return ERROR_SUCCESS
;
511 /***********************************************************************
512 * URLCacheContainer_CloseIndex (Internal)
520 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER
* pContainer
)
522 CloseHandle(pContainer
->hMapping
);
523 pContainer
->hMapping
= NULL
;
526 static BOOL
URLCacheContainers_AddContainer(LPCWSTR cache_prefix
,
527 LPCWSTR path
, DWORD default_entry_type
, LPWSTR mutex_name
)
529 URLCACHECONTAINER
* pContainer
= heap_alloc(sizeof(URLCACHECONTAINER
));
530 int cache_prefix_len
= strlenW(cache_prefix
);
537 pContainer
->hMapping
= NULL
;
538 pContainer
->file_size
= 0;
539 pContainer
->default_entry_type
= default_entry_type
;
541 pContainer
->path
= heap_strdupW(path
);
542 if (!pContainer
->path
)
544 heap_free(pContainer
);
548 pContainer
->cache_prefix
= heap_alloc((cache_prefix_len
+ 1) * sizeof(WCHAR
));
549 if (!pContainer
->cache_prefix
)
551 heap_free(pContainer
->path
);
552 heap_free(pContainer
);
556 memcpy(pContainer
->cache_prefix
, cache_prefix
, (cache_prefix_len
+ 1) * sizeof(WCHAR
));
558 CharLowerW(mutex_name
);
559 URLCache_PathToObjectName(mutex_name
, '!');
561 if ((pContainer
->hMutex
= CreateMutexW(NULL
, FALSE
, mutex_name
)) == NULL
)
563 ERR("couldn't create mutex (error is %d)\n", GetLastError());
564 heap_free(pContainer
->path
);
565 heap_free(pContainer
);
569 list_add_head(&UrlContainers
, &pContainer
->entry
);
574 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER
* pContainer
)
576 list_remove(&pContainer
->entry
);
578 URLCacheContainer_CloseIndex(pContainer
);
579 CloseHandle(pContainer
->hMutex
);
580 heap_free(pContainer
->path
);
581 heap_free(pContainer
->cache_prefix
);
582 heap_free(pContainer
);
585 static void URLCacheContainers_CreateDefaults(void)
587 static const WCHAR UrlSuffix
[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
588 static const WCHAR UrlPrefix
[] = {0};
589 static const WCHAR HistorySuffix
[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
590 static const WCHAR HistoryPrefix
[] = {'V','i','s','i','t','e','d',':',0};
591 static const WCHAR CookieSuffix
[] = {0};
592 static const WCHAR CookiePrefix
[] = {'C','o','o','k','i','e',':',0};
595 int nFolder
; /* CSIDL_* constant */
596 const WCHAR
* shpath_suffix
; /* suffix on path returned by SHGetSpecialFolderPath */
597 const WCHAR
* cache_prefix
; /* prefix used to reference the container */
598 DWORD default_entry_type
;
599 } DefaultContainerData
[] =
601 { CSIDL_INTERNET_CACHE
, UrlSuffix
, UrlPrefix
, NORMAL_CACHE_ENTRY
},
602 { CSIDL_HISTORY
, HistorySuffix
, HistoryPrefix
, URLHISTORY_CACHE_ENTRY
},
603 { CSIDL_COOKIES
, CookieSuffix
, CookiePrefix
, COOKIE_CACHE_ENTRY
},
607 for (i
= 0; i
< sizeof(DefaultContainerData
) / sizeof(DefaultContainerData
[0]); i
++)
609 WCHAR wszCachePath
[MAX_PATH
];
610 WCHAR wszMutexName
[MAX_PATH
];
611 int path_len
, suffix_len
;
613 if (!SHGetSpecialFolderPathW(NULL
, wszCachePath
, DefaultContainerData
[i
].nFolder
, TRUE
))
615 ERR("Couldn't get path for default container %u\n", i
);
618 path_len
= strlenW(wszCachePath
);
619 suffix_len
= strlenW(DefaultContainerData
[i
].shpath_suffix
);
621 if (path_len
+ suffix_len
+ 2 > MAX_PATH
)
623 ERR("Path too long\n");
627 wszCachePath
[path_len
] = '\\';
628 wszCachePath
[path_len
+1] = 0;
630 strcpyW(wszMutexName
, wszCachePath
);
634 memcpy(wszCachePath
+ path_len
+ 1, DefaultContainerData
[i
].shpath_suffix
, (suffix_len
+ 1) * sizeof(WCHAR
));
635 wszCachePath
[path_len
+ suffix_len
+ 1] = '\\';
636 wszCachePath
[path_len
+ suffix_len
+ 2] = '\0';
639 URLCacheContainers_AddContainer(DefaultContainerData
[i
].cache_prefix
, wszCachePath
,
640 DefaultContainerData
[i
].default_entry_type
, wszMutexName
);
644 static void URLCacheContainers_DeleteAll(void)
646 while(!list_empty(&UrlContainers
))
647 URLCacheContainer_DeleteContainer(
648 LIST_ENTRY(list_head(&UrlContainers
), URLCACHECONTAINER
, entry
)
652 static DWORD
URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl
, URLCACHECONTAINER
** ppContainer
)
654 URLCACHECONTAINER
* pContainer
;
656 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl
));
659 return ERROR_INVALID_PARAMETER
;
661 LIST_FOR_EACH_ENTRY(pContainer
, &UrlContainers
, URLCACHECONTAINER
, entry
)
663 int prefix_len
= strlenW(pContainer
->cache_prefix
);
664 if (!strncmpW(pContainer
->cache_prefix
, lpwszUrl
, prefix_len
))
666 TRACE("found container with prefix %s for URL %s\n", debugstr_w(pContainer
->cache_prefix
), debugstr_w(lpwszUrl
));
667 *ppContainer
= pContainer
;
668 return ERROR_SUCCESS
;
671 ERR("no container found\n");
672 return ERROR_FILE_NOT_FOUND
;
675 static DWORD
URLCacheContainers_FindContainerA(LPCSTR lpszUrl
, URLCACHECONTAINER
** ppContainer
)
680 if (lpszUrl
&& !(url
= heap_strdupAtoW(lpszUrl
)))
681 return ERROR_OUTOFMEMORY
;
683 ret
= URLCacheContainers_FindContainerW(url
, ppContainer
);
688 static BOOL
URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern
, DWORD dwIndex
, URLCACHECONTAINER
** ppContainer
)
691 URLCACHECONTAINER
* pContainer
;
693 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern
));
695 /* non-NULL search pattern only returns one container ever */
696 if (lpwszSearchPattern
&& dwIndex
> 0)
699 LIST_FOR_EACH_ENTRY(pContainer
, &UrlContainers
, URLCACHECONTAINER
, entry
)
701 if (lpwszSearchPattern
)
703 if (!strcmpW(pContainer
->cache_prefix
, lpwszSearchPattern
))
705 TRACE("found container with prefix %s\n", debugstr_w(pContainer
->cache_prefix
));
706 *ppContainer
= pContainer
;
714 TRACE("found container with prefix %s\n", debugstr_w(pContainer
->cache_prefix
));
715 *ppContainer
= pContainer
;
724 /***********************************************************************
725 * URLCacheContainer_LockIndex (Internal)
727 * Locks the index for system-wide exclusive access.
730 * Cache file header if successful
731 * NULL if failed and calls SetLastError.
733 static LPURLCACHE_HEADER
URLCacheContainer_LockIndex(URLCACHECONTAINER
* pContainer
)
737 URLCACHE_HEADER
* pHeader
;
741 WaitForSingleObject(pContainer
->hMutex
, INFINITE
);
743 pIndexData
= MapViewOfFile(pContainer
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
747 ReleaseMutex(pContainer
->hMutex
);
748 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
751 pHeader
= (URLCACHE_HEADER
*)pIndexData
;
753 /* file has grown - we need to remap to prevent us getting
754 * access violations when we try and access beyond the end
755 * of the memory mapped file */
756 if (pHeader
->dwFileSize
!= pContainer
->file_size
)
758 UnmapViewOfFile( pHeader
);
759 URLCacheContainer_CloseIndex(pContainer
);
760 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
761 if (error
!= ERROR_SUCCESS
)
763 ReleaseMutex(pContainer
->hMutex
);
767 pIndexData
= MapViewOfFile(pContainer
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
771 ReleaseMutex(pContainer
->hMutex
);
772 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
775 pHeader
= (URLCACHE_HEADER
*)pIndexData
;
778 TRACE("Signature: %s, file size: %d bytes\n", pHeader
->szSignature
, pHeader
->dwFileSize
);
780 for (index
= 0; index
< pHeader
->DirectoryCount
; index
++)
782 TRACE("Directory[%d] = \"%.8s\"\n", index
, pHeader
->directory_data
[index
].filename
);
788 /***********************************************************************
789 * URLCacheContainer_UnlockIndex (Internal)
792 static BOOL
URLCacheContainer_UnlockIndex(URLCACHECONTAINER
* pContainer
, LPURLCACHE_HEADER pHeader
)
795 ReleaseMutex(pContainer
->hMutex
);
796 return UnmapViewOfFile(pHeader
);
800 #define CHAR_BIT (8 * sizeof(CHAR))
803 /***********************************************************************
804 * URLCache_Allocation_BlockIsFree (Internal)
806 * Is the specified block number free?
813 static inline BYTE
URLCache_Allocation_BlockIsFree(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
815 BYTE mask
= 1 << (dwBlockNumber
% CHAR_BIT
);
816 return (AllocationTable
[dwBlockNumber
/ CHAR_BIT
] & mask
) == 0;
819 /***********************************************************************
820 * URLCache_Allocation_BlockFree (Internal)
822 * Marks the specified block as free
825 * this function is not updating used blocks count
831 static inline void URLCache_Allocation_BlockFree(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
833 BYTE mask
= ~(1 << (dwBlockNumber
% CHAR_BIT
));
834 AllocationTable
[dwBlockNumber
/ CHAR_BIT
] &= mask
;
837 /***********************************************************************
838 * URLCache_Allocation_BlockAllocate (Internal)
840 * Marks the specified block as allocated
843 * this function is not updating used blocks count
849 static inline void URLCache_Allocation_BlockAllocate(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
851 BYTE mask
= 1 << (dwBlockNumber
% CHAR_BIT
);
852 AllocationTable
[dwBlockNumber
/ CHAR_BIT
] |= mask
;
855 /***********************************************************************
856 * URLCache_FindFirstFreeEntry (Internal)
858 * Finds and allocates the first block of free space big enough and
859 * sets ppEntry to point to it.
862 * ERROR_SUCCESS when free memory block was found
863 * Any other Win32 error code if the entry could not be added
866 static DWORD
URLCache_FindFirstFreeEntry(URLCACHE_HEADER
* pHeader
, DWORD dwBlocksNeeded
, CACHEFILE_ENTRY
** ppEntry
)
870 for (dwBlockNumber
= 0; dwBlockNumber
< pHeader
->dwIndexCapacityInBlocks
; dwBlockNumber
++)
872 for (dwFreeCounter
= 0;
873 dwFreeCounter
< dwBlocksNeeded
&&
874 dwFreeCounter
+ dwBlockNumber
< pHeader
->dwIndexCapacityInBlocks
&&
875 URLCache_Allocation_BlockIsFree(pHeader
->allocation_table
, dwBlockNumber
+ dwFreeCounter
);
877 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber
, ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
879 if (dwFreeCounter
== dwBlocksNeeded
)
882 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber
, ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
883 for (index
= 0; index
< dwBlocksNeeded
; index
++)
884 URLCache_Allocation_BlockAllocate(pHeader
->allocation_table
, dwBlockNumber
+ index
);
885 *ppEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
886 for (index
= 0; index
< dwBlocksNeeded
* BLOCKSIZE
/ sizeof(DWORD
); index
++)
887 ((DWORD
*)*ppEntry
)[index
] = 0xdeadbeef;
888 (*ppEntry
)->dwBlocksUsed
= dwBlocksNeeded
;
889 pHeader
->dwBlocksInUse
+= dwBlocksNeeded
;
890 return ERROR_SUCCESS
;
894 return ERROR_HANDLE_DISK_FULL
;
897 /***********************************************************************
898 * URLCache_DeleteEntry (Internal)
900 * Deletes the specified entry and frees the space allocated to it
903 * TRUE if it succeeded
907 static BOOL
URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader
, CACHEFILE_ENTRY
* pEntry
)
912 /* update allocation table */
913 dwStartBlock
= ((DWORD
)((BYTE
*)pEntry
- (BYTE
*)pHeader
) - ENTRY_START_OFFSET
) / BLOCKSIZE
;
914 for (dwBlock
= dwStartBlock
; dwBlock
< dwStartBlock
+ pEntry
->dwBlocksUsed
; dwBlock
++)
915 URLCache_Allocation_BlockFree(pHeader
->allocation_table
, dwBlock
);
917 pHeader
->dwBlocksInUse
-= pEntry
->dwBlocksUsed
;
921 /***********************************************************************
922 * URLCache_LocalFileNameToPathW (Internal)
924 * Copies the full path to the specified buffer given the local file
925 * name and the index of the directory it is in. Always sets value in
926 * lpBufferSize to the required buffer size (in bytes).
929 * TRUE if the buffer was big enough
930 * FALSE if the buffer was too small
933 static BOOL
URLCache_LocalFileNameToPathW(
934 const URLCACHECONTAINER
* pContainer
,
935 LPCURLCACHE_HEADER pHeader
,
936 LPCSTR szLocalFileName
,
942 int path_len
= strlenW(pContainer
->path
);
943 int file_name_len
= MultiByteToWideChar(CP_ACP
, 0, szLocalFileName
, -1, NULL
, 0);
944 if (Directory
!=CACHE_CONTAINER_NO_SUBDIR
&& Directory
>=pHeader
->DirectoryCount
)
950 nRequired
= (path_len
+ file_name_len
) * sizeof(WCHAR
);
951 if(Directory
!= CACHE_CONTAINER_NO_SUBDIR
)
952 nRequired
+= (DIR_LENGTH
+ 1) * sizeof(WCHAR
);
953 if (nRequired
<= *lpBufferSize
)
957 memcpy(wszPath
, pContainer
->path
, path_len
* sizeof(WCHAR
));
958 if (Directory
!= CACHE_CONTAINER_NO_SUBDIR
)
960 dir_len
= MultiByteToWideChar(CP_ACP
, 0, pHeader
->directory_data
[Directory
].filename
, DIR_LENGTH
, wszPath
+ path_len
, DIR_LENGTH
);
961 wszPath
[dir_len
+ path_len
] = '\\';
968 MultiByteToWideChar(CP_ACP
, 0, szLocalFileName
, -1, wszPath
+ dir_len
+ path_len
, file_name_len
);
969 *lpBufferSize
= nRequired
;
972 *lpBufferSize
= nRequired
;
976 /***********************************************************************
977 * URLCache_LocalFileNameToPathA (Internal)
979 * Copies the full path to the specified buffer given the local file
980 * name and the index of the directory it is in. Always sets value in
981 * lpBufferSize to the required buffer size.
984 * TRUE if the buffer was big enough
985 * FALSE if the buffer was too small
988 static BOOL
URLCache_LocalFileNameToPathA(
989 const URLCACHECONTAINER
* pContainer
,
990 LPCURLCACHE_HEADER pHeader
,
991 LPCSTR szLocalFileName
,
997 int path_len
, file_name_len
, dir_len
;
999 if (Directory
!=CACHE_CONTAINER_NO_SUBDIR
&& Directory
>=pHeader
->DirectoryCount
)
1005 path_len
= WideCharToMultiByte(CP_ACP
, 0, pContainer
->path
, -1, NULL
, 0, NULL
, NULL
) - 1;
1006 file_name_len
= strlen(szLocalFileName
) + 1 /* for nul-terminator */;
1007 if (Directory
!=CACHE_CONTAINER_NO_SUBDIR
)
1008 dir_len
= DIR_LENGTH
+1;
1012 nRequired
= (path_len
+ dir_len
+ file_name_len
) * sizeof(char);
1013 if (nRequired
< *lpBufferSize
)
1015 WideCharToMultiByte(CP_ACP
, 0, pContainer
->path
, -1, szPath
, path_len
, NULL
, NULL
);
1017 memcpy(szPath
+path_len
, pHeader
->directory_data
[Directory
].filename
, dir_len
-1);
1018 szPath
[path_len
+ dir_len
-1] = '\\';
1020 memcpy(szPath
+ path_len
+ dir_len
, szLocalFileName
, file_name_len
);
1021 *lpBufferSize
= nRequired
;
1024 *lpBufferSize
= nRequired
;
1028 /* Just like FileTimeToDosDateTime, except that it also maps the special
1029 * case of a filetime of (0,0) to a DOS date/time of (0,0).
1031 static void URLCache_FileTimeToDosDateTime(const FILETIME
*ft
, WORD
*fatdate
,
1034 if (!ft
->dwLowDateTime
&& !ft
->dwHighDateTime
)
1035 *fatdate
= *fattime
= 0;
1037 FileTimeToDosDateTime(ft
, fatdate
, fattime
);
1040 /***********************************************************************
1041 * URLCache_DeleteFile (Internal)
1043 static DWORD
URLCache_DeleteFile(const URLCACHECONTAINER
*container
,
1044 URLCACHE_HEADER
*header
, URL_CACHEFILE_ENTRY
*url_entry
)
1046 WIN32_FILE_ATTRIBUTE_DATA attr
;
1047 WCHAR path
[MAX_PATH
];
1048 LONG path_size
= sizeof(path
);
1052 if(!url_entry
->dwOffsetLocalName
)
1055 if(!URLCache_LocalFileNameToPathW(container
, header
,
1056 (LPCSTR
)url_entry
+url_entry
->dwOffsetLocalName
,
1057 url_entry
->CacheDir
, path
, &path_size
))
1060 if(!GetFileAttributesExW(path
, GetFileExInfoStandard
, &attr
))
1062 URLCache_FileTimeToDosDateTime(&attr
.ftLastWriteTime
, &date
, &time
);
1063 if(date
!= url_entry
->LastWriteDate
|| time
!= url_entry
->LastWriteTime
)
1066 err
= (DeleteFileW(path
) ? ERROR_SUCCESS
: GetLastError());
1067 if(err
== ERROR_ACCESS_DENIED
|| err
== ERROR_SHARING_VIOLATION
)
1071 if (url_entry
->CacheDir
< header
->DirectoryCount
)
1073 if (header
->directory_data
[url_entry
->CacheDir
].dwNumFiles
)
1074 header
->directory_data
[url_entry
->CacheDir
].dwNumFiles
--;
1076 if (url_entry
->CacheEntryType
& STICKY_CACHE_ENTRY
)
1078 if (url_entry
->size
.QuadPart
< header
->ExemptUsage
.QuadPart
)
1079 header
->ExemptUsage
.QuadPart
-= url_entry
->size
.QuadPart
;
1081 header
->ExemptUsage
.QuadPart
= 0;
1085 if (url_entry
->size
.QuadPart
< header
->CacheUsage
.QuadPart
)
1086 header
->CacheUsage
.QuadPart
-= url_entry
->size
.QuadPart
;
1088 header
->CacheUsage
.QuadPart
= 0;
1091 return ERROR_SUCCESS
;
1094 static BOOL
urlcache_clean_leaked_entries(URLCACHECONTAINER
*container
, URLCACHE_HEADER
*header
)
1099 leak_off
= &header
->options
[CACHE_HEADER_DATA_ROOT_LEAK_OFFSET
];
1101 URL_CACHEFILE_ENTRY
*url_entry
= (URL_CACHEFILE_ENTRY
*)((LPBYTE
)header
+ *leak_off
);
1103 if(SUCCEEDED(URLCache_DeleteFile(container
, header
, url_entry
))) {
1104 *leak_off
= url_entry
->dwExemptDelta
;
1105 URLCache_DeleteEntry(header
, &url_entry
->CacheFileEntry
);
1108 leak_off
= &url_entry
->dwExemptDelta
;
1115 /***********************************************************************
1116 * URLCacheContainer_CleanIndex (Internal)
1118 * This function is meant to make place in index file by removing leaked
1119 * files entries and resizing the file.
1121 * CAUTION: file view may get mapped to new memory
1124 * ERROR_SUCCESS when new memory is available
1125 * error code otherwise
1127 static DWORD
URLCacheContainer_CleanIndex(URLCACHECONTAINER
*container
, URLCACHE_HEADER
**file_view
)
1129 URLCACHE_HEADER
*header
= *file_view
;
1132 TRACE("(%s %s)\n", debugstr_w(container
->cache_prefix
), debugstr_w(container
->path
));
1134 if(urlcache_clean_leaked_entries(container
, header
))
1135 return ERROR_SUCCESS
;
1137 if(header
->dwFileSize
>= ALLOCATION_TABLE_SIZE
*8*BLOCKSIZE
+ ENTRY_START_OFFSET
) {
1138 WARN("index file has maximal size\n");
1139 return ERROR_NOT_ENOUGH_MEMORY
;
1142 URLCacheContainer_CloseIndex(container
);
1143 ret
= URLCacheContainer_OpenIndex(container
, header
->dwIndexCapacityInBlocks
*2);
1144 if(ret
!= ERROR_SUCCESS
)
1146 header
= MapViewOfFile(container
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
1148 return GetLastError();
1150 UnmapViewOfFile(*file_view
);
1151 *file_view
= header
;
1152 return ERROR_SUCCESS
;
1155 /* Just like DosDateTimeToFileTime, except that it also maps the special
1156 * case of a DOS date/time of (0,0) to a filetime of (0,0).
1158 static void URLCache_DosDateTimeToFileTime(WORD fatdate
, WORD fattime
,
1161 if (!fatdate
&& !fattime
)
1162 ft
->dwLowDateTime
= ft
->dwHighDateTime
= 0;
1164 DosDateTimeToFileTime(fatdate
, fattime
, ft
);
1167 /***********************************************************************
1168 * URLCache_CopyEntry (Internal)
1170 * Copies an entry from the cache index file to the Win32 structure
1173 * ERROR_SUCCESS if the buffer was big enough
1174 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1177 static DWORD
URLCache_CopyEntry(
1178 URLCACHECONTAINER
* pContainer
,
1179 LPCURLCACHE_HEADER pHeader
,
1180 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1181 LPDWORD lpdwBufferSize
,
1182 const URL_CACHEFILE_ENTRY
* pUrlEntry
,
1186 DWORD dwRequiredSize
= sizeof(*lpCacheEntryInfo
);
1188 if (*lpdwBufferSize
>= dwRequiredSize
)
1190 lpCacheEntryInfo
->lpHeaderInfo
= NULL
;
1191 lpCacheEntryInfo
->lpszFileExtension
= NULL
;
1192 lpCacheEntryInfo
->lpszLocalFileName
= NULL
;
1193 lpCacheEntryInfo
->lpszSourceUrlName
= NULL
;
1194 lpCacheEntryInfo
->CacheEntryType
= pUrlEntry
->CacheEntryType
;
1195 lpCacheEntryInfo
->u
.dwExemptDelta
= pUrlEntry
->dwExemptDelta
;
1196 lpCacheEntryInfo
->dwHeaderInfoSize
= pUrlEntry
->dwHeaderInfoSize
;
1197 lpCacheEntryInfo
->dwHitRate
= pUrlEntry
->dwHitRate
;
1198 lpCacheEntryInfo
->dwSizeHigh
= pUrlEntry
->size
.u
.HighPart
;
1199 lpCacheEntryInfo
->dwSizeLow
= pUrlEntry
->size
.u
.LowPart
;
1200 lpCacheEntryInfo
->dwStructSize
= sizeof(*lpCacheEntryInfo
);
1201 lpCacheEntryInfo
->dwUseCount
= pUrlEntry
->dwUseCount
;
1202 URLCache_DosDateTimeToFileTime(pUrlEntry
->wExpiredDate
, pUrlEntry
->wExpiredTime
, &lpCacheEntryInfo
->ExpireTime
);
1203 lpCacheEntryInfo
->LastAccessTime
.dwHighDateTime
= pUrlEntry
->LastAccessTime
.dwHighDateTime
;
1204 lpCacheEntryInfo
->LastAccessTime
.dwLowDateTime
= pUrlEntry
->LastAccessTime
.dwLowDateTime
;
1205 lpCacheEntryInfo
->LastModifiedTime
.dwHighDateTime
= pUrlEntry
->LastModifiedTime
.dwHighDateTime
;
1206 lpCacheEntryInfo
->LastModifiedTime
.dwLowDateTime
= pUrlEntry
->LastModifiedTime
.dwLowDateTime
;
1207 URLCache_DosDateTimeToFileTime(pUrlEntry
->wLastSyncDate
, pUrlEntry
->wLastSyncTime
, &lpCacheEntryInfo
->LastSyncTime
);
1210 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1211 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1212 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1214 lenUrl
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, -1, NULL
, 0);
1216 lenUrl
= strlen((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
1217 dwRequiredSize
+= (lenUrl
+ 1) * (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
1219 /* FIXME: is source url optional? */
1220 if (*lpdwBufferSize
>= dwRequiredSize
)
1222 DWORD lenUrlBytes
= (lenUrl
+1) * (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
1224 lpCacheEntryInfo
->lpszSourceUrlName
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
- lenUrlBytes
;
1226 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, -1, (LPWSTR
)lpCacheEntryInfo
->lpszSourceUrlName
, lenUrl
+ 1);
1228 memcpy(lpCacheEntryInfo
->lpszSourceUrlName
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, lenUrlBytes
);
1231 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1232 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1233 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1235 if (pUrlEntry
->dwOffsetLocalName
)
1237 LONG nLocalFilePathSize
;
1238 LPSTR lpszLocalFileName
;
1239 lpszLocalFileName
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
;
1240 nLocalFilePathSize
= *lpdwBufferSize
- dwRequiredSize
;
1241 if ((bUnicode
&& URLCache_LocalFileNameToPathW(pContainer
, pHeader
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
, pUrlEntry
->CacheDir
, (LPWSTR
)lpszLocalFileName
, &nLocalFilePathSize
)) ||
1242 (!bUnicode
&& URLCache_LocalFileNameToPathA(pContainer
, pHeader
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
, pUrlEntry
->CacheDir
, lpszLocalFileName
, &nLocalFilePathSize
)))
1244 lpCacheEntryInfo
->lpszLocalFileName
= lpszLocalFileName
;
1246 dwRequiredSize
+= nLocalFilePathSize
* (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
)) ;
1248 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1249 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1250 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1252 dwRequiredSize
+= pUrlEntry
->dwHeaderInfoSize
+ 1;
1254 if (*lpdwBufferSize
>= dwRequiredSize
)
1256 lpCacheEntryInfo
->lpHeaderInfo
= (LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
- pUrlEntry
->dwHeaderInfoSize
- 1;
1257 memcpy(lpCacheEntryInfo
->lpHeaderInfo
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
, pUrlEntry
->dwHeaderInfoSize
);
1258 ((LPBYTE
)lpCacheEntryInfo
)[dwRequiredSize
- 1] = '\0';
1260 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1261 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1262 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1264 if (pUrlEntry
->dwOffsetFileExtension
)
1269 lenExtension
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, -1, NULL
, 0);
1271 lenExtension
= strlen((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
) + 1;
1272 dwRequiredSize
+= lenExtension
* (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
1274 if (*lpdwBufferSize
>= dwRequiredSize
)
1276 lpCacheEntryInfo
->lpszFileExtension
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
- lenExtension
;
1278 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, -1, (LPWSTR
)lpCacheEntryInfo
->lpszSourceUrlName
, lenExtension
);
1280 memcpy(lpCacheEntryInfo
->lpszFileExtension
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, lenExtension
* sizeof(CHAR
));
1283 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1284 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1285 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1288 if (dwRequiredSize
> *lpdwBufferSize
)
1290 *lpdwBufferSize
= dwRequiredSize
;
1291 return ERROR_INSUFFICIENT_BUFFER
;
1293 *lpdwBufferSize
= dwRequiredSize
;
1294 return ERROR_SUCCESS
;
1297 /***********************************************************************
1298 * URLCache_SetEntryInfo (Internal)
1300 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1301 * according to the flags set by dwFieldControl.
1304 * ERROR_SUCCESS if the buffer was big enough
1305 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1308 static DWORD
URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY
* pUrlEntry
, const INTERNET_CACHE_ENTRY_INFOW
* lpCacheEntryInfo
, DWORD dwFieldControl
)
1310 if (dwFieldControl
& CACHE_ENTRY_ACCTIME_FC
)
1311 pUrlEntry
->LastAccessTime
= lpCacheEntryInfo
->LastAccessTime
;
1312 if (dwFieldControl
& CACHE_ENTRY_ATTRIBUTE_FC
)
1313 pUrlEntry
->CacheEntryType
= lpCacheEntryInfo
->CacheEntryType
;
1314 if (dwFieldControl
& CACHE_ENTRY_EXEMPT_DELTA_FC
)
1315 pUrlEntry
->dwExemptDelta
= lpCacheEntryInfo
->u
.dwExemptDelta
;
1316 if (dwFieldControl
& CACHE_ENTRY_EXPTIME_FC
)
1317 URLCache_FileTimeToDosDateTime(&lpCacheEntryInfo
->ExpireTime
, &pUrlEntry
->wExpiredDate
, &pUrlEntry
->wExpiredTime
);
1318 if (dwFieldControl
& CACHE_ENTRY_HEADERINFO_FC
)
1319 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1320 if (dwFieldControl
& CACHE_ENTRY_HITRATE_FC
)
1321 pUrlEntry
->dwHitRate
= lpCacheEntryInfo
->dwHitRate
;
1322 if (dwFieldControl
& CACHE_ENTRY_MODTIME_FC
)
1323 pUrlEntry
->LastModifiedTime
= lpCacheEntryInfo
->LastModifiedTime
;
1324 if (dwFieldControl
& CACHE_ENTRY_SYNCTIME_FC
)
1325 URLCache_FileTimeToDosDateTime(&lpCacheEntryInfo
->LastAccessTime
, &pUrlEntry
->wLastSyncDate
, &pUrlEntry
->wLastSyncTime
);
1327 return ERROR_SUCCESS
;
1330 /***********************************************************************
1331 * URLCache_HashKey (Internal)
1333 * Returns the hash key for a given string
1336 * hash key for the string
1339 static DWORD
URLCache_HashKey(LPCSTR lpszKey
)
1341 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1342 * but the algorithm and result are not the same!
1344 static const unsigned char lookupTable
[256] =
1346 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1347 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1348 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1349 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1350 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1351 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1352 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1353 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1354 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1355 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1356 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1357 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1358 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1359 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1360 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1361 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1362 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1363 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1364 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1365 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1366 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1367 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1368 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1369 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1370 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1371 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1372 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1373 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1374 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1375 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1376 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1377 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1382 for (i
= 0; i
< sizeof(key
) / sizeof(key
[0]); i
++)
1383 key
[i
] = lookupTable
[(*lpszKey
+ i
) & 0xFF];
1385 for (lpszKey
++; *lpszKey
&& ((lpszKey
[0] != '/') || (lpszKey
[1] != 0)); lpszKey
++)
1387 for (i
= 0; i
< sizeof(key
) / sizeof(key
[0]); i
++)
1388 key
[i
] = lookupTable
[*lpszKey
^ key
[i
]];
1391 return *(DWORD
*)key
;
1394 static inline HASH_CACHEFILE_ENTRY
* URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader
, DWORD dwOffset
)
1396 return (HASH_CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ dwOffset
);
1399 static inline BOOL
URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader
, const HASH_CACHEFILE_ENTRY
*pHashEntry
)
1401 /* check pHashEntry located within acceptable bounds in the URL cache mapping */
1402 return ((DWORD
)((const BYTE
*)pHashEntry
- (const BYTE
*)pHeader
) >= ENTRY_START_OFFSET
) &&
1403 ((DWORD
)((const BYTE
*)pHashEntry
- (const BYTE
*)pHeader
) < pHeader
->dwFileSize
);
1406 static BOOL
URLCache_FindHash(LPCURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, struct _HASH_ENTRY
** ppHashEntry
)
1408 /* structure of hash table:
1409 * 448 entries divided into 64 blocks
1410 * each block therefore contains a chain of 7 key/offset pairs
1411 * how position in table is calculated:
1412 * 1. the url is hashed in helper function
1413 * 2. the key % HASHTABLE_NUM_ENTRIES is the bucket number
1414 * 3. bucket number * HASHTABLE_BLOCKSIZE is offset of the bucket
1417 * there can be multiple hash tables in the file and the offset to
1418 * the next one is stored in the header of the hash table
1420 DWORD key
= URLCache_HashKey(lpszUrl
);
1421 DWORD offset
= (key
& (HASHTABLE_NUM_ENTRIES
-1)) * HASHTABLE_BLOCKSIZE
;
1422 HASH_CACHEFILE_ENTRY
* pHashEntry
;
1423 DWORD dwHashTableNumber
= 0;
1425 key
>>= HASHTABLE_FLAG_BITS
;
1427 for (pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1428 URLCache_IsHashEntryValid(pHeader
, pHashEntry
);
1429 pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHashEntry
->dwAddressNext
))
1432 if (pHashEntry
->dwHashTableNumber
!= dwHashTableNumber
++)
1434 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry
->dwHashTableNumber
, dwHashTableNumber
);
1437 /* make sure that it is in fact a hash entry */
1438 if (pHashEntry
->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1440 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&pHashEntry
->CacheFileEntry
.dwSignature
);
1444 for (i
= 0; i
< HASHTABLE_BLOCKSIZE
; i
++)
1446 struct _HASH_ENTRY
* pHashElement
= &pHashEntry
->HashTable
[offset
+ i
];
1447 if (key
== pHashElement
->dwHashKey
>>HASHTABLE_FLAG_BITS
)
1449 /* FIXME: we should make sure that this is the right element
1450 * before returning and claiming that it is. We can do this
1451 * by doing a simple compare between the URL we were given
1452 * and the URL stored in the entry. However, this assumes
1453 * we know the format of all the entries stored in the
1455 *ppHashEntry
= pHashElement
;
1463 static BOOL
URLCache_FindHashW(LPCURLCACHE_HEADER pHeader
, LPCWSTR lpszUrl
, struct _HASH_ENTRY
** ppHashEntry
)
1468 urlA
= heap_strdupWtoA(lpszUrl
);
1471 SetLastError(ERROR_OUTOFMEMORY
);
1475 ret
= URLCache_FindHash(pHeader
, urlA
, ppHashEntry
);
1480 /***********************************************************************
1481 * URLCache_HashEntrySetFlags (Internal)
1483 * Sets special bits in hash key
1489 static void URLCache_HashEntrySetFlags(struct _HASH_ENTRY
* pHashEntry
, DWORD dwFlag
)
1491 pHashEntry
->dwHashKey
= (pHashEntry
->dwHashKey
>> HASHTABLE_FLAG_BITS
<< HASHTABLE_FLAG_BITS
) | dwFlag
;
1494 /***********************************************************************
1495 * URLCache_DeleteEntryFromHash (Internal)
1497 * Searches all the hash tables in the index for the given URL and
1498 * then if found deletes the entry.
1501 * TRUE if the entry was found
1502 * FALSE if the entry could not be found
1505 static BOOL
URLCache_DeleteEntryFromHash(struct _HASH_ENTRY
* pHashEntry
)
1507 pHashEntry
->dwHashKey
= HASHTABLE_DEL
;
1511 /***********************************************************************
1512 * URLCache_AddEntryToHash (Internal)
1514 * Searches all the hash tables for a free slot based on the offset
1515 * generated from the hash key. If a free slot is found, the offset and
1516 * key are entered into the hash table.
1519 * ERROR_SUCCESS if the entry was added
1520 * Any other Win32 error code if the entry could not be added
1523 static DWORD
URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, DWORD dwOffsetEntry
, DWORD dwFieldType
)
1525 /* see URLCache_FindEntryInHash for structure of hash tables */
1527 DWORD key
= URLCache_HashKey(lpszUrl
);
1528 DWORD offset
= (key
& (HASHTABLE_NUM_ENTRIES
-1)) * HASHTABLE_BLOCKSIZE
;
1529 HASH_CACHEFILE_ENTRY
* pHashEntry
, *pHashPrev
= NULL
;
1530 DWORD dwHashTableNumber
= 0;
1533 key
= ((key
>> HASHTABLE_FLAG_BITS
) << HASHTABLE_FLAG_BITS
) + dwFieldType
;
1535 for (pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1536 URLCache_IsHashEntryValid(pHeader
, pHashEntry
);
1537 pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHashEntry
->dwAddressNext
))
1540 pHashPrev
= pHashEntry
;
1542 if (pHashEntry
->dwHashTableNumber
!= dwHashTableNumber
++)
1544 ERR("not right hash table number (%d) expected %d\n", pHashEntry
->dwHashTableNumber
, dwHashTableNumber
);
1547 /* make sure that it is in fact a hash entry */
1548 if (pHashEntry
->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1550 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&pHashEntry
->CacheFileEntry
.dwSignature
);
1554 for (i
= 0; i
< HASHTABLE_BLOCKSIZE
; i
++)
1556 struct _HASH_ENTRY
* pHashElement
= &pHashEntry
->HashTable
[offset
+ i
];
1557 if (pHashElement
->dwHashKey
==HASHTABLE_FREE
|| pHashElement
->dwHashKey
==HASHTABLE_DEL
) /* if the slot is free */
1559 pHashElement
->dwHashKey
= key
;
1560 pHashElement
->dwOffsetEntry
= dwOffsetEntry
;
1561 return ERROR_SUCCESS
;
1565 error
= URLCache_CreateHashTable(pHeader
, pHashPrev
, &pHashEntry
);
1566 if (error
!= ERROR_SUCCESS
)
1569 pHashEntry
->HashTable
[offset
].dwHashKey
= key
;
1570 pHashEntry
->HashTable
[offset
].dwOffsetEntry
= dwOffsetEntry
;
1571 return ERROR_SUCCESS
;
1574 /***********************************************************************
1575 * URLCache_CreateHashTable (Internal)
1577 * Creates a new hash table in free space and adds it to the chain of existing
1581 * ERROR_SUCCESS if the hash table was created
1582 * ERROR_DISK_FULL if the hash table could not be created
1585 static DWORD
URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader
, HASH_CACHEFILE_ENTRY
*pPrevHash
, HASH_CACHEFILE_ENTRY
**ppHash
)
1587 DWORD dwOffset
, error
;
1590 if ((error
= URLCache_FindFirstFreeEntry(pHeader
, 0x20, (CACHEFILE_ENTRY
**)ppHash
)) != ERROR_SUCCESS
)
1593 dwOffset
= (BYTE
*)*ppHash
- (BYTE
*)pHeader
;
1596 pPrevHash
->dwAddressNext
= dwOffset
;
1598 pHeader
->dwOffsetFirstHashTable
= dwOffset
;
1599 (*ppHash
)->CacheFileEntry
.dwSignature
= HASH_SIGNATURE
;
1600 (*ppHash
)->CacheFileEntry
.dwBlocksUsed
= 0x20;
1601 (*ppHash
)->dwAddressNext
= 0;
1602 (*ppHash
)->dwHashTableNumber
= pPrevHash
? pPrevHash
->dwHashTableNumber
+ 1 : 0;
1603 for (i
= 0; i
< HASHTABLE_SIZE
; i
++)
1605 (*ppHash
)->HashTable
[i
].dwOffsetEntry
= HASHTABLE_FREE
;
1606 (*ppHash
)->HashTable
[i
].dwHashKey
= HASHTABLE_FREE
;
1608 return ERROR_SUCCESS
;
1611 /***********************************************************************
1612 * URLCache_EnumHashTables (Internal)
1614 * Enumerates the hash tables in a container.
1617 * TRUE if an entry was found
1618 * FALSE if there are no more tables to enumerate.
1621 static BOOL
URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader
, DWORD
*pdwHashTableNumber
, HASH_CACHEFILE_ENTRY
** ppHashEntry
)
1623 for (*ppHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1624 URLCache_IsHashEntryValid(pHeader
, *ppHashEntry
);
1625 *ppHashEntry
= URLCache_HashEntryFromOffset(pHeader
, (*ppHashEntry
)->dwAddressNext
))
1627 TRACE("looking at hash table number %d\n", (*ppHashEntry
)->dwHashTableNumber
);
1628 if ((*ppHashEntry
)->dwHashTableNumber
!= *pdwHashTableNumber
)
1630 /* make sure that it is in fact a hash entry */
1631 if ((*ppHashEntry
)->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1633 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&(*ppHashEntry
)->CacheFileEntry
.dwSignature
);
1634 (*pdwHashTableNumber
)++;
1638 TRACE("hash table number %d found\n", *pdwHashTableNumber
);
1644 /***********************************************************************
1645 * URLCache_EnumHashTableEntries (Internal)
1647 * Enumerates entries in a hash table and returns the next non-free entry.
1650 * TRUE if an entry was found
1651 * FALSE if the hash table is empty or there are no more entries to
1655 static BOOL
URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader
, const HASH_CACHEFILE_ENTRY
* pHashEntry
,
1656 DWORD
* index
, const struct _HASH_ENTRY
** ppHashEntry
)
1658 for (; *index
< HASHTABLE_SIZE
; (*index
)++)
1660 if (pHashEntry
->HashTable
[*index
].dwHashKey
==HASHTABLE_FREE
|| pHashEntry
->HashTable
[*index
].dwHashKey
==HASHTABLE_DEL
)
1663 *ppHashEntry
= &pHashEntry
->HashTable
[*index
];
1664 TRACE("entry found %d\n", *index
);
1667 TRACE("no more entries (%d)\n", *index
);
1671 /***********************************************************************
1672 * URLCache_DeleteCacheDirectory (Internal)
1674 * Erase a directory containing an URL cache.
1677 * TRUE success, FALSE failure/aborted.
1680 static BOOL
URLCache_DeleteCacheDirectory(LPCWSTR lpszPath
)
1683 WCHAR path
[MAX_PATH
+ 1];
1684 SHFILEOPSTRUCTW shfos
;
1687 path_len
= strlenW(lpszPath
);
1688 if (path_len
>= MAX_PATH
)
1690 strcpyW(path
, lpszPath
);
1691 path
[path_len
+ 1] = 0; /* double-NUL-terminate path */
1694 shfos
.wFunc
= FO_DELETE
;
1697 shfos
.fFlags
= FOF_NOCONFIRMATION
;
1698 shfos
.fAnyOperationsAborted
= FALSE
;
1699 ret
= SHFileOperationW(&shfos
);
1701 ERR("SHFileOperationW on %s returned %i\n", debugstr_w(path
), ret
);
1702 return !(ret
|| shfos
.fAnyOperationsAborted
);
1705 /***********************************************************************
1706 * URLCache_IsLocked (Internal)
1708 * Checks if entry is locked. Unlocks it if possible.
1710 static BOOL
URLCache_IsLocked(struct _HASH_ENTRY
*hash_entry
, URL_CACHEFILE_ENTRY
*url_entry
)
1713 ULARGE_INTEGER acc_time
, time
;
1715 if ((hash_entry
->dwHashKey
& ((1<<HASHTABLE_FLAG_BITS
)-1)) != HASHTABLE_LOCK
)
1718 GetSystemTimeAsFileTime(&cur_time
);
1719 time
.u
.LowPart
= cur_time
.dwLowDateTime
;
1720 time
.u
.HighPart
= cur_time
.dwHighDateTime
;
1722 acc_time
.u
.LowPart
= url_entry
->LastAccessTime
.dwLowDateTime
;
1723 acc_time
.u
.HighPart
= url_entry
->LastAccessTime
.dwHighDateTime
;
1725 time
.QuadPart
-= acc_time
.QuadPart
;
1727 /* check if entry was locked for at least a day */
1728 if(time
.QuadPart
> (ULONGLONG
)24*60*60*FILETIME_SECOND
) {
1729 URLCache_HashEntrySetFlags(hash_entry
, HASHTABLE_URL
);
1730 url_entry
->dwUseCount
= 0;
1737 /***********************************************************************
1738 * GetUrlCacheEntryInfoExA (WININET.@)
1741 BOOL WINAPI
GetUrlCacheEntryInfoExA(
1743 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1744 LPDWORD lpdwCacheEntryInfoBufSize
,
1746 LPDWORD lpdwReserved
,
1750 LPURLCACHE_HEADER pHeader
;
1751 struct _HASH_ENTRY
* pHashEntry
;
1752 const CACHEFILE_ENTRY
* pEntry
;
1753 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
1754 URLCACHECONTAINER
* pContainer
;
1757 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1758 debugstr_a(lpszUrl
),
1760 lpdwCacheEntryInfoBufSize
,
1766 if ((lpszReserved
!= NULL
) ||
1767 (lpdwReserved
!= NULL
) ||
1768 (lpReserved
!= NULL
))
1770 ERR("Reserved value was not 0\n");
1771 SetLastError(ERROR_INVALID_PARAMETER
);
1774 if (dwFlags
& ~GET_INSTALLED_ENTRY
)
1775 FIXME("ignoring unsupported flags: %x\n", dwFlags
);
1777 error
= URLCacheContainers_FindContainerA(lpszUrl
, &pContainer
);
1778 if (error
!= ERROR_SUCCESS
)
1780 SetLastError(error
);
1784 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
1785 if (error
!= ERROR_SUCCESS
)
1787 SetLastError(error
);
1791 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1794 if (!URLCache_FindHash(pHeader
, lpszUrl
, &pHashEntry
))
1796 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1797 WARN("entry %s not found!\n", debugstr_a(lpszUrl
));
1798 SetLastError(ERROR_FILE_NOT_FOUND
);
1802 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1803 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1805 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1806 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1807 SetLastError(ERROR_FILE_NOT_FOUND
);
1811 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
1812 TRACE("Found URL: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
));
1813 if (pUrlEntry
->dwOffsetHeaderInfo
)
1814 TRACE("Header info: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
1816 if((dwFlags
& GET_INSTALLED_ENTRY
) && !(pUrlEntry
->CacheEntryType
& INSTALLED_CACHE_ENTRY
))
1818 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1819 SetLastError(ERROR_FILE_NOT_FOUND
);
1823 if (lpdwCacheEntryInfoBufSize
)
1825 if (!lpCacheEntryInfo
)
1826 *lpdwCacheEntryInfoBufSize
= 0;
1828 error
= URLCache_CopyEntry(
1832 lpdwCacheEntryInfoBufSize
,
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 * GetUrlCacheEntryInfoA (WININET.@)
1853 BOOL WINAPI
GetUrlCacheEntryInfoA(
1854 IN LPCSTR lpszUrlName
,
1855 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1856 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1859 return GetUrlCacheEntryInfoExA(lpszUrlName
, lpCacheEntryInfo
,
1860 lpdwCacheEntryInfoBufferSize
, NULL
, NULL
, NULL
, 0);
1863 /***********************************************************************
1864 * GetUrlCacheEntryInfoW (WININET.@)
1867 BOOL WINAPI
GetUrlCacheEntryInfoW(LPCWSTR lpszUrl
,
1868 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1869 LPDWORD lpdwCacheEntryInfoBufferSize
)
1871 return GetUrlCacheEntryInfoExW(lpszUrl
, lpCacheEntryInfo
,
1872 lpdwCacheEntryInfoBufferSize
, NULL
, NULL
, NULL
, 0);
1875 /***********************************************************************
1876 * GetUrlCacheEntryInfoExW (WININET.@)
1879 BOOL WINAPI
GetUrlCacheEntryInfoExW(
1881 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1882 LPDWORD lpdwCacheEntryInfoBufSize
,
1883 LPWSTR lpszReserved
,
1884 LPDWORD lpdwReserved
,
1888 LPURLCACHE_HEADER pHeader
;
1889 struct _HASH_ENTRY
* pHashEntry
;
1890 const CACHEFILE_ENTRY
* pEntry
;
1891 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
1892 URLCACHECONTAINER
* pContainer
;
1895 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1896 debugstr_w(lpszUrl
),
1898 lpdwCacheEntryInfoBufSize
,
1904 /* Ignore GET_INSTALLED_ENTRY flag in unicode version of function */
1905 dwFlags
&= ~GET_INSTALLED_ENTRY
;
1907 if ((lpszReserved
!= NULL
) ||
1908 (lpdwReserved
!= NULL
) ||
1909 (lpReserved
!= NULL
))
1911 ERR("Reserved value was not 0\n");
1912 SetLastError(ERROR_INVALID_PARAMETER
);
1916 FIXME("ignoring unsupported flags: %x\n", dwFlags
);
1918 error
= URLCacheContainers_FindContainerW(lpszUrl
, &pContainer
);
1919 if (error
!= ERROR_SUCCESS
)
1921 SetLastError(error
);
1925 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
1926 if (error
!= ERROR_SUCCESS
)
1928 SetLastError(error
);
1932 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1935 if (!URLCache_FindHashW(pHeader
, lpszUrl
, &pHashEntry
))
1937 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1938 WARN("entry %s not found!\n", debugstr_w(lpszUrl
));
1939 SetLastError(ERROR_FILE_NOT_FOUND
);
1943 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1944 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1946 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1947 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1948 SetLastError(ERROR_FILE_NOT_FOUND
);
1952 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
1953 TRACE("Found URL: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
));
1954 TRACE("Header info: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
1956 if (lpdwCacheEntryInfoBufSize
)
1958 if (!lpCacheEntryInfo
)
1959 *lpdwCacheEntryInfoBufSize
= 0;
1961 error
= URLCache_CopyEntry(
1964 (LPINTERNET_CACHE_ENTRY_INFOA
)lpCacheEntryInfo
,
1965 lpdwCacheEntryInfoBufSize
,
1967 TRUE
/* UNICODE */);
1968 if (error
!= ERROR_SUCCESS
)
1970 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1971 SetLastError(error
);
1974 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
1977 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1982 /***********************************************************************
1983 * SetUrlCacheEntryInfoA (WININET.@)
1985 BOOL WINAPI
SetUrlCacheEntryInfoA(
1987 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1988 DWORD dwFieldControl
)
1990 LPURLCACHE_HEADER pHeader
;
1991 struct _HASH_ENTRY
* pHashEntry
;
1992 CACHEFILE_ENTRY
* pEntry
;
1993 URLCACHECONTAINER
* pContainer
;
1996 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
, dwFieldControl
);
1998 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
1999 if (error
!= ERROR_SUCCESS
)
2001 SetLastError(error
);
2005 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2006 if (error
!= ERROR_SUCCESS
)
2008 SetLastError(error
);
2012 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2015 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
2017 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2018 WARN("entry %s not found!\n", debugstr_a(lpszUrlName
));
2019 SetLastError(ERROR_FILE_NOT_FOUND
);
2023 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2024 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2026 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2027 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2028 SetLastError(ERROR_FILE_NOT_FOUND
);
2032 URLCache_SetEntryInfo(
2033 (URL_CACHEFILE_ENTRY
*)pEntry
,
2034 (const INTERNET_CACHE_ENTRY_INFOW
*)lpCacheEntryInfo
,
2037 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2042 /***********************************************************************
2043 * SetUrlCacheEntryInfoW (WININET.@)
2045 BOOL WINAPI
SetUrlCacheEntryInfoW(LPCWSTR lpszUrl
, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
, DWORD dwFieldControl
)
2047 LPURLCACHE_HEADER pHeader
;
2048 struct _HASH_ENTRY
* pHashEntry
;
2049 CACHEFILE_ENTRY
* pEntry
;
2050 URLCACHECONTAINER
* pContainer
;
2053 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl
), lpCacheEntryInfo
, dwFieldControl
);
2055 error
= URLCacheContainers_FindContainerW(lpszUrl
, &pContainer
);
2056 if (error
!= ERROR_SUCCESS
)
2058 SetLastError(error
);
2062 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2063 if (error
!= ERROR_SUCCESS
)
2065 SetLastError(error
);
2069 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2072 if (!URLCache_FindHashW(pHeader
, lpszUrl
, &pHashEntry
))
2074 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2075 WARN("entry %s not found!\n", debugstr_w(lpszUrl
));
2076 SetLastError(ERROR_FILE_NOT_FOUND
);
2080 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2081 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2083 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2084 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2085 SetLastError(ERROR_FILE_NOT_FOUND
);
2089 URLCache_SetEntryInfo(
2090 (URL_CACHEFILE_ENTRY
*)pEntry
,
2094 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2099 /***********************************************************************
2100 * RetrieveUrlCacheEntryFileA (WININET.@)
2103 BOOL WINAPI
RetrieveUrlCacheEntryFileA(
2104 IN LPCSTR lpszUrlName
,
2105 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
2106 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
2110 LPURLCACHE_HEADER pHeader
;
2111 struct _HASH_ENTRY
* pHashEntry
;
2112 CACHEFILE_ENTRY
* pEntry
;
2113 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2114 URLCACHECONTAINER
* pContainer
;
2117 TRACE("(%s, %p, %p, 0x%08x)\n",
2118 debugstr_a(lpszUrlName
),
2120 lpdwCacheEntryInfoBufferSize
,
2123 if (!lpszUrlName
|| !lpdwCacheEntryInfoBufferSize
||
2124 (!lpCacheEntryInfo
&& *lpdwCacheEntryInfoBufferSize
))
2126 SetLastError(ERROR_INVALID_PARAMETER
);
2130 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
2131 if (error
!= ERROR_SUCCESS
)
2133 SetLastError(error
);
2137 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2138 if (error
!= ERROR_SUCCESS
)
2140 SetLastError(error
);
2144 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2147 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
2149 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2150 TRACE("entry %s not found!\n", lpszUrlName
);
2151 SetLastError(ERROR_FILE_NOT_FOUND
);
2155 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2156 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2158 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2159 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2160 SetLastError(ERROR_FILE_NOT_FOUND
);
2164 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2165 if (!pUrlEntry
->dwOffsetLocalName
)
2167 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2168 SetLastError(ERROR_INVALID_DATA
);
2172 TRACE("Found URL: %s\n", (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
2173 TRACE("Header info: %s\n", (LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
);
2175 error
= URLCache_CopyEntry(pContainer
, pHeader
, lpCacheEntryInfo
,
2176 lpdwCacheEntryInfoBufferSize
, pUrlEntry
,
2178 if (error
!= ERROR_SUCCESS
)
2180 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2181 SetLastError(error
);
2184 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
2186 pUrlEntry
->dwHitRate
++;
2187 pUrlEntry
->dwUseCount
++;
2188 URLCache_HashEntrySetFlags(pHashEntry
, HASHTABLE_LOCK
);
2189 GetSystemTimeAsFileTime(&pUrlEntry
->LastAccessTime
);
2191 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2196 /***********************************************************************
2197 * RetrieveUrlCacheEntryFileW (WININET.@)
2200 BOOL WINAPI
RetrieveUrlCacheEntryFileW(
2201 IN LPCWSTR lpszUrlName
,
2202 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
2203 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
2207 LPURLCACHE_HEADER pHeader
;
2208 struct _HASH_ENTRY
* pHashEntry
;
2209 CACHEFILE_ENTRY
* pEntry
;
2210 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2211 URLCACHECONTAINER
* pContainer
;
2214 TRACE("(%s, %p, %p, 0x%08x)\n",
2215 debugstr_w(lpszUrlName
),
2217 lpdwCacheEntryInfoBufferSize
,
2220 if (!lpszUrlName
|| !lpdwCacheEntryInfoBufferSize
||
2221 (!lpCacheEntryInfo
&& *lpdwCacheEntryInfoBufferSize
))
2223 SetLastError(ERROR_INVALID_PARAMETER
);
2227 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2228 if (error
!= ERROR_SUCCESS
)
2230 SetLastError(error
);
2234 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2235 if (error
!= ERROR_SUCCESS
)
2237 SetLastError(error
);
2241 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2244 if (!URLCache_FindHashW(pHeader
, lpszUrlName
, &pHashEntry
))
2246 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2247 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName
));
2248 SetLastError(ERROR_FILE_NOT_FOUND
);
2252 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2253 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2255 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2256 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2257 SetLastError(ERROR_FILE_NOT_FOUND
);
2261 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2262 if (!pUrlEntry
->dwOffsetLocalName
)
2264 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2265 SetLastError(ERROR_INVALID_DATA
);
2269 TRACE("Found URL: %s\n", (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
2270 TRACE("Header info: %s\n", (LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
);
2272 error
= URLCache_CopyEntry(
2275 (LPINTERNET_CACHE_ENTRY_INFOA
)lpCacheEntryInfo
,
2276 lpdwCacheEntryInfoBufferSize
,
2278 TRUE
/* UNICODE */);
2279 if (error
!= ERROR_SUCCESS
)
2281 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2282 SetLastError(error
);
2285 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
2287 pUrlEntry
->dwHitRate
++;
2288 pUrlEntry
->dwUseCount
++;
2289 URLCache_HashEntrySetFlags(pHashEntry
, HASHTABLE_LOCK
);
2290 GetSystemTimeAsFileTime(&pUrlEntry
->LastAccessTime
);
2292 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2297 static BOOL
DeleteUrlCacheEntryInternal(const URLCACHECONTAINER
* pContainer
,
2298 LPURLCACHE_HEADER pHeader
, struct _HASH_ENTRY
*pHashEntry
)
2300 CACHEFILE_ENTRY
* pEntry
;
2301 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2303 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2304 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2306 FIXME("Trying to delete entry of unknown format %s\n",
2307 debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2308 SetLastError(ERROR_FILE_NOT_FOUND
);
2312 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2313 if(URLCache_IsLocked(pHashEntry
, pUrlEntry
))
2315 TRACE("Trying to delete locked entry\n");
2316 pUrlEntry
->CacheEntryType
|= PENDING_DELETE_CACHE_ENTRY
;
2317 SetLastError(ERROR_SHARING_VIOLATION
);
2321 if(!URLCache_DeleteFile(pContainer
, pHeader
, pUrlEntry
))
2323 URLCache_DeleteEntry(pHeader
, pEntry
);
2327 /* Add entry to leaked files list */
2328 pUrlEntry
->CacheFileEntry
.dwSignature
= LEAK_SIGNATURE
;
2329 pUrlEntry
->dwExemptDelta
= pHeader
->options
[CACHE_HEADER_DATA_ROOT_LEAK_OFFSET
];
2330 pHeader
->options
[CACHE_HEADER_DATA_ROOT_LEAK_OFFSET
] = pHashEntry
->dwOffsetEntry
;
2333 URLCache_DeleteEntryFromHash(pHashEntry
);
2337 static HANDLE free_cache_running
;
2338 static HANDLE dll_unload_event
;
2339 static DWORD WINAPI
handle_full_cache_worker(void *param
)
2341 FreeUrlCacheSpaceW(NULL
, 20, 0);
2342 ReleaseSemaphore(free_cache_running
, 1, NULL
);
2346 static void handle_full_cache(void)
2348 if(WaitForSingleObject(free_cache_running
, 0) == WAIT_OBJECT_0
) {
2349 if(!QueueUserWorkItem(handle_full_cache_worker
, NULL
, 0))
2350 ReleaseSemaphore(free_cache_running
, 1, NULL
);
2354 /* Enumerates entries in cache, allows cache unlocking between calls. */
2355 static BOOL
urlcache_next_entry(URLCACHE_HEADER
*header
, DWORD
*hash_table_off
, DWORD
*hash_table_entry
,
2356 struct _HASH_ENTRY
**hash_entry
, CACHEFILE_ENTRY
**entry
)
2358 HASH_CACHEFILE_ENTRY
*hashtable_entry
;
2363 if(!*hash_table_off
) {
2364 *hash_table_off
= header
->dwOffsetFirstHashTable
;
2365 *hash_table_entry
= 0;
2367 hashtable_entry
= URLCache_HashEntryFromOffset(header
, *hash_table_off
);
2369 if(*hash_table_off
>= header
->dwFileSize
) {
2370 *hash_table_off
= 0;
2374 hashtable_entry
= URLCache_HashEntryFromOffset(header
, *hash_table_off
);
2377 if(hashtable_entry
->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
) {
2378 *hash_table_off
= 0;
2383 if(*hash_table_entry
>= HASHTABLE_SIZE
) {
2384 *hash_table_off
= hashtable_entry
->dwAddressNext
;
2385 if(!*hash_table_off
) {
2386 *hash_table_off
= 0;
2390 hashtable_entry
= URLCache_HashEntryFromOffset(header
, *hash_table_off
);
2391 *hash_table_entry
= 0;
2394 if(hashtable_entry
->HashTable
[*hash_table_entry
].dwHashKey
!= HASHTABLE_DEL
&&
2395 hashtable_entry
->HashTable
[*hash_table_entry
].dwHashKey
!= HASHTABLE_FREE
) {
2396 *hash_entry
= &hashtable_entry
->HashTable
[*hash_table_entry
];
2397 *entry
= (CACHEFILE_ENTRY
*)((LPBYTE
)header
+ hashtable_entry
->HashTable
[*hash_table_entry
].dwOffsetEntry
);
2398 (*hash_table_entry
)++;
2402 (*hash_table_entry
)++;
2405 *hash_table_off
= 0;
2409 /* Rates an urlcache entry to determine if it can be deleted.
2411 * Score 0 means that entry can safely be removed, the bigger rating
2412 * the smaller chance of entry being removed.
2413 * DWORD_MAX means that entry can't be deleted at all.
2415 * Rating system is currently not fully compatible with native implementation.
2417 static DWORD
urlcache_rate_entry(URL_CACHEFILE_ENTRY
*url_entry
, FILETIME
*cur_time
)
2419 ULARGE_INTEGER time
, access_time
;
2422 access_time
.u
.LowPart
= url_entry
->LastAccessTime
.dwLowDateTime
;
2423 access_time
.u
.HighPart
= url_entry
->LastAccessTime
.dwHighDateTime
;
2425 time
.u
.LowPart
= cur_time
->dwLowDateTime
;
2426 time
.u
.HighPart
= cur_time
->dwHighDateTime
;
2428 /* Don't touch entries that were added less than 10 minutes ago */
2429 if(time
.QuadPart
< access_time
.QuadPart
+ (ULONGLONG
)10*60*FILETIME_SECOND
)
2432 if(url_entry
->CacheEntryType
& STICKY_CACHE_ENTRY
)
2433 if(time
.QuadPart
< access_time
.QuadPart
+ (ULONGLONG
)url_entry
->dwExemptDelta
*FILETIME_SECOND
)
2436 time
.QuadPart
= (time
.QuadPart
-access_time
.QuadPart
)/FILETIME_SECOND
;
2437 rating
= 400*60*60*24/(60*60*24+time
.QuadPart
);
2439 if(url_entry
->dwHitRate
> 100)
2442 rating
+= url_entry
->dwHitRate
;
2447 static int dword_cmp(const void *p1
, const void *p2
)
2449 return *(const DWORD
*)p1
- *(const DWORD
*)p2
;
2452 /***********************************************************************
2453 * FreeUrlCacheSpaceW (WININET.@)
2455 * Frees up some cache.
2458 * cache_path [I] Which volume to free up from, or NULL if you don't care.
2459 * size [I] How many percents of the cache should be free.
2460 * filter [I] Which entries can't be deleted (CacheEntryType)
2463 * TRUE success. FALSE failure.
2466 * This implementation just retrieves the path of the cache directory, and
2467 * deletes its contents from the filesystem. The correct approach would
2468 * probably be to implement and use {FindFirst,FindNext,Delete}UrlCacheGroup().
2470 BOOL WINAPI
FreeUrlCacheSpaceW(LPCWSTR cache_path
, DWORD size
, DWORD filter
)
2472 URLCACHECONTAINER
*container
;
2473 DWORD path_len
, err
;
2475 TRACE("(%s, %x, %x)\n", debugstr_w(cache_path
), size
, filter
);
2477 if(size
<1 || size
>100) {
2478 SetLastError(ERROR_INVALID_PARAMETER
);
2483 path_len
= strlenW(cache_path
);
2484 if(cache_path
[path_len
-1] == '\\')
2490 if(size
==100 && !filter
) {
2491 LIST_FOR_EACH_ENTRY(container
, &UrlContainers
, URLCACHECONTAINER
, entry
)
2493 /* When cache_path==NULL only clean Temporary Internet Files */
2494 if((!path_len
&& container
->cache_prefix
[0]==0) ||
2495 (path_len
&& !strncmpiW(container
->path
, cache_path
, path_len
) &&
2496 (container
->path
[path_len
]=='\0' || container
->path
[path_len
]=='\\')))
2500 WaitForSingleObject(container
->hMutex
, INFINITE
);
2502 /* unlock, delete, recreate and lock cache */
2503 URLCacheContainer_CloseIndex(container
);
2504 ret_del
= URLCache_DeleteCacheDirectory(container
->path
);
2505 err
= URLCacheContainer_OpenIndex(container
, MIN_BLOCK_NO
);
2507 ReleaseMutex(container
->hMutex
);
2508 if(!ret_del
|| (err
!= ERROR_SUCCESS
))
2516 LIST_FOR_EACH_ENTRY(container
, &UrlContainers
, URLCACHECONTAINER
, entry
)
2518 URLCACHE_HEADER
*header
;
2519 struct _HASH_ENTRY
*hash_entry
;
2520 CACHEFILE_ENTRY
*entry
;
2521 URL_CACHEFILE_ENTRY
*url_entry
;
2522 ULONGLONG desired_size
, cur_size
;
2523 DWORD delete_factor
, hash_table_off
, hash_table_entry
;
2524 DWORD rate
[100], rate_no
;
2527 if((path_len
|| container
->cache_prefix
[0]!=0) &&
2528 (!path_len
|| strncmpiW(container
->path
, cache_path
, path_len
) ||
2529 (container
->path
[path_len
]!='\0' && container
->path
[path_len
]!='\\')))
2532 err
= URLCacheContainer_OpenIndex(container
, MIN_BLOCK_NO
);
2533 if(err
!= ERROR_SUCCESS
)
2536 header
= URLCacheContainer_LockIndex(container
);
2540 urlcache_clean_leaked_entries(container
, header
);
2542 desired_size
= header
->CacheLimit
.QuadPart
*(100-size
)/100;
2543 cur_size
= header
->CacheUsage
.QuadPart
+header
->ExemptUsage
.QuadPart
;
2544 if(cur_size
<= desired_size
)
2547 delete_factor
= (cur_size
-desired_size
)*100/cur_size
;
2549 if(!delete_factor
) {
2550 URLCacheContainer_UnlockIndex(container
, header
);
2555 hash_table_entry
= 0;
2557 GetSystemTimeAsFileTime(&cur_time
);
2558 while(rate_no
<sizeof(rate
)/sizeof(*rate
) &&
2559 urlcache_next_entry(header
, &hash_table_off
, &hash_table_entry
, &hash_entry
, &entry
)) {
2560 if(entry
->dwSignature
!= URL_SIGNATURE
) {
2561 WARN("only url entries are currently supported\n");
2565 url_entry
= (URL_CACHEFILE_ENTRY
*)entry
;
2566 if(url_entry
->CacheEntryType
& filter
)
2569 rate
[rate_no
] = urlcache_rate_entry(url_entry
, &cur_time
);
2570 if(rate
[rate_no
] != -1)
2575 TRACE("nothing to delete\n");
2576 URLCacheContainer_UnlockIndex(container
, header
);
2580 qsort(rate
, rate_no
, sizeof(DWORD
), dword_cmp
);
2582 delete_factor
= delete_factor
*rate_no
/100;
2583 delete_factor
= rate
[delete_factor
];
2584 TRACE("deleting files with rating %d or less\n", delete_factor
);
2587 while(urlcache_next_entry(header
, &hash_table_off
, &hash_table_entry
, &hash_entry
, &entry
)) {
2588 if(entry
->dwSignature
!= URL_SIGNATURE
)
2591 url_entry
= (URL_CACHEFILE_ENTRY
*)entry
;
2592 if(url_entry
->CacheEntryType
& filter
)
2595 if(urlcache_rate_entry(url_entry
, &cur_time
) <= delete_factor
) {
2596 TRACE("deleting file: %s\n", (char*)url_entry
+url_entry
->dwOffsetLocalName
);
2597 DeleteUrlCacheEntryInternal(container
, header
, hash_entry
);
2599 if(header
->CacheUsage
.QuadPart
+header
->ExemptUsage
.QuadPart
<= desired_size
)
2602 /* Allow other threads to use cache while cleaning */
2603 URLCacheContainer_UnlockIndex(container
, header
);
2604 if(WaitForSingleObject(dll_unload_event
, 0) == WAIT_OBJECT_0
) {
2605 TRACE("got dll_unload_event - finishing\n");
2609 header
= URLCacheContainer_LockIndex(container
);
2613 TRACE("cache size after cleaning 0x%s/0x%s\n",
2614 wine_dbgstr_longlong(header
->CacheUsage
.QuadPart
+header
->ExemptUsage
.QuadPart
),
2615 wine_dbgstr_longlong(header
->CacheLimit
.QuadPart
));
2616 URLCacheContainer_UnlockIndex(container
, header
);
2622 /***********************************************************************
2623 * FreeUrlCacheSpaceA (WININET.@)
2625 * See FreeUrlCacheSpaceW.
2627 BOOL WINAPI
FreeUrlCacheSpaceA(LPCSTR lpszCachePath
, DWORD dwSize
, DWORD dwFilter
)
2630 LPWSTR path
= heap_strdupAtoW(lpszCachePath
);
2631 if (lpszCachePath
== NULL
|| path
!= NULL
)
2632 ret
= FreeUrlCacheSpaceW(path
, dwSize
, dwFilter
);
2637 /***********************************************************************
2638 * UnlockUrlCacheEntryFileA (WININET.@)
2641 BOOL WINAPI
UnlockUrlCacheEntryFileA(
2642 IN LPCSTR lpszUrlName
,
2646 LPURLCACHE_HEADER pHeader
;
2647 struct _HASH_ENTRY
* pHashEntry
;
2648 CACHEFILE_ENTRY
* pEntry
;
2649 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2650 URLCACHECONTAINER
* pContainer
;
2653 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName
), dwReserved
);
2657 ERR("dwReserved != 0\n");
2658 SetLastError(ERROR_INVALID_PARAMETER
);
2662 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
2663 if (error
!= ERROR_SUCCESS
)
2665 SetLastError(error
);
2669 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2670 if (error
!= ERROR_SUCCESS
)
2672 SetLastError(error
);
2676 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2679 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
2681 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2682 TRACE("entry %s not found!\n", lpszUrlName
);
2683 SetLastError(ERROR_FILE_NOT_FOUND
);
2687 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2688 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2690 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2691 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2692 SetLastError(ERROR_FILE_NOT_FOUND
);
2696 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2698 if (pUrlEntry
->dwUseCount
== 0)
2700 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2703 pUrlEntry
->dwUseCount
--;
2704 if (!pUrlEntry
->dwUseCount
)
2706 URLCache_HashEntrySetFlags(pHashEntry
, HASHTABLE_URL
);
2707 if (pUrlEntry
->CacheEntryType
& PENDING_DELETE_CACHE_ENTRY
)
2708 DeleteUrlCacheEntryInternal(pContainer
, pHeader
, pHashEntry
);
2711 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2716 /***********************************************************************
2717 * UnlockUrlCacheEntryFileW (WININET.@)
2720 BOOL WINAPI
UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName
, DWORD dwReserved
)
2722 LPURLCACHE_HEADER pHeader
;
2723 struct _HASH_ENTRY
* pHashEntry
;
2724 CACHEFILE_ENTRY
* pEntry
;
2725 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2726 URLCACHECONTAINER
* pContainer
;
2729 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName
), dwReserved
);
2733 ERR("dwReserved != 0\n");
2734 SetLastError(ERROR_INVALID_PARAMETER
);
2738 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2739 if (error
!= ERROR_SUCCESS
)
2741 SetLastError(error
);
2745 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2746 if (error
!= ERROR_SUCCESS
)
2748 SetLastError(error
);
2752 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2755 if (!URLCache_FindHashW(pHeader
, lpszUrlName
, &pHashEntry
))
2757 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2758 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName
));
2759 SetLastError(ERROR_FILE_NOT_FOUND
);
2763 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2764 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2766 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2767 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2768 SetLastError(ERROR_FILE_NOT_FOUND
);
2772 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2774 if (pUrlEntry
->dwUseCount
== 0)
2776 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2779 pUrlEntry
->dwUseCount
--;
2780 if (!pUrlEntry
->dwUseCount
)
2781 URLCache_HashEntrySetFlags(pHashEntry
, HASHTABLE_URL
);
2783 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2788 /***********************************************************************
2789 * CreateUrlCacheEntryA (WININET.@)
2792 BOOL WINAPI
CreateUrlCacheEntryA(
2793 IN LPCSTR lpszUrlName
,
2794 IN DWORD dwExpectedFileSize
,
2795 IN LPCSTR lpszFileExtension
,
2796 OUT LPSTR lpszFileName
,
2801 WCHAR
*file_extension
= NULL
;
2802 WCHAR file_name
[MAX_PATH
];
2803 BOOL bSuccess
= FALSE
;
2806 TRACE("(%s %d %s %p %d)\n", debugstr_a(lpszUrlName
), dwExpectedFileSize
,
2807 debugstr_a(lpszFileExtension
), lpszFileName
, dwReserved
);
2809 if (lpszUrlName
&& (url_name
= heap_strdupAtoW(lpszUrlName
)))
2811 if (!lpszFileExtension
|| (file_extension
= heap_strdupAtoW(lpszFileExtension
)))
2813 if (CreateUrlCacheEntryW(url_name
, dwExpectedFileSize
, file_extension
, file_name
, dwReserved
))
2815 if (WideCharToMultiByte(CP_ACP
, 0, file_name
, -1, lpszFileName
, MAX_PATH
, NULL
, NULL
) < MAX_PATH
)
2821 dwError
= GetLastError();
2826 dwError
= GetLastError();
2828 heap_free(file_extension
);
2832 dwError
= GetLastError();
2834 heap_free(url_name
);
2835 if (!bSuccess
) SetLastError(dwError
);
2839 /***********************************************************************
2840 * CreateUrlCacheEntryW (WININET.@)
2843 BOOL WINAPI
CreateUrlCacheEntryW(
2844 IN LPCWSTR lpszUrlName
,
2845 IN DWORD dwExpectedFileSize
,
2846 IN LPCWSTR lpszFileExtension
,
2847 OUT LPWSTR lpszFileName
,
2851 URLCACHECONTAINER
* pContainer
;
2852 LPURLCACHE_HEADER pHeader
;
2853 CHAR szFile
[MAX_PATH
];
2854 WCHAR szExtension
[MAX_PATH
];
2855 LPCWSTR lpszUrlPart
;
2857 LPCWSTR lpszFileNameExtension
;
2858 LPWSTR lpszFileNameNoPath
;
2860 int countnoextension
;
2863 BOOL bFound
= FALSE
;
2869 static const WCHAR szWWW
[] = {'w','w','w',0};
2870 static const WCHAR fmt
[] = {'%','0','8','X','%','s',0};
2872 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2873 debugstr_w(lpszUrlName
),
2875 debugstr_w(lpszFileExtension
),
2880 FIXME("dwReserved 0x%08x\n", dwReserved
);
2882 lpszUrlEnd
= lpszUrlName
+ strlenW(lpszUrlName
);
2884 if (((lpszUrlEnd
- lpszUrlName
) > 1) && (*(lpszUrlEnd
- 1) == '/' || *(lpszUrlEnd
- 1) == '\\'))
2887 lpszUrlPart
= memchrW(lpszUrlName
, '?', lpszUrlEnd
- lpszUrlName
);
2889 lpszUrlPart
= memchrW(lpszUrlName
, '#', lpszUrlEnd
- lpszUrlName
);
2891 lpszUrlEnd
= lpszUrlPart
;
2893 for (lpszUrlPart
= lpszUrlEnd
;
2894 (lpszUrlPart
>= lpszUrlName
);
2897 if ((*lpszUrlPart
== '/' || *lpszUrlPart
== '\\') && ((lpszUrlEnd
- lpszUrlPart
) > 1))
2904 if (!lstrcmpW(lpszUrlPart
, szWWW
))
2906 lpszUrlPart
+= lstrlenW(szWWW
);
2909 count
= lpszUrlEnd
- lpszUrlPart
;
2911 if (bFound
&& (count
< MAX_PATH
))
2913 int len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlPart
, count
, szFile
, sizeof(szFile
) - 1, NULL
, NULL
);
2917 while(len
&& szFile
[--len
] == '/') szFile
[len
] = '\0';
2919 /* FIXME: get rid of illegal characters like \, / and : */
2923 FIXME("need to generate a random filename\n");
2926 TRACE("File name: %s\n", debugstr_a(szFile
));
2928 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2929 if (error
!= ERROR_SUCCESS
)
2931 SetLastError(error
);
2935 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2936 if (error
!= ERROR_SUCCESS
)
2938 SetLastError(error
);
2942 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2945 if(pHeader
->DirectoryCount
)
2946 CacheDir
= (BYTE
)(rand() % pHeader
->DirectoryCount
);
2948 CacheDir
= CACHE_CONTAINER_NO_SUBDIR
;
2950 lBufferSize
= MAX_PATH
* sizeof(WCHAR
);
2951 if (!URLCache_LocalFileNameToPathW(pContainer
, pHeader
, szFile
, CacheDir
, lpszFileName
, &lBufferSize
))
2953 WARN("Failed to get full path for filename %s, needed %u bytes.\n",
2954 debugstr_a(szFile
), lBufferSize
);
2955 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2959 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2961 for (lpszFileNameNoPath
= lpszFileName
+ lBufferSize
/ sizeof(WCHAR
) - 2;
2962 lpszFileNameNoPath
>= lpszFileName
;
2963 --lpszFileNameNoPath
)
2965 if (*lpszFileNameNoPath
== '/' || *lpszFileNameNoPath
== '\\')
2969 countnoextension
= lstrlenW(lpszFileNameNoPath
);
2970 lpszFileNameExtension
= PathFindExtensionW(lpszFileNameNoPath
);
2971 if (lpszFileNameExtension
)
2972 countnoextension
-= lstrlenW(lpszFileNameExtension
);
2973 *szExtension
= '\0';
2975 if (lpszFileExtension
)
2977 szExtension
[0] = '.';
2978 lstrcpyW(szExtension
+1, lpszFileExtension
);
2981 for (i
= 0; i
< 255; i
++)
2983 static const WCHAR szFormat
[] = {'[','%','u',']','%','s',0};
2986 wsprintfW(lpszFileNameNoPath
+ countnoextension
, szFormat
, i
, szExtension
);
2987 for (p
= lpszFileNameNoPath
+ 1; *p
; p
++)
2993 case '/': case '\\':
3000 if (p
[-1] == ' ' || p
[-1] == '.') p
[-1] = '_';
3002 TRACE("Trying: %s\n", debugstr_w(lpszFileName
));
3003 hFile
= CreateFileW(lpszFileName
, GENERIC_READ
, 0, NULL
, CREATE_NEW
, 0, NULL
);
3004 if (hFile
!= INVALID_HANDLE_VALUE
)
3011 GetSystemTimeAsFileTime(&ft
);
3012 wsprintfW(lpszFileNameNoPath
+ countnoextension
, fmt
, ft
.dwLowDateTime
, szExtension
);
3014 TRACE("Trying: %s\n", debugstr_w(lpszFileName
));
3015 hFile
= CreateFileW(lpszFileName
, GENERIC_READ
, 0, NULL
, CREATE_NEW
, 0, NULL
);
3016 if (hFile
!= INVALID_HANDLE_VALUE
)
3022 WARN("Could not find a unique filename\n");
3026 /***********************************************************************
3027 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
3029 * The bug we are compensating for is that some drongo at Microsoft
3030 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
3031 * As a consequence, CommitUrlCacheEntryA has been effectively
3032 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
3033 * is still defined as LPCWSTR. The result (other than madness) is
3034 * that we always need to store lpHeaderInfo in CP_ACP rather than
3035 * in UTF16, and we need to avoid converting lpHeaderInfo in
3036 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
3037 * result will lose data for arbitrary binary data.
3040 static BOOL
CommitUrlCacheEntryInternal(
3041 IN LPCWSTR lpszUrlName
,
3042 IN LPCWSTR lpszLocalFileName
,
3043 IN FILETIME ExpireTime
,
3044 IN FILETIME LastModifiedTime
,
3045 IN DWORD CacheEntryType
,
3046 IN LPBYTE lpHeaderInfo
,
3047 IN DWORD dwHeaderSize
,
3048 IN LPCWSTR lpszFileExtension
,
3049 IN LPCWSTR lpszOriginalUrl
3052 URLCACHECONTAINER
* pContainer
;
3053 LPURLCACHE_HEADER pHeader
;
3054 struct _HASH_ENTRY
* pHashEntry
;
3055 CACHEFILE_ENTRY
* pEntry
;
3056 URL_CACHEFILE_ENTRY
* pUrlEntry
;
3057 DWORD url_entry_offset
;
3058 DWORD dwBytesNeeded
= DWORD_ALIGN(sizeof(*pUrlEntry
));
3059 DWORD dwOffsetLocalFileName
= 0;
3060 DWORD dwOffsetHeader
= 0;
3061 DWORD dwOffsetFileExtension
= 0;
3062 WIN32_FILE_ATTRIBUTE_DATA file_attr
;
3063 LARGE_INTEGER file_size
;
3065 char achFile
[MAX_PATH
];
3066 LPSTR lpszUrlNameA
= NULL
;
3067 LPSTR lpszFileExtensionA
= NULL
;
3068 char *pchLocalFileName
= 0;
3070 DWORD exempt_delta
= 0;
3073 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
3074 debugstr_w(lpszUrlName
),
3075 debugstr_w(lpszLocalFileName
),
3079 debugstr_w(lpszFileExtension
),
3080 debugstr_w(lpszOriginalUrl
));
3082 if (CacheEntryType
& STICKY_CACHE_ENTRY
&& !lpszLocalFileName
)
3084 SetLastError(ERROR_INVALID_PARAMETER
);
3087 if (lpszOriginalUrl
)
3088 WARN(": lpszOriginalUrl ignored\n");
3090 memset(&file_attr
, 0, sizeof(file_attr
));
3091 if (lpszLocalFileName
)
3093 if(!GetFileAttributesExW(lpszLocalFileName
, GetFileExInfoStandard
, &file_attr
))
3096 file_size
.u
.LowPart
= file_attr
.nFileSizeLow
;
3097 file_size
.u
.HighPart
= file_attr
.nFileSizeHigh
;
3099 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
3100 if (error
!= ERROR_SUCCESS
)
3102 SetLastError(error
);
3106 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
3107 if (error
!= ERROR_SUCCESS
)
3109 SetLastError(error
);
3113 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3116 lpszUrlNameA
= heap_strdupWtoA(lpszUrlName
);
3119 error
= GetLastError();
3123 if (lpszFileExtension
&& !(lpszFileExtensionA
= heap_strdupWtoA(lpszFileExtension
)))
3125 error
= GetLastError();
3129 if (URLCache_FindHash(pHeader
, lpszUrlNameA
, &pHashEntry
))
3131 URL_CACHEFILE_ENTRY
*pUrlEntry
= (URL_CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3132 if (URLCache_IsLocked(pHashEntry
, pUrlEntry
))
3134 TRACE("Trying to overwrite locked entry\n");
3135 error
= ERROR_SHARING_VIOLATION
;
3139 hit_rate
= pUrlEntry
->dwHitRate
;
3140 exempt_delta
= pUrlEntry
->dwExemptDelta
;
3141 DeleteUrlCacheEntryInternal(pContainer
, pHeader
, pHashEntry
);
3144 if (pHeader
->DirectoryCount
)
3147 cDirectory
= CACHE_CONTAINER_NO_SUBDIR
;
3149 if (lpszLocalFileName
)
3151 BOOL bFound
= FALSE
;
3153 if (strncmpW(lpszLocalFileName
, pContainer
->path
, lstrlenW(pContainer
->path
)))
3155 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName
), debugstr_w(pContainer
->path
));
3156 error
= ERROR_INVALID_PARAMETER
;
3160 /* skip container path prefix */
3161 lpszLocalFileName
+= lstrlenW(pContainer
->path
);
3163 WideCharToMultiByte(CP_ACP
, 0, lpszLocalFileName
, -1, achFile
, MAX_PATH
, NULL
, NULL
);
3164 pchLocalFileName
= achFile
;
3166 if(pHeader
->DirectoryCount
)
3168 for (cDirectory
= 0; cDirectory
< pHeader
->DirectoryCount
; cDirectory
++)
3170 if (!strncmp(pHeader
->directory_data
[cDirectory
].filename
, pchLocalFileName
, DIR_LENGTH
))
3179 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName
));
3180 error
= ERROR_INVALID_PARAMETER
;
3184 lpszLocalFileName
+= DIR_LENGTH
+ 1;
3185 pchLocalFileName
+= DIR_LENGTH
+ 1;
3189 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(lpszUrlNameA
) + 1);
3190 if (lpszLocalFileName
)
3192 dwOffsetLocalFileName
= dwBytesNeeded
;
3193 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(pchLocalFileName
) + 1);
3197 dwOffsetHeader
= dwBytesNeeded
;
3198 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ dwHeaderSize
);
3200 if (lpszFileExtensionA
)
3202 dwOffsetFileExtension
= dwBytesNeeded
;
3203 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(lpszFileExtensionA
) + 1);
3206 /* round up to next block */
3207 if (dwBytesNeeded
% BLOCKSIZE
)
3209 dwBytesNeeded
-= dwBytesNeeded
% BLOCKSIZE
;
3210 dwBytesNeeded
+= BLOCKSIZE
;
3213 error
= URLCache_FindFirstFreeEntry(pHeader
, dwBytesNeeded
/ BLOCKSIZE
, &pEntry
);
3214 while (error
== ERROR_HANDLE_DISK_FULL
)
3216 error
= URLCacheContainer_CleanIndex(pContainer
, &pHeader
);
3217 if (error
== ERROR_SUCCESS
)
3218 error
= URLCache_FindFirstFreeEntry(pHeader
, dwBytesNeeded
/ BLOCKSIZE
, &pEntry
);
3220 if (error
!= ERROR_SUCCESS
)
3223 /* FindFirstFreeEntry fills in blocks used */
3224 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
3225 url_entry_offset
= (LPBYTE
)pUrlEntry
- (LPBYTE
)pHeader
;
3226 pUrlEntry
->CacheFileEntry
.dwSignature
= URL_SIGNATURE
;
3227 pUrlEntry
->CacheDir
= cDirectory
;
3228 pUrlEntry
->CacheEntryType
= CacheEntryType
| pContainer
->default_entry_type
;
3229 pUrlEntry
->dwHeaderInfoSize
= dwHeaderSize
;
3230 if ((CacheEntryType
& STICKY_CACHE_ENTRY
) && !exempt_delta
)
3232 /* Sticky entries have a default exempt time of one day */
3233 exempt_delta
= 86400;
3235 pUrlEntry
->dwExemptDelta
= exempt_delta
;
3236 pUrlEntry
->dwHitRate
= hit_rate
+1;
3237 pUrlEntry
->dwOffsetFileExtension
= dwOffsetFileExtension
;
3238 pUrlEntry
->dwOffsetHeaderInfo
= dwOffsetHeader
;
3239 pUrlEntry
->dwOffsetLocalName
= dwOffsetLocalFileName
;
3240 pUrlEntry
->dwOffsetUrl
= DWORD_ALIGN(sizeof(*pUrlEntry
));
3241 pUrlEntry
->size
.QuadPart
= file_size
.QuadPart
;
3242 pUrlEntry
->dwUseCount
= 0;
3243 GetSystemTimeAsFileTime(&pUrlEntry
->LastAccessTime
);
3244 pUrlEntry
->LastModifiedTime
= LastModifiedTime
;
3245 URLCache_FileTimeToDosDateTime(&pUrlEntry
->LastAccessTime
, &pUrlEntry
->wLastSyncDate
, &pUrlEntry
->wLastSyncTime
);
3246 URLCache_FileTimeToDosDateTime(&ExpireTime
, &pUrlEntry
->wExpiredDate
, &pUrlEntry
->wExpiredTime
);
3247 URLCache_FileTimeToDosDateTime(&file_attr
.ftLastWriteTime
, &pUrlEntry
->LastWriteDate
, &pUrlEntry
->LastWriteTime
);
3250 pUrlEntry
->dwUnknown1
= 0;
3251 pUrlEntry
->dwUnknown2
= 0;
3252 pUrlEntry
->dwUnknown3
= 0x60;
3253 pUrlEntry
->Unknown4
= 0;
3254 pUrlEntry
->wUnknown5
= 0x1010;
3255 pUrlEntry
->dwUnknown7
= 0;
3256 pUrlEntry
->dwUnknown8
= 0;
3259 strcpy((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, lpszUrlNameA
);
3260 if (dwOffsetLocalFileName
)
3261 strcpy((LPSTR
)((LPBYTE
)pUrlEntry
+ dwOffsetLocalFileName
), pchLocalFileName
);
3263 memcpy((LPBYTE
)pUrlEntry
+ dwOffsetHeader
, lpHeaderInfo
, dwHeaderSize
);
3264 if (dwOffsetFileExtension
)
3265 strcpy((LPSTR
)((LPBYTE
)pUrlEntry
+ dwOffsetFileExtension
), lpszFileExtensionA
);
3267 error
= URLCache_AddEntryToHash(pHeader
, lpszUrlNameA
, url_entry_offset
, HASHTABLE_URL
);
3268 while (error
== ERROR_HANDLE_DISK_FULL
)
3270 error
= URLCacheContainer_CleanIndex(pContainer
, &pHeader
);
3271 if (error
== ERROR_SUCCESS
)
3273 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ url_entry_offset
);
3274 error
= URLCache_AddEntryToHash(pHeader
, lpszUrlNameA
,
3275 url_entry_offset
, HASHTABLE_URL
);
3278 if (error
!= ERROR_SUCCESS
)
3279 URLCache_DeleteEntry(pHeader
, &pUrlEntry
->CacheFileEntry
);
3282 if (pUrlEntry
->CacheDir
< pHeader
->DirectoryCount
)
3283 pHeader
->directory_data
[pUrlEntry
->CacheDir
].dwNumFiles
++;
3284 if (CacheEntryType
& STICKY_CACHE_ENTRY
)
3285 pHeader
->ExemptUsage
.QuadPart
+= file_size
.QuadPart
;
3287 pHeader
->CacheUsage
.QuadPart
+= file_size
.QuadPart
;
3288 if (pHeader
->CacheUsage
.QuadPart
+ pHeader
->ExemptUsage
.QuadPart
>
3289 pHeader
->CacheLimit
.QuadPart
)
3290 handle_full_cache();
3294 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3295 heap_free(lpszUrlNameA
);
3296 heap_free(lpszFileExtensionA
);
3298 if (error
== ERROR_SUCCESS
)
3302 SetLastError(error
);
3307 /***********************************************************************
3308 * CommitUrlCacheEntryA (WININET.@)
3311 BOOL WINAPI
CommitUrlCacheEntryA(
3312 IN LPCSTR lpszUrlName
,
3313 IN LPCSTR lpszLocalFileName
,
3314 IN FILETIME ExpireTime
,
3315 IN FILETIME LastModifiedTime
,
3316 IN DWORD CacheEntryType
,
3317 IN LPBYTE lpHeaderInfo
,
3318 IN DWORD dwHeaderSize
,
3319 IN LPCSTR lpszFileExtension
,
3320 IN LPCSTR lpszOriginalUrl
3323 WCHAR
*url_name
= NULL
;
3324 WCHAR
*local_file_name
= NULL
;
3325 WCHAR
*original_url
= NULL
;
3326 WCHAR
*file_extension
= NULL
;
3327 BOOL bSuccess
= FALSE
;
3329 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
3330 debugstr_a(lpszUrlName
),
3331 debugstr_a(lpszLocalFileName
),
3335 debugstr_a(lpszFileExtension
),
3336 debugstr_a(lpszOriginalUrl
));
3338 url_name
= heap_strdupAtoW(lpszUrlName
);
3342 if (lpszLocalFileName
)
3344 local_file_name
= heap_strdupAtoW(lpszLocalFileName
);
3345 if (!local_file_name
)
3348 if (lpszFileExtension
)
3350 file_extension
= heap_strdupAtoW(lpszFileExtension
);
3351 if (!file_extension
)
3354 if (lpszOriginalUrl
)
3356 original_url
= heap_strdupAtoW(lpszOriginalUrl
);
3361 bSuccess
= CommitUrlCacheEntryInternal(url_name
, local_file_name
, ExpireTime
, LastModifiedTime
,
3362 CacheEntryType
, lpHeaderInfo
, dwHeaderSize
,
3363 file_extension
, original_url
);
3366 heap_free(original_url
);
3367 heap_free(file_extension
);
3368 heap_free(local_file_name
);
3369 heap_free(url_name
);
3373 /***********************************************************************
3374 * CommitUrlCacheEntryW (WININET.@)
3377 BOOL WINAPI
CommitUrlCacheEntryW(
3378 IN LPCWSTR lpszUrlName
,
3379 IN LPCWSTR lpszLocalFileName
,
3380 IN FILETIME ExpireTime
,
3381 IN FILETIME LastModifiedTime
,
3382 IN DWORD CacheEntryType
,
3383 IN LPWSTR lpHeaderInfo
,
3384 IN DWORD dwHeaderSize
,
3385 IN LPCWSTR lpszFileExtension
,
3386 IN LPCWSTR lpszOriginalUrl
3390 BOOL bSuccess
= FALSE
;
3392 CHAR
*header_info
= NULL
;
3394 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
3395 debugstr_w(lpszUrlName
),
3396 debugstr_w(lpszLocalFileName
),
3400 debugstr_w(lpszFileExtension
),
3401 debugstr_w(lpszOriginalUrl
));
3403 if (!lpHeaderInfo
|| (header_info
= heap_strdupWtoA(lpHeaderInfo
)))
3405 if (CommitUrlCacheEntryInternal(lpszUrlName
, lpszLocalFileName
, ExpireTime
, LastModifiedTime
,
3406 CacheEntryType
, (LPBYTE
)header_info
, len
, lpszFileExtension
, lpszOriginalUrl
))
3412 dwError
= GetLastError();
3416 heap_free(header_info
);
3418 SetLastError(dwError
);
3424 /***********************************************************************
3425 * ReadUrlCacheEntryStream (WININET.@)
3428 BOOL WINAPI
ReadUrlCacheEntryStream(
3429 IN HANDLE hUrlCacheStream
,
3430 IN DWORD dwLocation
,
3431 IN OUT LPVOID lpBuffer
,
3432 IN OUT LPDWORD lpdwLen
,
3436 /* Get handle to file from 'stream' */
3437 STREAM_HANDLE
* pStream
= (STREAM_HANDLE
*)hUrlCacheStream
;
3439 if (dwReserved
!= 0)
3441 ERR("dwReserved != 0\n");
3442 SetLastError(ERROR_INVALID_PARAMETER
);
3446 if (IsBadReadPtr(pStream
, sizeof(*pStream
)) || IsBadStringPtrA(pStream
->lpszUrl
, INTERNET_MAX_URL_LENGTH
))
3448 SetLastError(ERROR_INVALID_HANDLE
);
3452 if (SetFilePointer(pStream
->hFile
, dwLocation
, NULL
, FILE_CURRENT
) == INVALID_SET_FILE_POINTER
)
3454 return ReadFile(pStream
->hFile
, lpBuffer
, *lpdwLen
, lpdwLen
, NULL
);
3457 /***********************************************************************
3458 * RetrieveUrlCacheEntryStreamA (WININET.@)
3461 HANDLE WINAPI
RetrieveUrlCacheEntryStreamA(
3462 IN LPCSTR lpszUrlName
,
3463 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
3464 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
3465 IN BOOL fRandomRead
,
3469 /* NOTE: this is not the same as the way that the native
3470 * version allocates 'stream' handles. I did it this way
3471 * as it is much easier and no applications should depend
3472 * on this behaviour. (Native version appears to allocate
3473 * indices into a table)
3475 STREAM_HANDLE
* pStream
;
3478 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
,
3479 lpdwCacheEntryInfoBufferSize
, fRandomRead
, dwReserved
);
3481 if (!RetrieveUrlCacheEntryFileA(lpszUrlName
,
3483 lpdwCacheEntryInfoBufferSize
,
3489 hFile
= CreateFileA(lpCacheEntryInfo
->lpszLocalFileName
,
3494 fRandomRead
? FILE_FLAG_RANDOM_ACCESS
: 0,
3496 if (hFile
== INVALID_HANDLE_VALUE
)
3499 /* allocate handle storage space */
3500 pStream
= heap_alloc(sizeof(STREAM_HANDLE
) + strlen(lpszUrlName
) * sizeof(CHAR
));
3504 SetLastError(ERROR_OUTOFMEMORY
);
3508 pStream
->hFile
= hFile
;
3509 strcpy(pStream
->lpszUrl
, lpszUrlName
);
3513 /***********************************************************************
3514 * RetrieveUrlCacheEntryStreamW (WININET.@)
3517 HANDLE WINAPI
RetrieveUrlCacheEntryStreamW(
3518 IN LPCWSTR lpszUrlName
,
3519 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
3520 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
3521 IN BOOL fRandomRead
,
3527 /* NOTE: this is not the same as the way that the native
3528 * version allocates 'stream' handles. I did it this way
3529 * as it is much easier and no applications should depend
3530 * on this behaviour. (Native version appears to allocate
3531 * indices into a table)
3533 STREAM_HANDLE
* pStream
;
3536 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName
), lpCacheEntryInfo
,
3537 lpdwCacheEntryInfoBufferSize
, fRandomRead
, dwReserved
);
3539 if (!RetrieveUrlCacheEntryFileW(lpszUrlName
,
3541 lpdwCacheEntryInfoBufferSize
,
3547 hFile
= CreateFileW(lpCacheEntryInfo
->lpszLocalFileName
,
3552 fRandomRead
? FILE_FLAG_RANDOM_ACCESS
: 0,
3554 if (hFile
== INVALID_HANDLE_VALUE
)
3557 /* allocate handle storage space */
3558 size
= sizeof(STREAM_HANDLE
);
3559 url_len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, NULL
, 0, NULL
, NULL
);
3561 pStream
= heap_alloc(size
);
3565 SetLastError(ERROR_OUTOFMEMORY
);
3569 pStream
->hFile
= hFile
;
3570 WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, pStream
->lpszUrl
, url_len
, NULL
, NULL
);
3574 /***********************************************************************
3575 * UnlockUrlCacheEntryStream (WININET.@)
3578 BOOL WINAPI
UnlockUrlCacheEntryStream(
3579 IN HANDLE hUrlCacheStream
,
3583 STREAM_HANDLE
* pStream
= (STREAM_HANDLE
*)hUrlCacheStream
;
3585 if (dwReserved
!= 0)
3587 ERR("dwReserved != 0\n");
3588 SetLastError(ERROR_INVALID_PARAMETER
);
3592 if (IsBadReadPtr(pStream
, sizeof(*pStream
)) || IsBadStringPtrA(pStream
->lpszUrl
, INTERNET_MAX_URL_LENGTH
))
3594 SetLastError(ERROR_INVALID_HANDLE
);
3598 if (!UnlockUrlCacheEntryFileA(pStream
->lpszUrl
, 0))
3601 CloseHandle(pStream
->hFile
);
3607 /***********************************************************************
3608 * DeleteUrlCacheEntryA (WININET.@)
3611 BOOL WINAPI
DeleteUrlCacheEntryA(LPCSTR lpszUrlName
)
3613 URLCACHECONTAINER
* pContainer
;
3614 LPURLCACHE_HEADER pHeader
;
3615 struct _HASH_ENTRY
* pHashEntry
;
3619 TRACE("(%s)\n", debugstr_a(lpszUrlName
));
3621 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
3622 if (error
!= ERROR_SUCCESS
)
3624 SetLastError(error
);
3628 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
3629 if (error
!= ERROR_SUCCESS
)
3631 SetLastError(error
);
3635 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3638 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
3640 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3641 TRACE("entry %s not found!\n", lpszUrlName
);
3642 SetLastError(ERROR_FILE_NOT_FOUND
);
3646 ret
= DeleteUrlCacheEntryInternal(pContainer
, pHeader
, pHashEntry
);
3648 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3653 /***********************************************************************
3654 * DeleteUrlCacheEntryW (WININET.@)
3657 BOOL WINAPI
DeleteUrlCacheEntryW(LPCWSTR lpszUrlName
)
3659 URLCACHECONTAINER
* pContainer
;
3660 LPURLCACHE_HEADER pHeader
;
3661 struct _HASH_ENTRY
* pHashEntry
;
3666 TRACE("(%s)\n", debugstr_w(lpszUrlName
));
3668 urlA
= heap_strdupWtoA(lpszUrlName
);
3671 SetLastError(ERROR_OUTOFMEMORY
);
3675 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
3676 if (error
!= ERROR_SUCCESS
)
3679 SetLastError(error
);
3683 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
3684 if (error
!= ERROR_SUCCESS
)
3687 SetLastError(error
);
3691 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3697 if (!URLCache_FindHash(pHeader
, urlA
, &pHashEntry
))
3699 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3700 TRACE("entry %s not found!\n", debugstr_a(urlA
));
3702 SetLastError(ERROR_FILE_NOT_FOUND
);
3706 ret
= DeleteUrlCacheEntryInternal(pContainer
, pHeader
, pHashEntry
);
3708 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3713 BOOL WINAPI
DeleteUrlCacheContainerA(DWORD d1
, DWORD d2
)
3715 FIXME("(0x%08x, 0x%08x) stub\n", d1
, d2
);
3719 BOOL WINAPI
DeleteUrlCacheContainerW(DWORD d1
, DWORD d2
)
3721 FIXME("(0x%08x, 0x%08x) stub\n", d1
, d2
);
3725 /***********************************************************************
3726 * CreateCacheContainerA (WININET.@)
3728 BOOL WINAPI
CreateUrlCacheContainerA(DWORD d1
, DWORD d2
, DWORD d3
, DWORD d4
,
3729 DWORD d5
, DWORD d6
, DWORD d7
, DWORD d8
)
3731 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3732 d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
);
3736 /***********************************************************************
3737 * CreateCacheContainerW (WININET.@)
3739 BOOL WINAPI
CreateUrlCacheContainerW(DWORD d1
, DWORD d2
, DWORD d3
, DWORD d4
,
3740 DWORD d5
, DWORD d6
, DWORD d7
, DWORD d8
)
3742 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3743 d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
);
3747 /***********************************************************************
3748 * FindFirstUrlCacheContainerA (WININET.@)
3750 HANDLE WINAPI
FindFirstUrlCacheContainerA( LPVOID p1
, LPVOID p2
, LPVOID p3
, DWORD d1
)
3752 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1
, p2
, p3
, d1
);
3756 /***********************************************************************
3757 * FindFirstUrlCacheContainerW (WININET.@)
3759 HANDLE WINAPI
FindFirstUrlCacheContainerW( LPVOID p1
, LPVOID p2
, LPVOID p3
, DWORD d1
)
3761 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1
, p2
, p3
, d1
);
3765 /***********************************************************************
3766 * FindNextUrlCacheContainerA (WININET.@)
3768 BOOL WINAPI
FindNextUrlCacheContainerA( HANDLE handle
, LPVOID p1
, LPVOID p2
)
3770 FIXME("(%p, %p, %p) stub\n", handle
, p1
, p2
);
3774 /***********************************************************************
3775 * FindNextUrlCacheContainerW (WININET.@)
3777 BOOL WINAPI
FindNextUrlCacheContainerW( HANDLE handle
, LPVOID p1
, LPVOID p2
)
3779 FIXME("(%p, %p, %p) stub\n", handle
, p1
, p2
);
3783 HANDLE WINAPI
FindFirstUrlCacheEntryExA(
3784 LPCSTR lpszUrlSearchPattern
,
3788 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
,
3789 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3791 LPDWORD pcbReserved2
,
3795 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern
),
3796 dwFlags
, dwFilter
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, lpFirstCacheEntryInfo
,
3797 lpdwFirstCacheEntryInfoBufferSize
, lpReserved
, pcbReserved2
,lpReserved3
);
3798 SetLastError(ERROR_FILE_NOT_FOUND
);
3802 HANDLE WINAPI
FindFirstUrlCacheEntryExW(
3803 LPCWSTR lpszUrlSearchPattern
,
3807 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
,
3808 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3810 LPDWORD pcbReserved2
,
3814 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern
),
3815 dwFlags
, dwFilter
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, lpFirstCacheEntryInfo
,
3816 lpdwFirstCacheEntryInfoBufferSize
, lpReserved
, pcbReserved2
,lpReserved3
);
3817 SetLastError(ERROR_FILE_NOT_FOUND
);
3821 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3823 typedef struct URLCacheFindEntryHandle
3826 LPWSTR lpszUrlSearchPattern
;
3827 DWORD dwContainerIndex
;
3828 DWORD dwHashTableIndex
;
3829 DWORD dwHashEntryIndex
;
3830 } URLCacheFindEntryHandle
;
3832 /***********************************************************************
3833 * FindFirstUrlCacheEntryA (WININET.@)
3836 INTERNETAPI HANDLE WINAPI
FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern
,
3837 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
, LPDWORD lpdwFirstCacheEntryInfoBufferSize
)
3839 URLCacheFindEntryHandle
*pEntryHandle
;
3841 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern
), lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
);
3843 pEntryHandle
= heap_alloc(sizeof(*pEntryHandle
));
3847 pEntryHandle
->dwMagic
= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
;
3848 if (lpszUrlSearchPattern
)
3850 pEntryHandle
->lpszUrlSearchPattern
= heap_strdupAtoW(lpszUrlSearchPattern
);
3851 if (!pEntryHandle
->lpszUrlSearchPattern
)
3853 heap_free(pEntryHandle
);
3858 pEntryHandle
->lpszUrlSearchPattern
= NULL
;
3859 pEntryHandle
->dwContainerIndex
= 0;
3860 pEntryHandle
->dwHashTableIndex
= 0;
3861 pEntryHandle
->dwHashEntryIndex
= 0;
3863 if (!FindNextUrlCacheEntryA(pEntryHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
))
3865 heap_free(pEntryHandle
);
3868 return pEntryHandle
;
3871 /***********************************************************************
3872 * FindFirstUrlCacheEntryW (WININET.@)
3875 INTERNETAPI HANDLE WINAPI
FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern
,
3876 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
, LPDWORD lpdwFirstCacheEntryInfoBufferSize
)
3878 URLCacheFindEntryHandle
*pEntryHandle
;
3880 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern
), lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
);
3882 pEntryHandle
= heap_alloc(sizeof(*pEntryHandle
));
3886 pEntryHandle
->dwMagic
= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
;
3887 if (lpszUrlSearchPattern
)
3889 pEntryHandle
->lpszUrlSearchPattern
= heap_strdupW(lpszUrlSearchPattern
);
3890 if (!pEntryHandle
->lpszUrlSearchPattern
)
3892 heap_free(pEntryHandle
);
3897 pEntryHandle
->lpszUrlSearchPattern
= NULL
;
3898 pEntryHandle
->dwContainerIndex
= 0;
3899 pEntryHandle
->dwHashTableIndex
= 0;
3900 pEntryHandle
->dwHashEntryIndex
= 0;
3902 if (!FindNextUrlCacheEntryW(pEntryHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
))
3904 heap_free(pEntryHandle
);
3907 return pEntryHandle
;
3910 static BOOL
FindNextUrlCacheEntryInternal(
3912 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo
,
3913 LPDWORD lpdwNextCacheEntryInfoBufferSize
,
3916 URLCacheFindEntryHandle
*pEntryHandle
= (URLCacheFindEntryHandle
*)hEnumHandle
;
3917 URLCACHECONTAINER
* pContainer
;
3919 if (pEntryHandle
->dwMagic
!= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
)
3921 SetLastError(ERROR_INVALID_HANDLE
);
3925 for (; URLCacheContainers_Enum(pEntryHandle
->lpszUrlSearchPattern
, pEntryHandle
->dwContainerIndex
, &pContainer
);
3926 pEntryHandle
->dwContainerIndex
++, pEntryHandle
->dwHashTableIndex
= 0)
3928 LPURLCACHE_HEADER pHeader
;
3929 HASH_CACHEFILE_ENTRY
*pHashTableEntry
;
3932 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
3933 if (error
!= ERROR_SUCCESS
)
3935 SetLastError(error
);
3939 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3942 for (; URLCache_EnumHashTables(pHeader
, &pEntryHandle
->dwHashTableIndex
, &pHashTableEntry
);
3943 pEntryHandle
->dwHashTableIndex
++, pEntryHandle
->dwHashEntryIndex
= 0)
3945 const struct _HASH_ENTRY
*pHashEntry
= NULL
;
3946 for (; URLCache_EnumHashTableEntries(pHeader
, pHashTableEntry
, &pEntryHandle
->dwHashEntryIndex
, &pHashEntry
);
3947 pEntryHandle
->dwHashEntryIndex
++)
3949 const URL_CACHEFILE_ENTRY
*pUrlEntry
;
3950 const CACHEFILE_ENTRY
*pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3952 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
3955 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
3956 TRACE("Found URL: %s\n",
3957 debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
));
3958 TRACE("Header info: %s\n",
3959 debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
3961 error
= URLCache_CopyEntry(
3964 lpNextCacheEntryInfo
,
3965 lpdwNextCacheEntryInfoBufferSize
,
3968 if (error
!= ERROR_SUCCESS
)
3970 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3971 SetLastError(error
);
3974 TRACE("Local File Name: %s\n",
3975 debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
3977 /* increment the current index so that next time the function
3978 * is called the next entry is returned */
3979 pEntryHandle
->dwHashEntryIndex
++;
3980 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3985 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3988 SetLastError(ERROR_NO_MORE_ITEMS
);
3992 /***********************************************************************
3993 * FindNextUrlCacheEntryA (WININET.@)
3995 BOOL WINAPI
FindNextUrlCacheEntryA(
3997 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo
,
3998 LPDWORD lpdwNextCacheEntryInfoBufferSize
)
4000 TRACE("(%p, %p, %p)\n", hEnumHandle
, lpNextCacheEntryInfo
, lpdwNextCacheEntryInfoBufferSize
);
4002 return FindNextUrlCacheEntryInternal(hEnumHandle
, lpNextCacheEntryInfo
,
4003 lpdwNextCacheEntryInfoBufferSize
, FALSE
/* not UNICODE */);
4006 /***********************************************************************
4007 * FindNextUrlCacheEntryW (WININET.@)
4009 BOOL WINAPI
FindNextUrlCacheEntryW(
4011 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo
,
4012 LPDWORD lpdwNextCacheEntryInfoBufferSize
4015 TRACE("(%p, %p, %p)\n", hEnumHandle
, lpNextCacheEntryInfo
, lpdwNextCacheEntryInfoBufferSize
);
4017 return FindNextUrlCacheEntryInternal(hEnumHandle
,
4018 (LPINTERNET_CACHE_ENTRY_INFOA
)lpNextCacheEntryInfo
,
4019 lpdwNextCacheEntryInfoBufferSize
, TRUE
/* UNICODE */);
4022 /***********************************************************************
4023 * FindCloseUrlCache (WININET.@)
4025 BOOL WINAPI
FindCloseUrlCache(HANDLE hEnumHandle
)
4027 URLCacheFindEntryHandle
*pEntryHandle
= (URLCacheFindEntryHandle
*)hEnumHandle
;
4029 TRACE("(%p)\n", hEnumHandle
);
4031 if (!pEntryHandle
|| pEntryHandle
->dwMagic
!= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
)
4033 SetLastError(ERROR_INVALID_HANDLE
);
4037 pEntryHandle
->dwMagic
= 0;
4038 heap_free(pEntryHandle
->lpszUrlSearchPattern
);
4039 heap_free(pEntryHandle
);
4043 HANDLE WINAPI
FindFirstUrlCacheGroup( DWORD dwFlags
, DWORD dwFilter
, LPVOID lpSearchCondition
,
4044 DWORD dwSearchCondition
, GROUPID
* lpGroupId
, LPVOID lpReserved
)
4046 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags
, dwFilter
, lpSearchCondition
,
4047 dwSearchCondition
, lpGroupId
, lpReserved
);
4051 BOOL WINAPI
FindNextUrlCacheEntryExA(
4053 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
,
4054 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
4056 LPDWORD pcbReserved2
,
4060 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
,
4061 lpReserved
, pcbReserved2
, lpReserved3
);
4065 BOOL WINAPI
FindNextUrlCacheEntryExW(
4067 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
,
4068 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
4070 LPDWORD pcbReserved2
,
4074 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
,
4075 lpReserved
, pcbReserved2
, lpReserved3
);
4079 BOOL WINAPI
FindNextUrlCacheGroup( HANDLE hFind
, GROUPID
* lpGroupId
, LPVOID lpReserved
)
4081 FIXME("(%p, %p, %p) stub\n", hFind
, lpGroupId
, lpReserved
);
4085 /***********************************************************************
4086 * CreateUrlCacheGroup (WININET.@)
4089 INTERNETAPI GROUPID WINAPI
CreateUrlCacheGroup(DWORD dwFlags
, LPVOID lpReserved
)
4091 FIXME("(0x%08x, %p): stub\n", dwFlags
, lpReserved
);
4095 /***********************************************************************
4096 * DeleteUrlCacheGroup (WININET.@)
4099 BOOL WINAPI
DeleteUrlCacheGroup(GROUPID GroupId
, DWORD dwFlags
, LPVOID lpReserved
)
4101 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
4102 (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, dwFlags
, lpReserved
);
4106 /***********************************************************************
4107 * SetUrlCacheEntryGroupA (WININET.@)
4110 BOOL WINAPI
SetUrlCacheEntryGroupA(LPCSTR lpszUrlName
, DWORD dwFlags
,
4111 GROUPID GroupId
, LPBYTE pbGroupAttributes
, DWORD cbGroupAttributes
,
4114 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
4115 debugstr_a(lpszUrlName
), dwFlags
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
,
4116 pbGroupAttributes
, cbGroupAttributes
, lpReserved
);
4117 SetLastError(ERROR_FILE_NOT_FOUND
);
4121 /***********************************************************************
4122 * SetUrlCacheEntryGroupW (WININET.@)
4125 BOOL WINAPI
SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName
, DWORD dwFlags
,
4126 GROUPID GroupId
, LPBYTE pbGroupAttributes
, DWORD cbGroupAttributes
,
4129 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
4130 debugstr_w(lpszUrlName
), dwFlags
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
,
4131 pbGroupAttributes
, cbGroupAttributes
, lpReserved
);
4132 SetLastError(ERROR_FILE_NOT_FOUND
);
4136 /***********************************************************************
4137 * GetUrlCacheConfigInfoW (WININET.@)
4139 BOOL WINAPI
GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo
, LPDWORD size
, DWORD bitmask
)
4141 FIXME("(%p, %p, %x)\n", CacheInfo
, size
, bitmask
);
4142 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
4146 /***********************************************************************
4147 * GetUrlCacheConfigInfoA (WININET.@)
4149 BOOL WINAPI
GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo
, LPDWORD size
, DWORD bitmask
)
4151 FIXME("(%p, %p, %x)\n", CacheInfo
, size
, bitmask
);
4152 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
4156 BOOL WINAPI
GetUrlCacheGroupAttributeA( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
4157 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo
,
4158 LPDWORD lpdwGroupInfo
, LPVOID lpReserved
)
4160 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
4161 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
,
4162 lpdwGroupInfo
, lpReserved
);
4166 BOOL WINAPI
GetUrlCacheGroupAttributeW( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
4167 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo
,
4168 LPDWORD lpdwGroupInfo
, LPVOID lpReserved
)
4170 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
4171 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
,
4172 lpdwGroupInfo
, lpReserved
);
4176 BOOL WINAPI
SetUrlCacheGroupAttributeA( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
4177 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo
, LPVOID lpReserved
)
4179 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
4180 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
, lpReserved
);
4184 BOOL WINAPI
SetUrlCacheGroupAttributeW( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
4185 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo
, LPVOID lpReserved
)
4187 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
4188 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
, lpReserved
);
4192 BOOL WINAPI
SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo
, DWORD dwFieldControl
)
4194 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo
, dwFieldControl
);
4198 BOOL WINAPI
SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo
, DWORD dwFieldControl
)
4200 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo
, dwFieldControl
);
4204 /***********************************************************************
4205 * DeleteIE3Cache (WININET.@)
4207 * Deletes the files used by the IE3 URL caching system.
4210 * hWnd [I] A dummy window.
4211 * hInst [I] Instance of process calling the function.
4212 * lpszCmdLine [I] Options used by function.
4213 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
4215 DWORD WINAPI
DeleteIE3Cache(HWND hWnd
, HINSTANCE hInst
, LPSTR lpszCmdLine
, int nCmdShow
)
4217 FIXME("(%p, %p, %s, %d)\n", hWnd
, hInst
, debugstr_a(lpszCmdLine
), nCmdShow
);
4221 static BOOL
IsUrlCacheEntryExpiredInternal(const URL_CACHEFILE_ENTRY
*pUrlEntry
,
4222 FILETIME
*pftLastModified
)
4225 FILETIME now
, expired
;
4227 *pftLastModified
= pUrlEntry
->LastModifiedTime
;
4228 GetSystemTimeAsFileTime(&now
);
4229 URLCache_DosDateTimeToFileTime(pUrlEntry
->wExpiredDate
,
4230 pUrlEntry
->wExpiredTime
, &expired
);
4231 /* If the expired time is 0, it's interpreted as not expired */
4232 if (!expired
.dwLowDateTime
&& !expired
.dwHighDateTime
)
4235 ret
= CompareFileTime(&expired
, &now
) < 0;
4239 /***********************************************************************
4240 * IsUrlCacheEntryExpiredA (WININET.@)
4244 * dwFlags [I] Unknown
4245 * pftLastModified [O] Last modified time
4247 BOOL WINAPI
IsUrlCacheEntryExpiredA( LPCSTR url
, DWORD dwFlags
, FILETIME
* pftLastModified
)
4249 LPURLCACHE_HEADER pHeader
;
4250 struct _HASH_ENTRY
* pHashEntry
;
4251 const CACHEFILE_ENTRY
* pEntry
;
4252 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
4253 URLCACHECONTAINER
* pContainer
;
4256 TRACE("(%s, %08x, %p)\n", debugstr_a(url
), dwFlags
, pftLastModified
);
4258 if (!url
|| !pftLastModified
)
4261 FIXME("unknown flags 0x%08x\n", dwFlags
);
4263 /* Any error implies that the URL is expired, i.e. not in the cache */
4264 if (URLCacheContainers_FindContainerA(url
, &pContainer
))
4266 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
4270 if (URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
))
4272 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
4276 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
4278 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
4282 if (!URLCache_FindHash(pHeader
, url
, &pHashEntry
))
4284 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
4285 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
4286 TRACE("entry %s not found!\n", url
);
4290 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
4291 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
4293 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
4294 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
4295 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
4299 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
4300 expired
= IsUrlCacheEntryExpiredInternal(pUrlEntry
, pftLastModified
);
4302 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
4307 /***********************************************************************
4308 * IsUrlCacheEntryExpiredW (WININET.@)
4312 * dwFlags [I] Unknown
4313 * pftLastModified [O] Last modified time
4315 BOOL WINAPI
IsUrlCacheEntryExpiredW( LPCWSTR url
, DWORD dwFlags
, FILETIME
* pftLastModified
)
4317 LPURLCACHE_HEADER pHeader
;
4318 struct _HASH_ENTRY
* pHashEntry
;
4319 const CACHEFILE_ENTRY
* pEntry
;
4320 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
4321 URLCACHECONTAINER
* pContainer
;
4324 TRACE("(%s, %08x, %p)\n", debugstr_w(url
), dwFlags
, pftLastModified
);
4326 if (!url
|| !pftLastModified
)
4329 FIXME("unknown flags 0x%08x\n", dwFlags
);
4331 /* Any error implies that the URL is expired, i.e. not in the cache */
4332 if (URLCacheContainers_FindContainerW(url
, &pContainer
))
4334 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
4338 if (URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
))
4340 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
4344 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
4346 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
4350 if (!URLCache_FindHashW(pHeader
, url
, &pHashEntry
))
4352 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
4353 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
4354 TRACE("entry %s not found!\n", debugstr_w(url
));
4358 if (!URLCache_FindHashW(pHeader
, url
, &pHashEntry
))
4360 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
4361 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
4362 TRACE("entry %s not found!\n", debugstr_w(url
));
4366 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
4367 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
4369 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
4370 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
4371 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
4375 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
4376 expired
= IsUrlCacheEntryExpiredInternal(pUrlEntry
, pftLastModified
);
4378 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
4383 /***********************************************************************
4384 * GetDiskInfoA (WININET.@)
4386 BOOL WINAPI
GetDiskInfoA(PCSTR path
, PDWORD cluster_size
, PDWORDLONG free
, PDWORDLONG total
)
4389 ULARGE_INTEGER bytes_free
, bytes_total
;
4391 TRACE("(%s, %p, %p, %p)\n", debugstr_a(path
), cluster_size
, free
, total
);
4395 SetLastError(ERROR_INVALID_PARAMETER
);
4399 if ((ret
= GetDiskFreeSpaceExA(path
, NULL
, &bytes_total
, &bytes_free
)))
4401 if (cluster_size
) *cluster_size
= 1;
4402 if (free
) *free
= bytes_free
.QuadPart
;
4403 if (total
) *total
= bytes_total
.QuadPart
;
4408 /***********************************************************************
4409 * RegisterUrlCacheNotification (WININET.@)
4411 DWORD WINAPI
RegisterUrlCacheNotification(LPVOID a
, DWORD b
, DWORD c
, DWORD d
, DWORD e
, DWORD f
)
4413 FIXME("(%p %x %x %x %x %x)\n", a
, b
, c
, d
, e
, f
);
4417 /***********************************************************************
4418 * IncrementUrlCacheHeaderData (WININET.@)
4420 BOOL WINAPI
IncrementUrlCacheHeaderData(DWORD index
, LPDWORD data
)
4422 FIXME("(%u, %p)\n", index
, data
);
4426 /***********************************************************************
4427 * RunOnceUrlCache (WININET.@)
4430 DWORD WINAPI
RunOnceUrlCache(HWND hwnd
, HINSTANCE hinst
, LPSTR cmd
, int cmdshow
)
4432 FIXME("(%p, %p, %s, %d): stub\n", hwnd
, hinst
, debugstr_a(cmd
), cmdshow
);
4436 BOOL
init_urlcache(void)
4438 dll_unload_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
4439 if(!dll_unload_event
)
4442 free_cache_running
= CreateSemaphoreW(NULL
, 1, 1, NULL
);
4443 if(!free_cache_running
) {
4444 CloseHandle(dll_unload_event
);
4448 URLCacheContainers_CreateDefaults();
4452 void free_urlcache(void)
4454 SetEvent(dll_unload_event
);
4455 WaitForSingleObject(free_cache_running
, INFINITE
);
4456 ReleaseSemaphore(free_cache_running
, 1, NULL
);
4457 CloseHandle(free_cache_running
);
4458 CloseHandle(dll_unload_event
);
4460 URLCacheContainers_DeleteAll();