xref: /reactos/dll/win32/wininet/urlcache.c (revision e152f78a)
15f12c8d7Swinesync #ifdef __REACTOS__
25f12c8d7Swinesync #define NONAMELESSUNION
35f12c8d7Swinesync #define NONAMELESSSTRUCT
45f12c8d7Swinesync #include "precomp.h"
55f12c8d7Swinesync #else
6c2c66affSColin Finck /*
7c2c66affSColin Finck  * Wininet - Url Cache functions
8c2c66affSColin Finck  *
9c2c66affSColin Finck  * Copyright 2001,2002 CodeWeavers
10c2c66affSColin Finck  * Copyright 2003-2008 Robert Shearman
11c2c66affSColin Finck  *
12c2c66affSColin Finck  * Eric Kohl
13c2c66affSColin Finck  * Aric Stewart
14c2c66affSColin Finck  *
15c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
16c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
17c2c66affSColin Finck  * License as published by the Free Software Foundation; either
18c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
19c2c66affSColin Finck  *
20c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
21c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23c2c66affSColin Finck  * Lesser General Public License for more details.
24c2c66affSColin Finck  *
25c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
26c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
27c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28c2c66affSColin Finck  */
29c2c66affSColin Finck 
30bc01cef0SAmine Khaldi #define NONAMELESSUNION
31c239cdd4SAmine Khaldi #define NONAMELESSSTRUCT
32bc01cef0SAmine Khaldi 
33bc01cef0SAmine Khaldi #include "ws2tcpip.h"
34bc01cef0SAmine Khaldi 
35bc01cef0SAmine Khaldi #include <stdarg.h>
36bc01cef0SAmine Khaldi #include <stdio.h>
37bc01cef0SAmine Khaldi #include <stdlib.h>
38bc01cef0SAmine Khaldi #include <string.h>
39bc01cef0SAmine Khaldi #include <time.h>
40bc01cef0SAmine Khaldi 
41bc01cef0SAmine Khaldi #include "windef.h"
42bc01cef0SAmine Khaldi #include "winbase.h"
43bc01cef0SAmine Khaldi #include "winuser.h"
44bc01cef0SAmine Khaldi #include "wininet.h"
45bc01cef0SAmine Khaldi #include "winineti.h"
46bc01cef0SAmine Khaldi #include "winerror.h"
47bc01cef0SAmine Khaldi #include "winreg.h"
48bc01cef0SAmine Khaldi #include "shlwapi.h"
49bc01cef0SAmine Khaldi #include "shlobj.h"
50bc01cef0SAmine Khaldi #include "shellapi.h"
51bc01cef0SAmine Khaldi 
52c2c66affSColin Finck #include "internet.h"
53bc01cef0SAmine Khaldi #include "wine/debug.h"
545f12c8d7Swinesync #endif /* defined(__REACTOS__) */
55bc01cef0SAmine Khaldi 
56bc01cef0SAmine Khaldi WINE_DEFAULT_DEBUG_CHANNEL(wininet);
57c2c66affSColin Finck 
58c2c66affSColin Finck static const char urlcache_ver_prefix[] = "WINE URLCache Ver ";
59c2c66affSColin Finck static const char urlcache_ver[] = "0.2012001";
60c2c66affSColin Finck 
61c2c66affSColin Finck #ifndef CHAR_BIT
62c2c66affSColin Finck #define CHAR_BIT    (8 * sizeof(CHAR))
63c2c66affSColin Finck #endif
64c2c66affSColin Finck 
65c2c66affSColin Finck #define ENTRY_START_OFFSET      0x4000
66c2c66affSColin Finck #define DIR_LENGTH              8
67c2c66affSColin Finck #define MAX_DIR_NO              0x20
68c2c66affSColin Finck #define BLOCKSIZE               128
69c2c66affSColin Finck #define HASHTABLE_SIZE          448
70c2c66affSColin Finck #define HASHTABLE_NUM_ENTRIES   64 /* this needs to be power of 2, that divides HASHTABLE_SIZE */
71c2c66affSColin Finck #define HASHTABLE_BLOCKSIZE     (HASHTABLE_SIZE / HASHTABLE_NUM_ENTRIES)
72c2c66affSColin Finck #define ALLOCATION_TABLE_OFFSET 0x250
73c2c66affSColin Finck #define ALLOCATION_TABLE_SIZE   (ENTRY_START_OFFSET - ALLOCATION_TABLE_OFFSET)
74c2c66affSColin Finck #define MIN_BLOCK_NO            0x80
75c2c66affSColin Finck #define MAX_BLOCK_NO            (ALLOCATION_TABLE_SIZE * CHAR_BIT)
76c2c66affSColin Finck #define FILE_SIZE(blocks)       ((blocks) * BLOCKSIZE + ENTRY_START_OFFSET)
77c2c66affSColin Finck 
78c2c66affSColin Finck #define HASHTABLE_URL           0
79c2c66affSColin Finck #define HASHTABLE_DEL           1
80c2c66affSColin Finck #define HASHTABLE_LOCK          2
81c2c66affSColin Finck #define HASHTABLE_FREE          3
82c2c66affSColin Finck #define HASHTABLE_REDR          5
83c2c66affSColin Finck #define HASHTABLE_FLAG_BITS     6
84c2c66affSColin Finck 
85c2c66affSColin Finck #define PENDING_DELETE_CACHE_ENTRY  0x00400000
86c2c66affSColin Finck #define INSTALLED_CACHE_ENTRY       0x10000000
87c2c66affSColin Finck #define GET_INSTALLED_ENTRY         0x200
88c2c66affSColin Finck #define CACHE_CONTAINER_NO_SUBDIR   0xFE
89c2c66affSColin Finck 
90c2c66affSColin Finck #define CACHE_HEADER_DATA_ROOT_LEAK_OFFSET 0x16
91c2c66affSColin Finck 
92c2c66affSColin Finck #define FILETIME_SECOND 10000000
93c2c66affSColin Finck 
94c2c66affSColin Finck #define DWORD_SIG(a,b,c,d)  (a | (b << 8) | (c << 16) | (d << 24))
95c2c66affSColin Finck #define URL_SIGNATURE   DWORD_SIG('U','R','L',' ')
96c2c66affSColin Finck #define REDR_SIGNATURE  DWORD_SIG('R','E','D','R')
97c2c66affSColin Finck #define LEAK_SIGNATURE  DWORD_SIG('L','E','A','K')
98c2c66affSColin Finck #define HASH_SIGNATURE  DWORD_SIG('H','A','S','H')
99c2c66affSColin Finck 
100c2c66affSColin Finck #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
101c2c66affSColin Finck 
102c2c66affSColin Finck #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
103c2c66affSColin Finck 
104c2c66affSColin Finck typedef struct
105c2c66affSColin Finck {
106c2c66affSColin Finck     DWORD signature;
107c2c66affSColin Finck     DWORD blocks_used; /* number of 128byte blocks used by this entry */
108c2c66affSColin Finck } entry_header;
109c2c66affSColin Finck 
110c2c66affSColin Finck typedef struct
111c2c66affSColin Finck {
112c2c66affSColin Finck     entry_header header;
113c2c66affSColin Finck     FILETIME modification_time;
114c2c66affSColin Finck     FILETIME access_time;
115c2c66affSColin Finck     WORD expire_date; /* expire date in dos format */
116c2c66affSColin Finck     WORD expire_time; /* expire time in dos format */
117c2c66affSColin Finck     DWORD unk1; /* usually zero */
118c2c66affSColin Finck     ULARGE_INTEGER size; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow/High */
119c2c66affSColin Finck     DWORD unk2; /* usually zero */
120c2c66affSColin Finck     DWORD exempt_delta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
121c2c66affSColin Finck     DWORD unk3; /* usually 0x60 */
122c2c66affSColin Finck     DWORD url_off; /* offset of start of url from start of entry */
123c2c66affSColin Finck     BYTE cache_dir; /* index of cache directory this url is stored in */
124c2c66affSColin Finck     BYTE unk4; /* usually zero */
125c2c66affSColin Finck     WORD unk5; /* usually 0x1010 */
126c2c66affSColin Finck     DWORD local_name_off; /* offset of start of local filename from start of entry */
127c2c66affSColin Finck     DWORD cache_entry_type; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
128c2c66affSColin Finck     DWORD header_info_off; /* offset of start of header info from start of entry */
129c2c66affSColin Finck     DWORD header_info_size;
130c2c66affSColin Finck     DWORD file_extension_off; /* offset of start of file extension from start of entry */
131c2c66affSColin Finck     WORD sync_date; /* last sync date in dos format */
132c2c66affSColin Finck     WORD sync_time; /* last sync time in dos format */
133c2c66affSColin Finck     DWORD hit_rate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
134c2c66affSColin Finck     DWORD use_count; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
135c2c66affSColin Finck     WORD write_date;
136c2c66affSColin Finck     WORD write_time;
137c2c66affSColin Finck     DWORD unk7; /* usually zero */
138c2c66affSColin Finck     DWORD unk8; /* usually zero */
139c2c66affSColin Finck     /* packing to dword align start of next field */
140c2c66affSColin Finck     /* CHAR szSourceUrlName[]; (url) */
141c2c66affSColin Finck     /* packing to dword align start of next field */
142c2c66affSColin Finck     /* CHAR szLocalFileName[]; (local file name excluding path) */
143c2c66affSColin Finck     /* packing to dword align start of next field */
144c2c66affSColin Finck     /* CHAR szHeaderInfo[]; (header info) */
145c2c66affSColin Finck } entry_url;
146c2c66affSColin Finck 
147c2c66affSColin Finck struct hash_entry
148c2c66affSColin Finck {
149c2c66affSColin Finck     DWORD key;
150c2c66affSColin Finck     DWORD offset;
151c2c66affSColin Finck };
152c2c66affSColin Finck 
153c2c66affSColin Finck typedef struct
154c2c66affSColin Finck {
155c2c66affSColin Finck     entry_header header;
156c2c66affSColin Finck     DWORD next;
157c2c66affSColin Finck     DWORD id;
158c2c66affSColin Finck     struct hash_entry hash_table[HASHTABLE_SIZE];
159c2c66affSColin Finck } entry_hash_table;
160c2c66affSColin Finck 
161c2c66affSColin Finck typedef struct
162c2c66affSColin Finck {
163c2c66affSColin Finck     char signature[28];
164c2c66affSColin Finck     DWORD size;
165c2c66affSColin Finck     DWORD hash_table_off;
166c2c66affSColin Finck     DWORD capacity_in_blocks;
167c2c66affSColin Finck     DWORD blocks_in_use;
168c2c66affSColin Finck     DWORD unk1;
169c2c66affSColin Finck     ULARGE_INTEGER cache_limit;
170c2c66affSColin Finck     ULARGE_INTEGER cache_usage;
171c2c66affSColin Finck     ULARGE_INTEGER exempt_usage;
172c2c66affSColin Finck     DWORD dirs_no;
173c2c66affSColin Finck     struct _directory_data
174c2c66affSColin Finck     {
175c2c66affSColin Finck         DWORD files_no;
176c2c66affSColin Finck         char name[DIR_LENGTH];
177c2c66affSColin Finck     } directory_data[MAX_DIR_NO];
178c2c66affSColin Finck     DWORD options[0x21];
179c2c66affSColin Finck     BYTE allocation_table[ALLOCATION_TABLE_SIZE];
180c2c66affSColin Finck } urlcache_header;
181c2c66affSColin Finck 
182c2c66affSColin Finck typedef struct
183c2c66affSColin Finck {
184c2c66affSColin Finck     HANDLE file;
185c2c66affSColin Finck     CHAR url[1];
186c2c66affSColin Finck } stream_handle;
187c2c66affSColin Finck 
188c2c66affSColin Finck typedef struct
189c2c66affSColin Finck {
190c2c66affSColin Finck     struct list entry; /* part of a list */
191c2c66affSColin Finck     char *cache_prefix; /* string that has to be prefixed for this container to be used */
192c2c66affSColin Finck     LPWSTR path; /* path to url container directory */
193c2c66affSColin Finck     HANDLE mapping; /* handle of file mapping */
194c2c66affSColin Finck     DWORD file_size; /* size of file when mapping was opened */
195c2c66affSColin Finck     HANDLE mutex; /* handle of mutex */
196c2c66affSColin Finck     DWORD default_entry_type;
197c2c66affSColin Finck } cache_container;
198c2c66affSColin Finck 
199c2c66affSColin Finck typedef struct
200c2c66affSColin Finck {
201c2c66affSColin Finck     DWORD magic;
202c2c66affSColin Finck     char *url_search_pattern;
203c2c66affSColin Finck     DWORD container_idx;
204c2c66affSColin Finck     DWORD hash_table_idx;
205c2c66affSColin Finck     DWORD hash_entry_idx;
206c2c66affSColin Finck } find_handle;
207c2c66affSColin Finck 
208c2c66affSColin Finck /* List of all containers available */
209c2c66affSColin Finck static struct list UrlContainers = LIST_INIT(UrlContainers);
210c2c66affSColin Finck /* ReactOS r54992 */
211c2c66affSColin Finck BOOL bDefaultContainersAdded = FALSE;
212c2c66affSColin Finck 
heap_strdupWtoUTF8(LPCWSTR str)213c2c66affSColin Finck static inline char *heap_strdupWtoUTF8(LPCWSTR str)
214c2c66affSColin Finck {
215c2c66affSColin Finck     char *ret = NULL;
216c2c66affSColin Finck 
217c2c66affSColin Finck     if(str) {
218c2c66affSColin Finck         DWORD size = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
219c2c66affSColin Finck         ret = heap_alloc(size);
220c2c66affSColin Finck         if(ret)
221c2c66affSColin Finck             WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, size, NULL, NULL);
222c2c66affSColin Finck     }
223c2c66affSColin Finck 
224c2c66affSColin Finck     return ret;
225c2c66affSColin Finck }
226c2c66affSColin Finck 
227c2c66affSColin Finck /***********************************************************************
228c2c66affSColin Finck  *           urlcache_block_is_free (Internal)
229c2c66affSColin Finck  *
230c2c66affSColin Finck  *  Is the specified block number free?
231c2c66affSColin Finck  *
232c2c66affSColin Finck  * RETURNS
233c2c66affSColin Finck  *    zero if free
234c2c66affSColin Finck  *    non-zero otherwise
235c2c66affSColin Finck  *
236c2c66affSColin Finck  */
urlcache_block_is_free(BYTE * allocation_table,DWORD block_number)237c2c66affSColin Finck static inline BYTE urlcache_block_is_free(BYTE *allocation_table, DWORD block_number)
238c2c66affSColin Finck {
239c2c66affSColin Finck     BYTE mask = 1 << (block_number%CHAR_BIT);
240c2c66affSColin Finck     return (allocation_table[block_number/CHAR_BIT] & mask) == 0;
241c2c66affSColin Finck }
242c2c66affSColin Finck 
243c2c66affSColin Finck /***********************************************************************
244c2c66affSColin Finck  *           urlcache_block_free (Internal)
245c2c66affSColin Finck  *
246c2c66affSColin Finck  *  Marks the specified block as free
247c2c66affSColin Finck  *
248c2c66affSColin Finck  * CAUTION
249c2c66affSColin Finck  *    this function is not updating used blocks count
250c2c66affSColin Finck  *
251c2c66affSColin Finck  * RETURNS
252c2c66affSColin Finck  *    nothing
253c2c66affSColin Finck  *
254c2c66affSColin Finck  */
urlcache_block_free(BYTE * allocation_table,DWORD block_number)255c2c66affSColin Finck static inline void urlcache_block_free(BYTE *allocation_table, DWORD block_number)
256c2c66affSColin Finck {
257c2c66affSColin Finck     BYTE mask = ~(1 << (block_number%CHAR_BIT));
258c2c66affSColin Finck     allocation_table[block_number/CHAR_BIT] &= mask;
259c2c66affSColin Finck }
260c2c66affSColin Finck 
261c2c66affSColin Finck /***********************************************************************
262c2c66affSColin Finck  *           urlcache_block_alloc (Internal)
263c2c66affSColin Finck  *
264c2c66affSColin Finck  *  Marks the specified block as allocated
265c2c66affSColin Finck  *
266c2c66affSColin Finck  * CAUTION
267c2c66affSColin Finck  *     this function is not updating used blocks count
268c2c66affSColin Finck  *
269c2c66affSColin Finck  * RETURNS
270c2c66affSColin Finck  *    nothing
271c2c66affSColin Finck  *
272c2c66affSColin Finck  */
urlcache_block_alloc(BYTE * allocation_table,DWORD block_number)273c2c66affSColin Finck static inline void urlcache_block_alloc(BYTE *allocation_table, DWORD block_number)
274c2c66affSColin Finck {
275c2c66affSColin Finck     BYTE mask = 1 << (block_number%CHAR_BIT);
276c2c66affSColin Finck     allocation_table[block_number/CHAR_BIT] |= mask;
277c2c66affSColin Finck }
278c2c66affSColin Finck 
279c2c66affSColin Finck /***********************************************************************
280c2c66affSColin Finck  *           urlcache_entry_alloc (Internal)
281c2c66affSColin Finck  *
282c2c66affSColin Finck  *  Finds and allocates the first block of free space big enough and
283c2c66affSColin Finck  * sets entry to point to it.
284c2c66affSColin Finck  *
285c2c66affSColin Finck  * RETURNS
286c2c66affSColin Finck  *    ERROR_SUCCESS when free memory block was found
287c2c66affSColin Finck  *    Any other Win32 error code if the entry could not be added
288c2c66affSColin Finck  *
289c2c66affSColin Finck  */
urlcache_entry_alloc(urlcache_header * header,DWORD blocks_needed,entry_header ** entry)290c2c66affSColin Finck static DWORD urlcache_entry_alloc(urlcache_header *header, DWORD blocks_needed, entry_header **entry)
291c2c66affSColin Finck {
292c2c66affSColin Finck     DWORD block, block_size;
293c2c66affSColin Finck 
294c2c66affSColin Finck     for(block=0; block<header->capacity_in_blocks; block+=block_size+1)
295c2c66affSColin Finck     {
296c2c66affSColin Finck         block_size = 0;
297c2c66affSColin Finck         while(block_size<blocks_needed && block_size+block<header->capacity_in_blocks
298c2c66affSColin Finck                 && urlcache_block_is_free(header->allocation_table, block+block_size))
299c2c66affSColin Finck             block_size++;
300c2c66affSColin Finck 
301c2c66affSColin Finck         if(block_size == blocks_needed)
302c2c66affSColin Finck         {
303c2c66affSColin Finck             DWORD index;
304c2c66affSColin Finck 
305c2c66affSColin Finck             TRACE("Found free blocks starting at no. %d (0x%x)\n", block, ENTRY_START_OFFSET+block*BLOCKSIZE);
306c2c66affSColin Finck 
307c2c66affSColin Finck             for(index=0; index<blocks_needed; index++)
308c2c66affSColin Finck                 urlcache_block_alloc(header->allocation_table, block+index);
309c2c66affSColin Finck 
310c2c66affSColin Finck             *entry = (entry_header*)((BYTE*)header+ENTRY_START_OFFSET+block*BLOCKSIZE);
311c2c66affSColin Finck             for(index=0; index<blocks_needed*BLOCKSIZE/sizeof(DWORD); index++)
312c2c66affSColin Finck                 ((DWORD*)*entry)[index] = 0xdeadbeef;
313c2c66affSColin Finck             (*entry)->blocks_used = blocks_needed;
314c2c66affSColin Finck 
315c2c66affSColin Finck             header->blocks_in_use += blocks_needed;
316c2c66affSColin Finck             return ERROR_SUCCESS;
317c2c66affSColin Finck         }
318c2c66affSColin Finck     }
319c2c66affSColin Finck 
320c2c66affSColin Finck     return ERROR_HANDLE_DISK_FULL;
321c2c66affSColin Finck }
322c2c66affSColin Finck 
323c2c66affSColin Finck /***********************************************************************
324c2c66affSColin Finck  *           urlcache_entry_free (Internal)
325c2c66affSColin Finck  *
326c2c66affSColin Finck  *  Deletes the specified entry and frees the space allocated to it
327c2c66affSColin Finck  *
328c2c66affSColin Finck  * RETURNS
329c2c66affSColin Finck  *    TRUE if it succeeded
330c2c66affSColin Finck  *    FALSE if it failed
331c2c66affSColin Finck  *
332c2c66affSColin Finck  */
urlcache_entry_free(urlcache_header * header,entry_header * entry)333c2c66affSColin Finck static BOOL urlcache_entry_free(urlcache_header *header, entry_header *entry)
334c2c66affSColin Finck {
335c2c66affSColin Finck     DWORD start_block, block;
336c2c66affSColin Finck 
337c2c66affSColin Finck     /* update allocation table */
338c2c66affSColin Finck     start_block = ((DWORD)((BYTE*)entry - (BYTE*)header) - ENTRY_START_OFFSET) / BLOCKSIZE;
339c2c66affSColin Finck     for(block = start_block; block < start_block+entry->blocks_used; block++)
340c2c66affSColin Finck         urlcache_block_free(header->allocation_table, block);
341c2c66affSColin Finck 
342c2c66affSColin Finck     header->blocks_in_use -= entry->blocks_used;
343c2c66affSColin Finck     return TRUE;
344c2c66affSColin Finck }
345c2c66affSColin Finck 
346c2c66affSColin Finck /***********************************************************************
347c2c66affSColin Finck  *           urlcache_create_hash_table (Internal)
348c2c66affSColin Finck  *
349c2c66affSColin Finck  *  Creates a new hash table in free space and adds it to the chain of existing
350c2c66affSColin Finck  * hash tables.
351c2c66affSColin Finck  *
352c2c66affSColin Finck  * RETURNS
353c2c66affSColin Finck  *    ERROR_SUCCESS if the hash table was created
354c2c66affSColin Finck  *    ERROR_DISK_FULL if the hash table could not be created
355c2c66affSColin Finck  *
356c2c66affSColin Finck  */
urlcache_create_hash_table(urlcache_header * header,entry_hash_table * hash_table_prev,entry_hash_table ** hash_table)357c2c66affSColin Finck static DWORD urlcache_create_hash_table(urlcache_header *header, entry_hash_table *hash_table_prev, entry_hash_table **hash_table)
358c2c66affSColin Finck {
359c2c66affSColin Finck     DWORD dwOffset, error;
360c2c66affSColin Finck     int i;
361c2c66affSColin Finck 
362c2c66affSColin Finck     if((error = urlcache_entry_alloc(header, 0x20, (entry_header**)hash_table)) != ERROR_SUCCESS)
363c2c66affSColin Finck         return error;
364c2c66affSColin Finck 
365c2c66affSColin Finck     dwOffset = (BYTE*)*hash_table-(BYTE*)header;
366c2c66affSColin Finck 
367c2c66affSColin Finck     if(hash_table_prev)
368c2c66affSColin Finck         hash_table_prev->next = dwOffset;
369c2c66affSColin Finck     else
370c2c66affSColin Finck         header->hash_table_off = dwOffset;
371c2c66affSColin Finck 
372c2c66affSColin Finck     (*hash_table)->header.signature = HASH_SIGNATURE;
373c2c66affSColin Finck     (*hash_table)->next = 0;
374c2c66affSColin Finck     (*hash_table)->id = hash_table_prev ? hash_table_prev->id+1 : 0;
375c2c66affSColin Finck     for(i = 0; i < HASHTABLE_SIZE; i++) {
376c2c66affSColin Finck         (*hash_table)->hash_table[i].offset = HASHTABLE_FREE;
377c2c66affSColin Finck         (*hash_table)->hash_table[i].key = HASHTABLE_FREE;
378c2c66affSColin Finck     }
379c2c66affSColin Finck     return ERROR_SUCCESS;
380c2c66affSColin Finck }
381c2c66affSColin Finck 
382c2c66affSColin Finck /***********************************************************************
383c2c66affSColin Finck  *           cache_container_create_object_name (Internal)
384c2c66affSColin Finck  *
385c2c66affSColin Finck  *  Converts a path to a name suitable for use as a Win32 object name.
386c2c66affSColin Finck  * Replaces '\\' characters in-place with the specified character
387c2c66affSColin Finck  * (usually '_' or '!')
388c2c66affSColin Finck  *
389c2c66affSColin Finck  * RETURNS
390c2c66affSColin Finck  *    nothing
391c2c66affSColin Finck  *
392c2c66affSColin Finck  */
cache_container_create_object_name(LPWSTR lpszPath,WCHAR replace)393c2c66affSColin Finck static void cache_container_create_object_name(LPWSTR lpszPath, WCHAR replace)
394c2c66affSColin Finck {
395c2c66affSColin Finck     for (; *lpszPath; lpszPath++)
396c2c66affSColin Finck     {
397c2c66affSColin Finck         if (*lpszPath == '\\')
398c2c66affSColin Finck             *lpszPath = replace;
399c2c66affSColin Finck     }
400c2c66affSColin Finck }
401c2c66affSColin Finck 
402c2c66affSColin Finck /* Caller must hold container lock */
cache_container_map_index(HANDLE file,const WCHAR * path,DWORD size,BOOL * validate)403c2c66affSColin Finck static HANDLE cache_container_map_index(HANDLE file, const WCHAR *path, DWORD size, BOOL *validate)
404c2c66affSColin Finck {
405c2c66affSColin Finck     WCHAR mapping_name[MAX_PATH];
406c2c66affSColin Finck     HANDLE mapping;
407c2c66affSColin Finck 
408*e152f78aSwinesync     wsprintfW(mapping_name, L"%sindex.dat_%lu", path, size);
409c2c66affSColin Finck     cache_container_create_object_name(mapping_name, '_');
410c2c66affSColin Finck 
411c2c66affSColin Finck     mapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, mapping_name);
412c2c66affSColin Finck     if(mapping) {
413c2c66affSColin Finck         if(validate) *validate = FALSE;
414c2c66affSColin Finck         return mapping;
415c2c66affSColin Finck     }
416c2c66affSColin Finck 
417c2c66affSColin Finck     if(validate) *validate = TRUE;
418c2c66affSColin Finck     return CreateFileMappingW(file, NULL, PAGE_READWRITE, 0, 0, mapping_name);
419c2c66affSColin Finck }
420c2c66affSColin Finck 
421c2c66affSColin Finck /* Caller must hold container lock */
cache_container_set_size(cache_container * container,HANDLE file,DWORD blocks_no)422c2c66affSColin Finck static DWORD cache_container_set_size(cache_container *container, HANDLE file, DWORD blocks_no)
423c2c66affSColin Finck {
424c2c66affSColin Finck     DWORD file_size = FILE_SIZE(blocks_no);
425c2c66affSColin Finck     WCHAR dir_path[MAX_PATH], *dir_name;
426c2c66affSColin Finck     entry_hash_table *hashtable_entry;
427c2c66affSColin Finck     urlcache_header *header;
428c2c66affSColin Finck     HANDLE mapping;
429c2c66affSColin Finck     FILETIME ft;
430c2c66affSColin Finck     HKEY key;
431c2c66affSColin Finck     int i, j;
432c2c66affSColin Finck 
433c2c66affSColin Finck     if(SetFilePointer(file, file_size, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
434c2c66affSColin Finck         return GetLastError();
435c2c66affSColin Finck 
436c2c66affSColin Finck     if(!SetEndOfFile(file))
437c2c66affSColin Finck         return GetLastError();
438c2c66affSColin Finck 
439c2c66affSColin Finck     mapping = cache_container_map_index(file, container->path, file_size, NULL);
440c2c66affSColin Finck     if(!mapping)
441c2c66affSColin Finck         return GetLastError();
442c2c66affSColin Finck 
443c2c66affSColin Finck     header = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
444c2c66affSColin Finck     if(!header) {
445c2c66affSColin Finck         CloseHandle(mapping);
446c2c66affSColin Finck         return GetLastError();
447c2c66affSColin Finck     }
448c2c66affSColin Finck 
449c2c66affSColin Finck     if(blocks_no != MIN_BLOCK_NO) {
450c2c66affSColin Finck         if(file_size > header->size)
451c2c66affSColin Finck             memset((char*)header+header->size, 0, file_size-header->size);
452c2c66affSColin Finck         header->size = file_size;
453c2c66affSColin Finck         header->capacity_in_blocks = blocks_no;
454c2c66affSColin Finck 
455c2c66affSColin Finck         UnmapViewOfFile(header);
456c2c66affSColin Finck         CloseHandle(container->mapping);
457c2c66affSColin Finck         container->mapping = mapping;
458c2c66affSColin Finck         container->file_size = file_size;
459c2c66affSColin Finck         return ERROR_SUCCESS;
460c2c66affSColin Finck     }
461c2c66affSColin Finck 
462c2c66affSColin Finck     memset(header, 0, file_size);
463c2c66affSColin Finck     /* First set some constants and defaults in the header */
464c2c66affSColin Finck     memcpy(header->signature, urlcache_ver_prefix, sizeof(urlcache_ver_prefix)-1);
465c2c66affSColin Finck     memcpy(header->signature+sizeof(urlcache_ver_prefix)-1, urlcache_ver, sizeof(urlcache_ver)-1);
466c2c66affSColin Finck     header->size = file_size;
467c2c66affSColin Finck     header->capacity_in_blocks = blocks_no;
468c2c66affSColin Finck     /* 127MB - taken from default for Windows 2000 */
469c2c66affSColin Finck     header->cache_limit.QuadPart = 0x07ff5400;
470c2c66affSColin Finck     /* Copied from a Windows 2000 cache index */
471c2c66affSColin Finck     header->dirs_no = container->default_entry_type==NORMAL_CACHE_ENTRY ? 4 : 0;
472c2c66affSColin Finck 
473c2c66affSColin Finck     /* If the registry has a cache size set, use the registry value */
474*e152f78aSwinesync     if(RegOpenKeyW(HKEY_CURRENT_USER,
475*e152f78aSwinesync                 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content", &key) == ERROR_SUCCESS) {
476c2c66affSColin Finck         DWORD dw, len = sizeof(dw), keytype;
477c2c66affSColin Finck 
478*e152f78aSwinesync         if(RegQueryValueExW(key, L"CacheLimit", NULL, &keytype, (BYTE*)&dw, &len) == ERROR_SUCCESS &&
479c2c66affSColin Finck                 keytype == REG_DWORD)
480c2c66affSColin Finck             header->cache_limit.QuadPart = (ULONGLONG)dw * 1024;
481c2c66affSColin Finck         RegCloseKey(key);
482c2c66affSColin Finck     }
483c2c66affSColin Finck 
484c2c66affSColin Finck     urlcache_create_hash_table(header, NULL, &hashtable_entry);
485c2c66affSColin Finck 
486c2c66affSColin Finck     /* Last step - create the directories */
4875f12c8d7Swinesync     lstrcpyW(dir_path, container->path);
4885f12c8d7Swinesync     dir_name = dir_path + lstrlenW(dir_path);
489c2c66affSColin Finck     dir_name[8] = 0;
490c2c66affSColin Finck 
491c2c66affSColin Finck     GetSystemTimeAsFileTime(&ft);
492c2c66affSColin Finck 
493c2c66affSColin Finck     for(i=0; i<header->dirs_no; ++i) {
494c2c66affSColin Finck         header->directory_data[i].files_no = 0;
495c2c66affSColin Finck         for(j=0;; ++j) {
496c2c66affSColin Finck             ULONGLONG n = ft.dwHighDateTime;
497c2c66affSColin Finck             int k;
498c2c66affSColin Finck 
499c2c66affSColin Finck             /* Generate a file name to attempt to create.
500c2c66affSColin Finck              * This algorithm will create what will appear
501c2c66affSColin Finck              * to be random and unrelated directory names
502c2c66affSColin Finck              * of up to 9 characters in length.
503c2c66affSColin Finck              */
504c2c66affSColin Finck             n <<= 32;
505c2c66affSColin Finck             n += ft.dwLowDateTime;
506c2c66affSColin Finck             n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
507c2c66affSColin Finck 
508c2c66affSColin Finck             for(k = 0; k < 8; ++k) {
509c2c66affSColin Finck                 int r = (n % 36);
510c2c66affSColin Finck 
511c2c66affSColin Finck                 /* Dividing by a prime greater than 36 helps
512c2c66affSColin Finck                  * with the appearance of randomness
513c2c66affSColin Finck                  */
514c2c66affSColin Finck                 n /= 37;
515c2c66affSColin Finck 
516c2c66affSColin Finck                 if(r < 10)
517c2c66affSColin Finck                     dir_name[k] = '0' + r;
518c2c66affSColin Finck                 else
519c2c66affSColin Finck                     dir_name[k] = 'A' + (r - 10);
520c2c66affSColin Finck             }
521c2c66affSColin Finck 
522c2c66affSColin Finck             if(CreateDirectoryW(dir_path, 0)) {
523c2c66affSColin Finck                 /* The following is OK because we generated an
524c2c66affSColin Finck                  * 8 character directory name made from characters
525c2c66affSColin Finck                  * [A-Z0-9], which are equivalent for all code
526c2c66affSColin Finck                  * pages and for UTF-16
527c2c66affSColin Finck                  */
528c2c66affSColin Finck                 for (k = 0; k < 8; ++k)
529c2c66affSColin Finck                     header->directory_data[i].name[k] = dir_name[k];
530c2c66affSColin Finck                 break;
531c2c66affSColin Finck             }else if(j >= 255) {
532c2c66affSColin Finck                 /* Give up. The most likely cause of this
533c2c66affSColin Finck                  * is a full disk, but whatever the cause
534c2c66affSColin Finck                  * is, it should be more than apparent that
535c2c66affSColin Finck                  * we won't succeed.
536c2c66affSColin Finck                  */
537c2c66affSColin Finck                 UnmapViewOfFile(header);
538c2c66affSColin Finck                 CloseHandle(mapping);
539c2c66affSColin Finck                 return GetLastError();
540c2c66affSColin Finck             }
541c2c66affSColin Finck         }
542c2c66affSColin Finck     }
543c2c66affSColin Finck 
544c2c66affSColin Finck     UnmapViewOfFile(header);
545c2c66affSColin Finck     CloseHandle(container->mapping);
546c2c66affSColin Finck     container->mapping = mapping;
547c2c66affSColin Finck     container->file_size = file_size;
548c2c66affSColin Finck     return ERROR_SUCCESS;
549c2c66affSColin Finck }
550c2c66affSColin Finck 
cache_container_is_valid(urlcache_header * header,DWORD file_size)551c2c66affSColin Finck static BOOL cache_container_is_valid(urlcache_header *header, DWORD file_size)
552c2c66affSColin Finck {
553c2c66affSColin Finck     DWORD allocation_size, count_bits, i;
554c2c66affSColin Finck 
555c2c66affSColin Finck     if(file_size < FILE_SIZE(MIN_BLOCK_NO))
556c2c66affSColin Finck         return FALSE;
557c2c66affSColin Finck 
558c2c66affSColin Finck     if(file_size != header->size)
559c2c66affSColin Finck         return FALSE;
560c2c66affSColin Finck 
561c2c66affSColin Finck     if (!memcmp(header->signature, urlcache_ver_prefix, sizeof(urlcache_ver_prefix)-1) &&
562c2c66affSColin Finck             memcmp(header->signature+sizeof(urlcache_ver_prefix)-1, urlcache_ver, sizeof(urlcache_ver)-1))
563c2c66affSColin Finck         return FALSE;
564c2c66affSColin Finck 
565c2c66affSColin Finck     if(FILE_SIZE(header->capacity_in_blocks) != file_size)
566c2c66affSColin Finck         return FALSE;
567c2c66affSColin Finck 
568c2c66affSColin Finck     allocation_size = 0;
569c2c66affSColin Finck     for(i=0; i<header->capacity_in_blocks/8; i++) {
570c2c66affSColin Finck         for(count_bits = header->allocation_table[i]; count_bits!=0; count_bits>>=1) {
571c2c66affSColin Finck             if(count_bits & 1)
572c2c66affSColin Finck                 allocation_size++;
573c2c66affSColin Finck         }
574c2c66affSColin Finck     }
575c2c66affSColin Finck     if(allocation_size != header->blocks_in_use)
576c2c66affSColin Finck         return FALSE;
577c2c66affSColin Finck 
578c2c66affSColin Finck     for(; i<ALLOCATION_TABLE_SIZE; i++) {
579c2c66affSColin Finck         if(header->allocation_table[i])
580c2c66affSColin Finck             return FALSE;
581c2c66affSColin Finck     }
582c2c66affSColin Finck 
583c2c66affSColin Finck     return TRUE;
584c2c66affSColin Finck }
585c2c66affSColin Finck 
586c2c66affSColin Finck /***********************************************************************
587c2c66affSColin Finck  *           cache_container_open_index (Internal)
588c2c66affSColin Finck  *
589c2c66affSColin Finck  *  Opens the index file and saves mapping handle
590c2c66affSColin Finck  *
591c2c66affSColin Finck  * RETURNS
592c2c66affSColin Finck  *    ERROR_SUCCESS if succeeded
593c2c66affSColin Finck  *    Any other Win32 error code if failed
594c2c66affSColin Finck  *
595c2c66affSColin Finck  */
cache_container_open_index(cache_container * container,DWORD blocks_no)596c2c66affSColin Finck static DWORD cache_container_open_index(cache_container *container, DWORD blocks_no)
597c2c66affSColin Finck {
598c2c66affSColin Finck     HANDLE file;
599c2c66affSColin Finck     WCHAR index_path[MAX_PATH];
600c2c66affSColin Finck     DWORD file_size;
601c2c66affSColin Finck     BOOL validate;
602c2c66affSColin Finck 
603c2c66affSColin Finck     WaitForSingleObject(container->mutex, INFINITE);
604c2c66affSColin Finck 
605c2c66affSColin Finck     if(container->mapping) {
606c2c66affSColin Finck         ReleaseMutex(container->mutex);
607c2c66affSColin Finck         return ERROR_SUCCESS;
608c2c66affSColin Finck     }
609c2c66affSColin Finck 
6105f12c8d7Swinesync     lstrcpyW(index_path, container->path);
611*e152f78aSwinesync     lstrcatW(index_path, L"index.dat");
612c2c66affSColin Finck 
613c2c66affSColin Finck     file = CreateFileW(index_path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
614c2c66affSColin Finck     if(file == INVALID_HANDLE_VALUE) {
615c2c66affSColin Finck 	/* Maybe the directory wasn't there? Try to create it */
616c2c66affSColin Finck 	if(CreateDirectoryW(container->path, 0))
617c2c66affSColin Finck             file = CreateFileW(index_path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
618c2c66affSColin Finck     }
619c2c66affSColin Finck     if(file == INVALID_HANDLE_VALUE) {
620c2c66affSColin Finck         TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(index_path));
621c2c66affSColin Finck         ReleaseMutex(container->mutex);
622c2c66affSColin Finck         return GetLastError();
623c2c66affSColin Finck     }
624c2c66affSColin Finck 
625c2c66affSColin Finck     file_size = GetFileSize(file, NULL);
626c2c66affSColin Finck     if(file_size == INVALID_FILE_SIZE) {
627c2c66affSColin Finck         CloseHandle(file);
628c2c66affSColin Finck 	ReleaseMutex(container->mutex);
629c2c66affSColin Finck         return GetLastError();
630c2c66affSColin Finck     }
631c2c66affSColin Finck 
632c2c66affSColin Finck     if(blocks_no < MIN_BLOCK_NO)
633c2c66affSColin Finck         blocks_no = MIN_BLOCK_NO;
634c2c66affSColin Finck     else if(blocks_no > MAX_BLOCK_NO)
635c2c66affSColin Finck         blocks_no = MAX_BLOCK_NO;
636c2c66affSColin Finck 
637c2c66affSColin Finck     if(file_size < FILE_SIZE(blocks_no)) {
638c2c66affSColin Finck         DWORD ret = cache_container_set_size(container, file, blocks_no);
639c2c66affSColin Finck         CloseHandle(file);
640c2c66affSColin Finck         ReleaseMutex(container->mutex);
641c2c66affSColin Finck         return ret;
642c2c66affSColin Finck     }
643c2c66affSColin Finck 
644c2c66affSColin Finck     container->file_size = file_size;
645c2c66affSColin Finck     container->mapping = cache_container_map_index(file, container->path, file_size, &validate);
646c2c66affSColin Finck     CloseHandle(file);
647c2c66affSColin Finck     if(container->mapping && validate) {
648c2c66affSColin Finck         urlcache_header *header = MapViewOfFile(container->mapping, FILE_MAP_WRITE, 0, 0, 0);
649c2c66affSColin Finck 
650c2c66affSColin Finck         if(header && !cache_container_is_valid(header, file_size)) {
651c2c66affSColin Finck             WARN("detected old or broken index.dat file\n");
652c2c66affSColin Finck             UnmapViewOfFile(header);
653c2c66affSColin Finck             FreeUrlCacheSpaceW(container->path, 100, 0);
654c2c66affSColin Finck         }else if(header) {
655c2c66affSColin Finck             UnmapViewOfFile(header);
656c2c66affSColin Finck         }else {
657c2c66affSColin Finck             CloseHandle(container->mapping);
658c2c66affSColin Finck             container->mapping = NULL;
659c2c66affSColin Finck         }
660c2c66affSColin Finck     }
661c2c66affSColin Finck 
662c2c66affSColin Finck     if(!container->mapping)
663c2c66affSColin Finck     {
664c2c66affSColin Finck         ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
665c2c66affSColin Finck         ReleaseMutex(container->mutex);
666c2c66affSColin Finck         return GetLastError();
667c2c66affSColin Finck     }
668c2c66affSColin Finck 
669c2c66affSColin Finck     ReleaseMutex(container->mutex);
670c2c66affSColin Finck     return ERROR_SUCCESS;
671c2c66affSColin Finck }
672c2c66affSColin Finck 
673c2c66affSColin Finck /***********************************************************************
674c2c66affSColin Finck  *           cache_container_close_index (Internal)
675c2c66affSColin Finck  *
676c2c66affSColin Finck  *  Closes the index
677c2c66affSColin Finck  *
678c2c66affSColin Finck  * RETURNS
679c2c66affSColin Finck  *    nothing
680c2c66affSColin Finck  *
681c2c66affSColin Finck  */
cache_container_close_index(cache_container * pContainer)682c2c66affSColin Finck static void cache_container_close_index(cache_container *pContainer)
683c2c66affSColin Finck {
684c2c66affSColin Finck     CloseHandle(pContainer->mapping);
685c2c66affSColin Finck     pContainer->mapping = NULL;
686c2c66affSColin Finck }
687c2c66affSColin Finck 
cache_containers_add(const char * cache_prefix,LPCWSTR path,DWORD default_entry_type,LPWSTR mutex_name)688c2c66affSColin Finck static BOOL cache_containers_add(const char *cache_prefix, LPCWSTR path,
689c2c66affSColin Finck         DWORD default_entry_type, LPWSTR mutex_name)
690c2c66affSColin Finck {
691c2c66affSColin Finck     cache_container *pContainer = heap_alloc(sizeof(cache_container));
692c2c66affSColin Finck     int cache_prefix_len = strlen(cache_prefix);
693c2c66affSColin Finck 
694c2c66affSColin Finck     if (!pContainer)
695c2c66affSColin Finck     {
696c2c66affSColin Finck         return FALSE;
697c2c66affSColin Finck     }
698c2c66affSColin Finck 
699c2c66affSColin Finck     pContainer->mapping = NULL;
700c2c66affSColin Finck     pContainer->file_size = 0;
701c2c66affSColin Finck     pContainer->default_entry_type = default_entry_type;
702c2c66affSColin Finck 
703c2c66affSColin Finck     pContainer->path = heap_strdupW(path);
704c2c66affSColin Finck     if (!pContainer->path)
705c2c66affSColin Finck     {
706c2c66affSColin Finck         heap_free(pContainer);
707c2c66affSColin Finck         return FALSE;
708c2c66affSColin Finck     }
709c2c66affSColin Finck 
710c2c66affSColin Finck     pContainer->cache_prefix = heap_alloc(cache_prefix_len+1);
711c2c66affSColin Finck     if (!pContainer->cache_prefix)
712c2c66affSColin Finck     {
713c2c66affSColin Finck         heap_free(pContainer->path);
714c2c66affSColin Finck         heap_free(pContainer);
715c2c66affSColin Finck         return FALSE;
716c2c66affSColin Finck     }
717c2c66affSColin Finck 
718c2c66affSColin Finck     memcpy(pContainer->cache_prefix, cache_prefix, cache_prefix_len+1);
719c2c66affSColin Finck 
720c2c66affSColin Finck     CharLowerW(mutex_name);
721c2c66affSColin Finck     cache_container_create_object_name(mutex_name, '!');
722c2c66affSColin Finck 
723c2c66affSColin Finck     if ((pContainer->mutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL)
724c2c66affSColin Finck     {
725c2c66affSColin Finck         ERR("couldn't create mutex (error is %d)\n", GetLastError());
726c2c66affSColin Finck         heap_free(pContainer->path);
727c2c66affSColin Finck         heap_free(pContainer);
728c2c66affSColin Finck         return FALSE;
729c2c66affSColin Finck     }
730c2c66affSColin Finck 
731c2c66affSColin Finck     list_add_head(&UrlContainers, &pContainer->entry);
732c2c66affSColin Finck 
733c2c66affSColin Finck     return TRUE;
734c2c66affSColin Finck }
735c2c66affSColin Finck 
cache_container_delete_container(cache_container * pContainer)736c2c66affSColin Finck static void cache_container_delete_container(cache_container *pContainer)
737c2c66affSColin Finck {
738c2c66affSColin Finck     list_remove(&pContainer->entry);
739c2c66affSColin Finck 
740c2c66affSColin Finck     cache_container_close_index(pContainer);
741c2c66affSColin Finck     CloseHandle(pContainer->mutex);
742c2c66affSColin Finck     heap_free(pContainer->path);
743c2c66affSColin Finck     heap_free(pContainer->cache_prefix);
744c2c66affSColin Finck     heap_free(pContainer);
745c2c66affSColin Finck }
746c2c66affSColin Finck 
cache_containers_init(void)747c2c66affSColin Finck static void cache_containers_init(void)
748c2c66affSColin Finck {
749c2c66affSColin Finck     /* ReactOS r50916 */
750c2c66affSColin Finck     static const struct
751c2c66affSColin Finck     {
752c2c66affSColin Finck         int nFolder; /* CSIDL_* constant */
753c2c66affSColin Finck         const WCHAR *shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */
754c2c66affSColin Finck         const char *cache_prefix; /* prefix used to reference the container */
755c2c66affSColin Finck         DWORD default_entry_type;
756c2c66affSColin Finck     } DefaultContainerData[] =
757c2c66affSColin Finck     {
758cde08ff2Swinesync         { CSIDL_INTERNET_CACHE, L"Content.IE5", "", NORMAL_CACHE_ENTRY },
759cde08ff2Swinesync         { CSIDL_HISTORY, L"History.IE5", "Visited:", URLHISTORY_CACHE_ENTRY },
760cde08ff2Swinesync         { CSIDL_COOKIES, L"", "Cookie:", COOKIE_CACHE_ENTRY },
761c2c66affSColin Finck     };
762c2c66affSColin Finck     DWORD i;
763c2c66affSColin Finck 
764c2c66affSColin Finck     /* ReactOS r50916 */
765cde08ff2Swinesync     if (GetEnvironmentVariableW(L"USERPROFILE", NULL, 0) == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)
766c2c66affSColin Finck     {
767c2c66affSColin Finck         ERR("Environment variable 'USERPROFILE' does not exist!\n");
768c2c66affSColin Finck         return;
769c2c66affSColin Finck     }
770c2c66affSColin Finck 
771c239cdd4SAmine Khaldi     for (i = 0; i < ARRAY_SIZE(DefaultContainerData); i++)
772c2c66affSColin Finck     {
773c2c66affSColin Finck         WCHAR wszCachePath[MAX_PATH];
774c2c66affSColin Finck         WCHAR wszMutexName[MAX_PATH];
775c2c66affSColin Finck         int path_len, suffix_len;
776c2c66affSColin Finck         BOOL def_char;
777c2c66affSColin Finck 
778c2c66affSColin Finck         if (!SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE))
779c2c66affSColin Finck         {
780c2c66affSColin Finck             ERR("Couldn't get path for default container %u\n", i);
781c2c66affSColin Finck             continue;
782c2c66affSColin Finck         }
7835f12c8d7Swinesync         path_len = lstrlenW(wszCachePath);
7845f12c8d7Swinesync         suffix_len = lstrlenW(DefaultContainerData[i].shpath_suffix);
785c2c66affSColin Finck 
786c2c66affSColin Finck         if (path_len + suffix_len + 2 > MAX_PATH)
787c2c66affSColin Finck         {
788c2c66affSColin Finck             ERR("Path too long\n");
789c2c66affSColin Finck             continue;
790c2c66affSColin Finck         }
791c2c66affSColin Finck 
792c2c66affSColin Finck         wszCachePath[path_len] = '\\';
793c2c66affSColin Finck         wszCachePath[path_len+1] = 0;
794c2c66affSColin Finck 
7955f12c8d7Swinesync         lstrcpyW(wszMutexName, wszCachePath);
796c2c66affSColin Finck 
797c2c66affSColin Finck         if (suffix_len)
798c2c66affSColin Finck         {
799c2c66affSColin Finck             memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR));
800c2c66affSColin Finck             wszCachePath[path_len + suffix_len + 1] = '\\';
801c2c66affSColin Finck             wszCachePath[path_len + suffix_len + 2] = '\0';
802c2c66affSColin Finck         }
803c2c66affSColin Finck 
804c2c66affSColin Finck         if (!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wszCachePath, path_len,
805c2c66affSColin Finck                     NULL, 0, NULL, &def_char) || def_char)
806c2c66affSColin Finck         {
807c2c66affSColin Finck             WCHAR tmp[MAX_PATH];
808c2c66affSColin Finck 
809c2c66affSColin Finck             /* cannot convert path to ANSI code page */
810c2c66affSColin Finck             if (!(path_len = GetShortPathNameW(wszCachePath, tmp, MAX_PATH)) ||
811c2c66affSColin Finck                 !WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, tmp, path_len,
812c2c66affSColin Finck                     NULL, 0, NULL, &def_char) || def_char)
813c2c66affSColin Finck                 ERR("Can't create container path accessible by ANSI functions\n");
814c2c66affSColin Finck             else
815c2c66affSColin Finck                 memcpy(wszCachePath, tmp, (path_len+1)*sizeof(WCHAR));
816c2c66affSColin Finck         }
817c2c66affSColin Finck 
818c2c66affSColin Finck         cache_containers_add(DefaultContainerData[i].cache_prefix, wszCachePath,
819c2c66affSColin Finck                 DefaultContainerData[i].default_entry_type, wszMutexName);
820c2c66affSColin Finck     }
821c2c66affSColin Finck 
822c2c66affSColin Finck #ifdef __REACTOS__
823c2c66affSColin Finck     bDefaultContainersAdded = TRUE;
824c2c66affSColin Finck #endif
825c2c66affSColin Finck }
826c2c66affSColin Finck 
cache_containers_free(void)827c2c66affSColin Finck static void cache_containers_free(void)
828c2c66affSColin Finck {
829c2c66affSColin Finck     while(!list_empty(&UrlContainers))
830c2c66affSColin Finck         cache_container_delete_container(
831c2c66affSColin Finck             LIST_ENTRY(list_head(&UrlContainers), cache_container, entry)
832c2c66affSColin Finck         );
833c2c66affSColin Finck }
834c2c66affSColin Finck 
cache_containers_find(const char * url,cache_container ** ret)835c2c66affSColin Finck static DWORD cache_containers_find(const char *url, cache_container **ret)
836c2c66affSColin Finck {
837c2c66affSColin Finck     cache_container *container;
838c2c66affSColin Finck 
839c2c66affSColin Finck     TRACE("searching for prefix for URL: %s\n", debugstr_a(url));
840c2c66affSColin Finck 
841c2c66affSColin Finck     if(!url)
842c2c66affSColin Finck         return ERROR_INVALID_PARAMETER;
843c2c66affSColin Finck 
844c2c66affSColin Finck #ifdef __REACTOS__
845c2c66affSColin Finck     /* ReactOS r54992 */
846c2c66affSColin Finck     if (!bDefaultContainersAdded)
847c2c66affSColin Finck         cache_containers_init();
848c2c66affSColin Finck #endif
849c2c66affSColin Finck 
850c2c66affSColin Finck     LIST_FOR_EACH_ENTRY(container, &UrlContainers, cache_container, entry)
851c2c66affSColin Finck     {
852c2c66affSColin Finck         int prefix_len = strlen(container->cache_prefix);
853c2c66affSColin Finck 
854c2c66affSColin Finck         if(!strncmp(container->cache_prefix, url, prefix_len)) {
855c2c66affSColin Finck             TRACE("found container with prefix %s\n", debugstr_a(container->cache_prefix));
856c2c66affSColin Finck             *ret = container;
857c2c66affSColin Finck             return ERROR_SUCCESS;
858c2c66affSColin Finck         }
859c2c66affSColin Finck     }
860c2c66affSColin Finck 
861c2c66affSColin Finck     ERR("no container found\n");
862c2c66affSColin Finck     return ERROR_FILE_NOT_FOUND;
863c2c66affSColin Finck }
864c2c66affSColin Finck 
cache_containers_enum(char * search_pattern,DWORD index,cache_container ** ret)865c2c66affSColin Finck static BOOL cache_containers_enum(char *search_pattern, DWORD index, cache_container **ret)
866c2c66affSColin Finck {
867c2c66affSColin Finck     DWORD i = 0;
868c2c66affSColin Finck     cache_container *container;
869c2c66affSColin Finck 
870c2c66affSColin Finck     TRACE("searching for prefix: %s\n", debugstr_a(search_pattern));
871c2c66affSColin Finck 
872c2c66affSColin Finck     /* non-NULL search pattern only returns one container ever */
873c2c66affSColin Finck     if (search_pattern && index > 0)
874c2c66affSColin Finck         return FALSE;
875c2c66affSColin Finck 
876c2c66affSColin Finck #ifdef __REACTOS__
877c2c66affSColin Finck     /* ReactOS r54992 */
878c2c66affSColin Finck     if (!bDefaultContainersAdded)
879c2c66affSColin Finck         cache_containers_init();
880c2c66affSColin Finck #endif
881c2c66affSColin Finck 
882c2c66affSColin Finck     LIST_FOR_EACH_ENTRY(container, &UrlContainers, cache_container, entry)
883c2c66affSColin Finck     {
884c2c66affSColin Finck         if (search_pattern)
885c2c66affSColin Finck         {
886c2c66affSColin Finck             if (!strcmp(container->cache_prefix, search_pattern))
887c2c66affSColin Finck             {
888c2c66affSColin Finck                 TRACE("found container with prefix %s\n", debugstr_a(container->cache_prefix));
889c2c66affSColin Finck                 *ret = container;
890c2c66affSColin Finck                 return TRUE;
891c2c66affSColin Finck             }
892c2c66affSColin Finck         }
893c2c66affSColin Finck         else
894c2c66affSColin Finck         {
895c2c66affSColin Finck             if (i == index)
896c2c66affSColin Finck             {
897c2c66affSColin Finck                 TRACE("found container with prefix %s\n", debugstr_a(container->cache_prefix));
898c2c66affSColin Finck                 *ret = container;
899c2c66affSColin Finck                 return TRUE;
900c2c66affSColin Finck             }
901c2c66affSColin Finck         }
902c2c66affSColin Finck         i++;
903c2c66affSColin Finck     }
904c2c66affSColin Finck     return FALSE;
905c2c66affSColin Finck }
906c2c66affSColin Finck 
907c2c66affSColin Finck /***********************************************************************
908c2c66affSColin Finck  *           cache_container_lock_index (Internal)
909c2c66affSColin Finck  *
910c2c66affSColin Finck  * Locks the index for system-wide exclusive access.
911c2c66affSColin Finck  *
912c2c66affSColin Finck  * RETURNS
913c2c66affSColin Finck  *  Cache file header if successful
914c2c66affSColin Finck  *  NULL if failed and calls SetLastError.
915c2c66affSColin Finck  */
cache_container_lock_index(cache_container * pContainer)916c2c66affSColin Finck static urlcache_header* cache_container_lock_index(cache_container *pContainer)
917c2c66affSColin Finck {
918c2c66affSColin Finck     BYTE index;
919c2c66affSColin Finck     LPVOID pIndexData;
920c2c66affSColin Finck     urlcache_header* pHeader;
921c2c66affSColin Finck     DWORD error;
922c2c66affSColin Finck 
923c2c66affSColin Finck     /* acquire mutex */
924c2c66affSColin Finck     WaitForSingleObject(pContainer->mutex, INFINITE);
925c2c66affSColin Finck 
926c2c66affSColin Finck     pIndexData = MapViewOfFile(pContainer->mapping, FILE_MAP_WRITE, 0, 0, 0);
927c2c66affSColin Finck 
928c2c66affSColin Finck     if (!pIndexData)
929c2c66affSColin Finck     {
930c2c66affSColin Finck         ReleaseMutex(pContainer->mutex);
931c2c66affSColin Finck         ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
932c2c66affSColin Finck         return NULL;
933c2c66affSColin Finck     }
934c2c66affSColin Finck     pHeader = (urlcache_header*)pIndexData;
935c2c66affSColin Finck 
936c2c66affSColin Finck     /* file has grown - we need to remap to prevent us getting
937c2c66affSColin Finck      * access violations when we try and access beyond the end
938c2c66affSColin Finck      * of the memory mapped file */
939c2c66affSColin Finck     if (pHeader->size != pContainer->file_size)
940c2c66affSColin Finck     {
941c2c66affSColin Finck         UnmapViewOfFile( pHeader );
942c2c66affSColin Finck         cache_container_close_index(pContainer);
943c2c66affSColin Finck         error = cache_container_open_index(pContainer, MIN_BLOCK_NO);
944c2c66affSColin Finck         if (error != ERROR_SUCCESS)
945c2c66affSColin Finck         {
946c2c66affSColin Finck             ReleaseMutex(pContainer->mutex);
947c2c66affSColin Finck             SetLastError(error);
948c2c66affSColin Finck             return NULL;
949c2c66affSColin Finck         }
950c2c66affSColin Finck         pIndexData = MapViewOfFile(pContainer->mapping, FILE_MAP_WRITE, 0, 0, 0);
951c2c66affSColin Finck 
952c2c66affSColin Finck         if (!pIndexData)
953c2c66affSColin Finck         {
954c2c66affSColin Finck             ReleaseMutex(pContainer->mutex);
955c2c66affSColin Finck             ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
956c2c66affSColin Finck             return NULL;
957c2c66affSColin Finck         }
958c2c66affSColin Finck         pHeader = (urlcache_header*)pIndexData;
959c2c66affSColin Finck     }
960c2c66affSColin Finck 
961c2c66affSColin Finck     TRACE("Signature: %s, file size: %d bytes\n", pHeader->signature, pHeader->size);
962c2c66affSColin Finck 
963c2c66affSColin Finck     for (index = 0; index < pHeader->dirs_no; index++)
964c2c66affSColin Finck     {
965c2c66affSColin Finck         TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].name);
966c2c66affSColin Finck     }
967c2c66affSColin Finck 
968c2c66affSColin Finck     return pHeader;
969c2c66affSColin Finck }
970c2c66affSColin Finck 
971c2c66affSColin Finck /***********************************************************************
972c2c66affSColin Finck  *           cache_container_unlock_index (Internal)
973c2c66affSColin Finck  *
974c2c66affSColin Finck  */
cache_container_unlock_index(cache_container * pContainer,urlcache_header * pHeader)975c2c66affSColin Finck static BOOL cache_container_unlock_index(cache_container *pContainer, urlcache_header *pHeader)
976c2c66affSColin Finck {
977c2c66affSColin Finck     /* release mutex */
978c2c66affSColin Finck     ReleaseMutex(pContainer->mutex);
979c2c66affSColin Finck     return UnmapViewOfFile(pHeader);
980c2c66affSColin Finck }
981c2c66affSColin Finck 
982c2c66affSColin Finck /***********************************************************************
983c2c66affSColin Finck  *           urlcache_create_file_pathW (Internal)
984c2c66affSColin Finck  *
985c2c66affSColin Finck  *  Copies the full path to the specified buffer given the local file
986c2c66affSColin Finck  * name and the index of the directory it is in. Always sets value in
987c2c66affSColin Finck  * lpBufferSize to the required buffer size (in bytes).
988c2c66affSColin Finck  *
989c2c66affSColin Finck  * RETURNS
990c2c66affSColin Finck  *    TRUE if the buffer was big enough
991c2c66affSColin Finck  *    FALSE if the buffer was too small
992c2c66affSColin Finck  *
993c2c66affSColin Finck  */
urlcache_create_file_pathW(const cache_container * pContainer,const urlcache_header * pHeader,LPCSTR szLocalFileName,BYTE Directory,LPWSTR wszPath,LPLONG lpBufferSize,BOOL trunc_name)994c2c66affSColin Finck static BOOL urlcache_create_file_pathW(
995c2c66affSColin Finck     const cache_container *pContainer,
996c2c66affSColin Finck     const urlcache_header *pHeader,
997c2c66affSColin Finck     LPCSTR szLocalFileName,
998c2c66affSColin Finck     BYTE Directory,
999c2c66affSColin Finck     LPWSTR wszPath,
1000c2c66affSColin Finck     LPLONG lpBufferSize,
1001c2c66affSColin Finck     BOOL trunc_name)
1002c2c66affSColin Finck {
1003c2c66affSColin Finck     LONG nRequired;
10045f12c8d7Swinesync     int path_len = lstrlenW(pContainer->path);
1005c2c66affSColin Finck     int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0);
1006c2c66affSColin Finck     if (Directory!=CACHE_CONTAINER_NO_SUBDIR && Directory>=pHeader->dirs_no)
1007c2c66affSColin Finck     {
1008c2c66affSColin Finck         *lpBufferSize = 0;
1009c2c66affSColin Finck         return FALSE;
1010c2c66affSColin Finck     }
1011c2c66affSColin Finck 
1012c2c66affSColin Finck     nRequired = (path_len + file_name_len) * sizeof(WCHAR);
1013c2c66affSColin Finck     if(Directory != CACHE_CONTAINER_NO_SUBDIR)
1014c2c66affSColin Finck         nRequired += (DIR_LENGTH + 1) * sizeof(WCHAR);
1015c2c66affSColin Finck     if (trunc_name && nRequired >= *lpBufferSize)
1016c2c66affSColin Finck         nRequired = *lpBufferSize;
1017c2c66affSColin Finck     if (nRequired <= *lpBufferSize)
1018c2c66affSColin Finck     {
1019c2c66affSColin Finck         int dir_len;
1020c2c66affSColin Finck 
1021c2c66affSColin Finck         memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR));
1022c2c66affSColin Finck         if (Directory != CACHE_CONTAINER_NO_SUBDIR)
1023c2c66affSColin Finck         {
1024c2c66affSColin Finck             dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].name, DIR_LENGTH, wszPath + path_len, DIR_LENGTH);
1025c2c66affSColin Finck             wszPath[dir_len + path_len] = '\\';
1026c2c66affSColin Finck             dir_len++;
1027c2c66affSColin Finck         }
1028c2c66affSColin Finck         else
1029c2c66affSColin Finck         {
1030c2c66affSColin Finck             dir_len = 0;
1031c2c66affSColin Finck         }
1032c2c66affSColin Finck         MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len,
1033c2c66affSColin Finck                 *lpBufferSize/sizeof(WCHAR)-dir_len-path_len);
1034c2c66affSColin Finck         wszPath[*lpBufferSize/sizeof(WCHAR)-1] = 0;
1035c2c66affSColin Finck         *lpBufferSize = nRequired;
1036c2c66affSColin Finck         return TRUE;
1037c2c66affSColin Finck     }
1038c2c66affSColin Finck     *lpBufferSize = nRequired;
1039c2c66affSColin Finck     return FALSE;
1040c2c66affSColin Finck }
1041c2c66affSColin Finck 
1042c2c66affSColin Finck /***********************************************************************
1043c2c66affSColin Finck  *           urlcache_create_file_pathA (Internal)
1044c2c66affSColin Finck  *
1045c2c66affSColin Finck  *  Copies the full path to the specified buffer given the local file
1046c2c66affSColin Finck  * name and the index of the directory it is in. Always sets value in
1047c2c66affSColin Finck  * lpBufferSize to the required buffer size.
1048c2c66affSColin Finck  *
1049c2c66affSColin Finck  * RETURNS
1050c2c66affSColin Finck  *    TRUE if the buffer was big enough
1051c2c66affSColin Finck  *    FALSE if the buffer was too small
1052c2c66affSColin Finck  *
1053c2c66affSColin Finck  */
urlcache_create_file_pathA(const cache_container * pContainer,const urlcache_header * pHeader,LPCSTR szLocalFileName,BYTE Directory,LPSTR szPath,LPLONG lpBufferSize)1054c2c66affSColin Finck static BOOL urlcache_create_file_pathA(
1055c2c66affSColin Finck     const cache_container *pContainer,
1056c2c66affSColin Finck     const urlcache_header *pHeader,
1057c2c66affSColin Finck     LPCSTR szLocalFileName,
1058c2c66affSColin Finck     BYTE Directory,
1059c2c66affSColin Finck     LPSTR szPath,
1060c2c66affSColin Finck     LPLONG lpBufferSize)
1061c2c66affSColin Finck {
1062c2c66affSColin Finck     LONG nRequired;
1063c2c66affSColin Finck     int path_len, file_name_len, dir_len;
1064c2c66affSColin Finck 
1065c2c66affSColin Finck     if (Directory!=CACHE_CONTAINER_NO_SUBDIR && Directory>=pHeader->dirs_no)
1066c2c66affSColin Finck     {
1067c2c66affSColin Finck         *lpBufferSize = 0;
1068c2c66affSColin Finck         return FALSE;
1069c2c66affSColin Finck     }
1070c2c66affSColin Finck 
1071c2c66affSColin Finck     path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL) - 1;
1072c2c66affSColin Finck     file_name_len = strlen(szLocalFileName) + 1 /* for nul-terminator */;
1073c2c66affSColin Finck     if (Directory!=CACHE_CONTAINER_NO_SUBDIR)
1074c2c66affSColin Finck         dir_len = DIR_LENGTH+1;
1075c2c66affSColin Finck     else
1076c2c66affSColin Finck         dir_len = 0;
1077c2c66affSColin Finck 
1078c2c66affSColin Finck     nRequired = (path_len + dir_len + file_name_len) * sizeof(char);
1079c2c66affSColin Finck     if (nRequired <= *lpBufferSize)
1080c2c66affSColin Finck     {
1081c2c66affSColin Finck         WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, path_len, NULL, NULL);
1082c2c66affSColin Finck         if(dir_len) {
1083c2c66affSColin Finck             memcpy(szPath+path_len, pHeader->directory_data[Directory].name, dir_len-1);
1084c2c66affSColin Finck             szPath[path_len + dir_len-1] = '\\';
1085c2c66affSColin Finck         }
1086c2c66affSColin Finck         memcpy(szPath + path_len + dir_len, szLocalFileName, file_name_len);
1087c2c66affSColin Finck         *lpBufferSize = nRequired;
1088c2c66affSColin Finck         return TRUE;
1089c2c66affSColin Finck     }
1090c2c66affSColin Finck     *lpBufferSize = nRequired;
1091c2c66affSColin Finck     return FALSE;
1092c2c66affSColin Finck }
1093c2c66affSColin Finck 
1094c2c66affSColin Finck /* Just like FileTimeToDosDateTime, except that it also maps the special
1095c2c66affSColin Finck  * case of a filetime of (0,0) to a DOS date/time of (0,0).
1096c2c66affSColin Finck  */
file_time_to_dos_date_time(const FILETIME * ft,WORD * fatdate,WORD * fattime)1097c2c66affSColin Finck static void file_time_to_dos_date_time(const FILETIME *ft, WORD *fatdate,
1098c2c66affSColin Finck                                            WORD *fattime)
1099c2c66affSColin Finck {
1100c2c66affSColin Finck     if (!ft->dwLowDateTime && !ft->dwHighDateTime)
1101c2c66affSColin Finck         *fatdate = *fattime = 0;
1102c2c66affSColin Finck     else
1103c2c66affSColin Finck         FileTimeToDosDateTime(ft, fatdate, fattime);
1104c2c66affSColin Finck }
1105c2c66affSColin Finck 
1106c2c66affSColin Finck /***********************************************************************
1107c2c66affSColin Finck  *           urlcache_delete_file (Internal)
1108c2c66affSColin Finck  */
urlcache_delete_file(const cache_container * container,urlcache_header * header,entry_url * url_entry)1109c2c66affSColin Finck static DWORD urlcache_delete_file(const cache_container *container,
1110c2c66affSColin Finck         urlcache_header *header, entry_url *url_entry)
1111c2c66affSColin Finck {
1112c2c66affSColin Finck     WIN32_FILE_ATTRIBUTE_DATA attr;
1113c2c66affSColin Finck     WCHAR path[MAX_PATH];
1114c2c66affSColin Finck     LONG path_size = sizeof(path);
1115c2c66affSColin Finck     DWORD err;
1116c2c66affSColin Finck     WORD date, time;
1117c2c66affSColin Finck 
1118c2c66affSColin Finck     if(!url_entry->local_name_off)
1119c2c66affSColin Finck         goto succ;
1120c2c66affSColin Finck 
1121c2c66affSColin Finck     if(!urlcache_create_file_pathW(container, header,
1122c2c66affSColin Finck                 (LPCSTR)url_entry+url_entry->local_name_off,
1123c2c66affSColin Finck                 url_entry->cache_dir, path, &path_size, FALSE))
1124c2c66affSColin Finck         goto succ;
1125c2c66affSColin Finck 
1126c2c66affSColin Finck     if(!GetFileAttributesExW(path, GetFileExInfoStandard, &attr))
1127c2c66affSColin Finck         goto succ;
1128c2c66affSColin Finck     file_time_to_dos_date_time(&attr.ftLastWriteTime, &date, &time);
1129c2c66affSColin Finck     if(date != url_entry->write_date || time != url_entry->write_time)
1130c2c66affSColin Finck         goto succ;
1131c2c66affSColin Finck 
1132c2c66affSColin Finck     err = (DeleteFileW(path) ? ERROR_SUCCESS : GetLastError());
1133c2c66affSColin Finck     if(err == ERROR_ACCESS_DENIED || err == ERROR_SHARING_VIOLATION)
1134c2c66affSColin Finck         return err;
1135c2c66affSColin Finck 
1136c2c66affSColin Finck succ:
1137c2c66affSColin Finck     if (url_entry->cache_dir < header->dirs_no)
1138c2c66affSColin Finck     {
1139c2c66affSColin Finck         if (header->directory_data[url_entry->cache_dir].files_no)
1140c2c66affSColin Finck             header->directory_data[url_entry->cache_dir].files_no--;
1141c2c66affSColin Finck     }
1142c2c66affSColin Finck     if (url_entry->cache_entry_type & STICKY_CACHE_ENTRY)
1143c2c66affSColin Finck     {
1144c2c66affSColin Finck         if (url_entry->size.QuadPart < header->exempt_usage.QuadPart)
1145c2c66affSColin Finck             header->exempt_usage.QuadPart -= url_entry->size.QuadPart;
1146c2c66affSColin Finck         else
1147c2c66affSColin Finck             header->exempt_usage.QuadPart = 0;
1148c2c66affSColin Finck     }
1149c2c66affSColin Finck     else
1150c2c66affSColin Finck     {
1151c2c66affSColin Finck         if (url_entry->size.QuadPart < header->cache_usage.QuadPart)
1152c2c66affSColin Finck             header->cache_usage.QuadPart -= url_entry->size.QuadPart;
1153c2c66affSColin Finck         else
1154c2c66affSColin Finck             header->cache_usage.QuadPart = 0;
1155c2c66affSColin Finck     }
1156c2c66affSColin Finck 
1157c2c66affSColin Finck     return ERROR_SUCCESS;
1158c2c66affSColin Finck }
1159c2c66affSColin Finck 
urlcache_clean_leaked_entries(cache_container * container,urlcache_header * header)1160c2c66affSColin Finck static BOOL urlcache_clean_leaked_entries(cache_container *container, urlcache_header *header)
1161c2c66affSColin Finck {
1162c2c66affSColin Finck     DWORD *leak_off;
1163c2c66affSColin Finck     BOOL freed = FALSE;
1164c2c66affSColin Finck 
1165c2c66affSColin Finck     leak_off = &header->options[CACHE_HEADER_DATA_ROOT_LEAK_OFFSET];
1166c2c66affSColin Finck     while(*leak_off) {
1167c2c66affSColin Finck         entry_url *url_entry = (entry_url*)((LPBYTE)header + *leak_off);
1168c2c66affSColin Finck 
1169c2c66affSColin Finck         if(SUCCEEDED(urlcache_delete_file(container, header, url_entry))) {
1170c2c66affSColin Finck             *leak_off = url_entry->exempt_delta;
1171c2c66affSColin Finck             urlcache_entry_free(header, &url_entry->header);
1172c2c66affSColin Finck             freed = TRUE;
1173c2c66affSColin Finck         }else {
1174c2c66affSColin Finck             leak_off = &url_entry->exempt_delta;
1175c2c66affSColin Finck         }
1176c2c66affSColin Finck     }
1177c2c66affSColin Finck 
1178c2c66affSColin Finck     return freed;
1179c2c66affSColin Finck }
1180c2c66affSColin Finck 
1181c2c66affSColin Finck /***********************************************************************
1182c2c66affSColin Finck  *           cache_container_clean_index (Internal)
1183c2c66affSColin Finck  *
1184c2c66affSColin Finck  * This function is meant to make place in index file by removing leaked
1185c2c66affSColin Finck  * files entries and resizing the file.
1186c2c66affSColin Finck  *
1187c2c66affSColin Finck  * CAUTION: file view may get mapped to new memory
1188c2c66affSColin Finck  *
1189c2c66affSColin Finck  * RETURNS
1190c2c66affSColin Finck  *     ERROR_SUCCESS when new memory is available
1191c2c66affSColin Finck  *     error code otherwise
1192c2c66affSColin Finck  */
cache_container_clean_index(cache_container * container,urlcache_header ** file_view)1193c2c66affSColin Finck static DWORD cache_container_clean_index(cache_container *container, urlcache_header **file_view)
1194c2c66affSColin Finck {
1195c2c66affSColin Finck     urlcache_header *header = *file_view;
1196c2c66affSColin Finck     DWORD ret;
1197c2c66affSColin Finck 
1198c2c66affSColin Finck     TRACE("(%s %s)\n", debugstr_a(container->cache_prefix), debugstr_w(container->path));
1199c2c66affSColin Finck 
1200c2c66affSColin Finck     if(urlcache_clean_leaked_entries(container, header))
1201c2c66affSColin Finck         return ERROR_SUCCESS;
1202c2c66affSColin Finck 
1203c2c66affSColin Finck     if(header->size >= ALLOCATION_TABLE_SIZE*8*BLOCKSIZE + ENTRY_START_OFFSET) {
1204c2c66affSColin Finck         WARN("index file has maximal size\n");
1205c2c66affSColin Finck         return ERROR_NOT_ENOUGH_MEMORY;
1206c2c66affSColin Finck     }
1207c2c66affSColin Finck 
1208c2c66affSColin Finck     cache_container_close_index(container);
1209c2c66affSColin Finck     ret = cache_container_open_index(container, header->capacity_in_blocks*2);
1210c2c66affSColin Finck     if(ret != ERROR_SUCCESS)
1211c2c66affSColin Finck         return ret;
1212c2c66affSColin Finck     header = MapViewOfFile(container->mapping, FILE_MAP_WRITE, 0, 0, 0);
1213c2c66affSColin Finck     if(!header)
1214c2c66affSColin Finck         return GetLastError();
1215c2c66affSColin Finck 
1216c2c66affSColin Finck     UnmapViewOfFile(*file_view);
1217c2c66affSColin Finck     *file_view = header;
1218c2c66affSColin Finck     return ERROR_SUCCESS;
1219c2c66affSColin Finck }
1220c2c66affSColin Finck 
1221c2c66affSColin Finck /* Just like DosDateTimeToFileTime, except that it also maps the special
1222c2c66affSColin Finck  * case of a DOS date/time of (0,0) to a filetime of (0,0).
1223c2c66affSColin Finck  */
dos_date_time_to_file_time(WORD fatdate,WORD fattime,FILETIME * ft)1224c2c66affSColin Finck static void dos_date_time_to_file_time(WORD fatdate, WORD fattime,
1225c2c66affSColin Finck                                            FILETIME *ft)
1226c2c66affSColin Finck {
1227c2c66affSColin Finck     if (!fatdate && !fattime)
1228c2c66affSColin Finck         ft->dwLowDateTime = ft->dwHighDateTime = 0;
1229c2c66affSColin Finck     else
1230c2c66affSColin Finck         DosDateTimeToFileTime(fatdate, fattime, ft);
1231c2c66affSColin Finck }
1232c2c66affSColin Finck 
urlcache_decode_url(const char * url,WCHAR * decoded_url,int decoded_len)1233c2c66affSColin Finck static int urlcache_decode_url(const char *url, WCHAR *decoded_url, int decoded_len)
1234c2c66affSColin Finck {
1235c2c66affSColin Finck     URL_COMPONENTSA uc;
1236c2c66affSColin Finck     DWORD len, part_len;
1237c2c66affSColin Finck     WCHAR *host_name;
1238c2c66affSColin Finck 
1239c2c66affSColin Finck     memset(&uc, 0, sizeof(uc));
1240c2c66affSColin Finck     uc.dwStructSize = sizeof(uc);
1241c2c66affSColin Finck     uc.dwHostNameLength = 1;
1242c2c66affSColin Finck     if(!InternetCrackUrlA(url, 0, 0, &uc))
1243c2c66affSColin Finck         uc.nScheme = INTERNET_SCHEME_UNKNOWN;
1244c2c66affSColin Finck 
1245c2c66affSColin Finck     if(uc.nScheme!=INTERNET_SCHEME_HTTP && uc.nScheme!=INTERNET_SCHEME_HTTPS)
1246c2c66affSColin Finck         return MultiByteToWideChar(CP_UTF8, 0, url, -1, decoded_url, decoded_len);
1247c2c66affSColin Finck 
1248c2c66affSColin Finck     if(!decoded_url)
1249c2c66affSColin Finck         decoded_len = 0;
1250c2c66affSColin Finck 
1251c2c66affSColin Finck     len = MultiByteToWideChar(CP_UTF8, 0, url, uc.lpszHostName-url, decoded_url, decoded_len);
1252c2c66affSColin Finck     if(!len)
1253c2c66affSColin Finck         return 0;
1254c2c66affSColin Finck     if(decoded_url)
1255c2c66affSColin Finck         decoded_len -= len;
1256c2c66affSColin Finck 
1257c2c66affSColin Finck     host_name = heap_alloc(uc.dwHostNameLength*sizeof(WCHAR));
1258c2c66affSColin Finck     if(!host_name)
1259c2c66affSColin Finck         return 0;
1260c2c66affSColin Finck     if(!MultiByteToWideChar(CP_UTF8, 0, uc.lpszHostName, uc.dwHostNameLength,
1261c2c66affSColin Finck                 host_name, uc.dwHostNameLength)) {
1262c2c66affSColin Finck         heap_free(host_name);
1263c2c66affSColin Finck         return 0;
1264c2c66affSColin Finck     }
1265c2c66affSColin Finck     part_len = IdnToUnicode(0, host_name, uc.dwHostNameLength,
1266c2c66affSColin Finck             decoded_url ? decoded_url+len : NULL, decoded_len);
1267c2c66affSColin Finck     heap_free(host_name);
1268c2c66affSColin Finck     if(!part_len) {
1269c2c66affSColin Finck         SetLastError(ERROR_INTERNET_INVALID_URL);
1270c2c66affSColin Finck         return 0;
1271c2c66affSColin Finck     }
1272c2c66affSColin Finck     len += part_len;
1273c2c66affSColin Finck     if(decoded_url)
1274c2c66affSColin Finck         decoded_len -= part_len;
1275c2c66affSColin Finck 
1276c2c66affSColin Finck     part_len = MultiByteToWideChar(CP_UTF8, 0,
1277c2c66affSColin Finck             uc.lpszHostName+uc.dwHostNameLength,
1278c2c66affSColin Finck             -1, decoded_url ? decoded_url+len : NULL, decoded_len);
1279c2c66affSColin Finck     if(!part_len)
1280c2c66affSColin Finck         return 0;
1281c2c66affSColin Finck     len += part_len;
1282c2c66affSColin Finck 
1283c2c66affSColin Finck     return len;
1284c2c66affSColin Finck }
1285c2c66affSColin Finck 
1286c2c66affSColin Finck /***********************************************************************
1287c2c66affSColin Finck  *           urlcache_copy_entry (Internal)
1288c2c66affSColin Finck  *
1289c2c66affSColin Finck  *  Copies an entry from the cache index file to the Win32 structure
1290c2c66affSColin Finck  *
1291c2c66affSColin Finck  * RETURNS
1292c2c66affSColin Finck  *    ERROR_SUCCESS if the buffer was big enough
1293c2c66affSColin Finck  *    ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1294c2c66affSColin Finck  *
1295c2c66affSColin Finck  */
urlcache_copy_entry(cache_container * container,const urlcache_header * header,INTERNET_CACHE_ENTRY_INFOA * entry_info,DWORD * info_size,const entry_url * url_entry,BOOL unicode)1296c2c66affSColin Finck static DWORD urlcache_copy_entry(cache_container *container, const urlcache_header *header,
1297c2c66affSColin Finck         INTERNET_CACHE_ENTRY_INFOA *entry_info, DWORD *info_size, const entry_url *url_entry, BOOL unicode)
1298c2c66affSColin Finck {
1299c2c66affSColin Finck     int url_len;
1300c2c66affSColin Finck     DWORD size = sizeof(*entry_info);
1301c2c66affSColin Finck 
1302c2c66affSColin Finck     if(*info_size >= size) {
1303c2c66affSColin Finck         entry_info->lpHeaderInfo = NULL;
1304c2c66affSColin Finck         entry_info->lpszFileExtension = NULL;
1305c2c66affSColin Finck         entry_info->lpszLocalFileName = NULL;
1306c2c66affSColin Finck         entry_info->lpszSourceUrlName = NULL;
1307c2c66affSColin Finck         entry_info->CacheEntryType = url_entry->cache_entry_type;
1308c2c66affSColin Finck         entry_info->u.dwExemptDelta = url_entry->exempt_delta;
1309c2c66affSColin Finck         entry_info->dwHeaderInfoSize = url_entry->header_info_size;
1310c2c66affSColin Finck         entry_info->dwHitRate = url_entry->hit_rate;
1311c2c66affSColin Finck         entry_info->dwSizeHigh = url_entry->size.u.HighPart;
1312c2c66affSColin Finck         entry_info->dwSizeLow = url_entry->size.u.LowPart;
1313c2c66affSColin Finck         entry_info->dwStructSize = sizeof(*entry_info);
1314c2c66affSColin Finck         entry_info->dwUseCount = url_entry->use_count;
1315c2c66affSColin Finck         dos_date_time_to_file_time(url_entry->expire_date, url_entry->expire_time, &entry_info->ExpireTime);
1316c2c66affSColin Finck         entry_info->LastAccessTime = url_entry->access_time;
1317c2c66affSColin Finck         entry_info->LastModifiedTime = url_entry->modification_time;
1318c2c66affSColin Finck         dos_date_time_to_file_time(url_entry->sync_date, url_entry->sync_time, &entry_info->LastSyncTime);
1319c2c66affSColin Finck     }
1320c2c66affSColin Finck 
1321c2c66affSColin Finck     if(unicode)
1322c2c66affSColin Finck         url_len = urlcache_decode_url((const char*)url_entry+url_entry->url_off, NULL, 0);
1323c2c66affSColin Finck     else
1324c2c66affSColin Finck         url_len = strlen((LPCSTR)url_entry+url_entry->url_off) + 1;
1325c2c66affSColin Finck     size += url_len * (unicode ? sizeof(WCHAR) : sizeof(CHAR));
1326c2c66affSColin Finck 
1327c2c66affSColin Finck     if(*info_size >= size) {
1328c2c66affSColin Finck         DWORD url_size = url_len * (unicode ? sizeof(WCHAR) : sizeof(CHAR));
1329c2c66affSColin Finck 
1330c2c66affSColin Finck         entry_info->lpszSourceUrlName = (LPSTR)entry_info+size-url_size;
1331c2c66affSColin Finck         if(unicode)
1332c2c66affSColin Finck             urlcache_decode_url((const char*)url_entry+url_entry->url_off, (WCHAR*)entry_info->lpszSourceUrlName, url_len);
1333c2c66affSColin Finck         else
1334c2c66affSColin Finck             memcpy(entry_info->lpszSourceUrlName, (LPCSTR)url_entry+url_entry->url_off, url_size);
1335c2c66affSColin Finck     }
1336c2c66affSColin Finck 
1337c2c66affSColin Finck     if(size%4 && size<*info_size)
1338c2c66affSColin Finck         ZeroMemory((LPBYTE)entry_info+size, 4-size%4);
1339c2c66affSColin Finck     size = DWORD_ALIGN(size);
1340c2c66affSColin Finck 
1341c2c66affSColin Finck     if(url_entry->local_name_off) {
1342c2c66affSColin Finck         LONG file_name_size;
1343c2c66affSColin Finck         LPSTR file_name;
1344c2c66affSColin Finck         file_name = (LPSTR)entry_info+size;
1345c2c66affSColin Finck         file_name_size = *info_size-size;
1346c2c66affSColin Finck         if((unicode && urlcache_create_file_pathW(container, header, (LPCSTR)url_entry+url_entry->local_name_off,
1347c2c66affSColin Finck                         url_entry->cache_dir, (LPWSTR)file_name, &file_name_size, FALSE)) ||
1348c2c66affSColin Finck             (!unicode && urlcache_create_file_pathA(container, header, (LPCSTR)url_entry+url_entry->local_name_off,
1349c2c66affSColin Finck                         url_entry->cache_dir, file_name, &file_name_size))) {
1350c2c66affSColin Finck             entry_info->lpszLocalFileName = file_name;
1351c2c66affSColin Finck         }
1352c2c66affSColin Finck         size += file_name_size;
1353c2c66affSColin Finck 
1354c2c66affSColin Finck         if(size%4 && size<*info_size)
1355c2c66affSColin Finck             ZeroMemory((LPBYTE)entry_info+size, 4-size%4);
1356c2c66affSColin Finck         size = DWORD_ALIGN(size);
1357c2c66affSColin Finck     }
1358c2c66affSColin Finck 
1359c2c66affSColin Finck     if(url_entry->header_info_off) {
1360c2c66affSColin Finck         DWORD header_len;
1361c2c66affSColin Finck 
1362c2c66affSColin Finck         if(unicode)
1363c2c66affSColin Finck             header_len = MultiByteToWideChar(CP_UTF8, 0, (const char*)url_entry+url_entry->header_info_off,
1364c2c66affSColin Finck                     url_entry->header_info_size, NULL, 0);
1365c2c66affSColin Finck         else
1366c2c66affSColin Finck             header_len = url_entry->header_info_size;
1367c2c66affSColin Finck         size += header_len * (unicode ? sizeof(WCHAR) : sizeof(CHAR));
1368c2c66affSColin Finck 
1369c2c66affSColin Finck         if(*info_size >= size) {
1370c2c66affSColin Finck             DWORD header_size = header_len * (unicode ? sizeof(WCHAR) : sizeof(CHAR));
1371c2c66affSColin Finck             entry_info->lpHeaderInfo = (LPBYTE)entry_info+size-header_size;
1372c2c66affSColin Finck             if(unicode)
1373c2c66affSColin Finck                 MultiByteToWideChar(CP_UTF8, 0, (const char*)url_entry+url_entry->header_info_off,
1374c2c66affSColin Finck                         url_entry->header_info_size, (LPWSTR)entry_info->lpHeaderInfo, header_len);
1375c2c66affSColin Finck             else
1376c2c66affSColin Finck                 memcpy(entry_info->lpHeaderInfo, (LPCSTR)url_entry+url_entry->header_info_off, header_len);
1377c2c66affSColin Finck         }
1378c2c66affSColin Finck         if(size%4 && size<*info_size)
1379c2c66affSColin Finck             ZeroMemory((LPBYTE)entry_info+size, 4-size%4);
1380c2c66affSColin Finck         size = DWORD_ALIGN(size);
1381c2c66affSColin Finck     }
1382c2c66affSColin Finck 
1383c2c66affSColin Finck     if(url_entry->file_extension_off) {
1384c2c66affSColin Finck         int ext_len;
1385c2c66affSColin Finck 
1386c2c66affSColin Finck         if(unicode)
1387c2c66affSColin Finck             ext_len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)url_entry+url_entry->file_extension_off, -1, NULL, 0);
1388c2c66affSColin Finck         else
1389c2c66affSColin Finck             ext_len = strlen((LPCSTR)url_entry+url_entry->file_extension_off) + 1;
1390c2c66affSColin Finck         size += ext_len * (unicode ? sizeof(WCHAR) : sizeof(CHAR));
1391c2c66affSColin Finck 
1392c2c66affSColin Finck         if(*info_size >= size) {
1393c2c66affSColin Finck             DWORD ext_size = ext_len * (unicode ? sizeof(WCHAR) : sizeof(CHAR));
1394c2c66affSColin Finck             entry_info->lpszFileExtension = (LPSTR)entry_info+size-ext_size;
1395c2c66affSColin Finck             if(unicode)
1396c2c66affSColin Finck                 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)url_entry+url_entry->file_extension_off, -1, (LPWSTR)entry_info->lpszFileExtension, ext_len);
1397c2c66affSColin Finck             else
1398c2c66affSColin Finck                 memcpy(entry_info->lpszFileExtension, (LPCSTR)url_entry+url_entry->file_extension_off, ext_len*sizeof(CHAR));
1399c2c66affSColin Finck         }
1400c2c66affSColin Finck 
1401c2c66affSColin Finck         if(size%4 && size<*info_size)
1402c2c66affSColin Finck             ZeroMemory((LPBYTE)entry_info+size, 4-size%4);
1403c2c66affSColin Finck         size = DWORD_ALIGN(size);
1404c2c66affSColin Finck     }
1405c2c66affSColin Finck 
1406c2c66affSColin Finck     if(size > *info_size) {
1407c2c66affSColin Finck         *info_size = size;
1408c2c66affSColin Finck         return ERROR_INSUFFICIENT_BUFFER;
1409c2c66affSColin Finck     }
1410c2c66affSColin Finck     *info_size = size;
1411c2c66affSColin Finck     return ERROR_SUCCESS;
1412c2c66affSColin Finck }
1413c2c66affSColin Finck 
1414c2c66affSColin Finck /***********************************************************************
1415c2c66affSColin Finck  *           urlcache_set_entry_info (Internal)
1416c2c66affSColin Finck  *
1417c2c66affSColin Finck  *  Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1418c2c66affSColin Finck  * according to the flags set by field_control.
1419c2c66affSColin Finck  *
1420c2c66affSColin Finck  * RETURNS
1421c2c66affSColin Finck  *    ERROR_SUCCESS if the buffer was big enough
1422c2c66affSColin Finck  *    ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1423c2c66affSColin Finck  *
1424c2c66affSColin Finck  */
urlcache_set_entry_info(entry_url * url_entry,const INTERNET_CACHE_ENTRY_INFOA * entry_info,DWORD field_control)1425c2c66affSColin Finck static DWORD urlcache_set_entry_info(entry_url *url_entry, const INTERNET_CACHE_ENTRY_INFOA *entry_info, DWORD field_control)
1426c2c66affSColin Finck {
1427c2c66affSColin Finck     if (field_control & CACHE_ENTRY_ACCTIME_FC)
1428c2c66affSColin Finck         url_entry->access_time = entry_info->LastAccessTime;
1429c2c66affSColin Finck     if (field_control & CACHE_ENTRY_ATTRIBUTE_FC)
1430c2c66affSColin Finck         url_entry->cache_entry_type = entry_info->CacheEntryType;
1431c2c66affSColin Finck     if (field_control & CACHE_ENTRY_EXEMPT_DELTA_FC)
1432c2c66affSColin Finck         url_entry->exempt_delta = entry_info->u.dwExemptDelta;
1433c2c66affSColin Finck     if (field_control & CACHE_ENTRY_EXPTIME_FC)
1434c2c66affSColin Finck         file_time_to_dos_date_time(&entry_info->ExpireTime, &url_entry->expire_date, &url_entry->expire_time);
1435c2c66affSColin Finck     if (field_control & CACHE_ENTRY_HEADERINFO_FC)
1436c2c66affSColin Finck         FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1437c2c66affSColin Finck     if (field_control & CACHE_ENTRY_HITRATE_FC)
1438c2c66affSColin Finck         url_entry->hit_rate = entry_info->dwHitRate;
1439c2c66affSColin Finck     if (field_control & CACHE_ENTRY_MODTIME_FC)
1440c2c66affSColin Finck         url_entry->modification_time = entry_info->LastModifiedTime;
1441c2c66affSColin Finck     if (field_control & CACHE_ENTRY_SYNCTIME_FC)
1442c2c66affSColin Finck         file_time_to_dos_date_time(&entry_info->LastAccessTime, &url_entry->sync_date, &url_entry->sync_time);
1443c2c66affSColin Finck 
1444c2c66affSColin Finck     return ERROR_SUCCESS;
1445c2c66affSColin Finck }
1446c2c66affSColin Finck 
1447c2c66affSColin Finck /***********************************************************************
1448c2c66affSColin Finck  *           urlcache_hash_key (Internal)
1449c2c66affSColin Finck  *
1450c2c66affSColin Finck  *  Returns the hash key for a given string
1451c2c66affSColin Finck  *
1452c2c66affSColin Finck  * RETURNS
1453c2c66affSColin Finck  *    hash key for the string
1454c2c66affSColin Finck  *
1455c2c66affSColin Finck  */
urlcache_hash_key(LPCSTR lpszKey)1456c2c66affSColin Finck static DWORD urlcache_hash_key(LPCSTR lpszKey)
1457c2c66affSColin Finck {
1458c2c66affSColin Finck     /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1459c2c66affSColin Finck      * but the algorithm and result are not the same!
1460c2c66affSColin Finck      */
1461c2c66affSColin Finck     static const unsigned char lookupTable[256] =
1462c2c66affSColin Finck     {
1463c2c66affSColin Finck         0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1464c2c66affSColin Finck         0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1465c2c66affSColin Finck         0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1466c2c66affSColin Finck         0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1467c2c66affSColin Finck         0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1468c2c66affSColin Finck         0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1469c2c66affSColin Finck         0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1470c2c66affSColin Finck         0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1471c2c66affSColin Finck         0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1472c2c66affSColin Finck         0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1473c2c66affSColin Finck         0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1474c2c66affSColin Finck         0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1475c2c66affSColin Finck         0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1476c2c66affSColin Finck         0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1477c2c66affSColin Finck         0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1478c2c66affSColin Finck         0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1479c2c66affSColin Finck         0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1480c2c66affSColin Finck         0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1481c2c66affSColin Finck         0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1482c2c66affSColin Finck         0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1483c2c66affSColin Finck         0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1484c2c66affSColin Finck         0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1485c2c66affSColin Finck         0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1486c2c66affSColin Finck         0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1487c2c66affSColin Finck         0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1488c2c66affSColin Finck         0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1489c2c66affSColin Finck         0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1490c2c66affSColin Finck         0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1491c2c66affSColin Finck         0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1492c2c66affSColin Finck         0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1493c2c66affSColin Finck         0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1494c2c66affSColin Finck         0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1495c2c66affSColin Finck     };
1496c2c66affSColin Finck     BYTE key[4];
1497c2c66affSColin Finck     DWORD i;
1498c2c66affSColin Finck 
1499c239cdd4SAmine Khaldi     for (i = 0; i < ARRAY_SIZE(key); i++)
1500c2c66affSColin Finck         key[i] = lookupTable[(*lpszKey + i) & 0xFF];
1501c2c66affSColin Finck 
1502c2c66affSColin Finck     for (lpszKey++; *lpszKey; lpszKey++)
1503c2c66affSColin Finck     {
1504c239cdd4SAmine Khaldi         for (i = 0; i < ARRAY_SIZE(key); i++)
1505c2c66affSColin Finck             key[i] = lookupTable[*lpszKey ^ key[i]];
1506c2c66affSColin Finck     }
1507c2c66affSColin Finck 
1508c2c66affSColin Finck     return *(DWORD *)key;
1509c2c66affSColin Finck }
1510c2c66affSColin Finck 
urlcache_get_hash_table(const urlcache_header * pHeader,DWORD dwOffset)1511c2c66affSColin Finck static inline entry_hash_table* urlcache_get_hash_table(const urlcache_header *pHeader, DWORD dwOffset)
1512c2c66affSColin Finck {
1513c2c66affSColin Finck     if(!dwOffset)
1514c2c66affSColin Finck         return NULL;
1515c2c66affSColin Finck     return (entry_hash_table*)((LPBYTE)pHeader + dwOffset);
1516c2c66affSColin Finck }
1517c2c66affSColin Finck 
urlcache_find_hash_entry(const urlcache_header * pHeader,LPCSTR lpszUrl,struct hash_entry ** ppHashEntry)1518c2c66affSColin Finck static BOOL urlcache_find_hash_entry(const urlcache_header *pHeader, LPCSTR lpszUrl, struct hash_entry **ppHashEntry)
1519c2c66affSColin Finck {
1520c2c66affSColin Finck     /* structure of hash table:
1521c2c66affSColin Finck      *  448 entries divided into 64 blocks
1522c2c66affSColin Finck      *  each block therefore contains a chain of 7 key/offset pairs
1523c2c66affSColin Finck      * how position in table is calculated:
1524c2c66affSColin Finck      *  1. the url is hashed in helper function
1525c2c66affSColin Finck      *  2. the key % HASHTABLE_NUM_ENTRIES is the bucket number
1526c2c66affSColin Finck      *  3. bucket number * HASHTABLE_BLOCKSIZE is offset of the bucket
1527c2c66affSColin Finck      *
1528c2c66affSColin Finck      * note:
1529c2c66affSColin Finck      *  there can be multiple hash tables in the file and the offset to
1530c2c66affSColin Finck      *  the next one is stored in the header of the hash table
1531c2c66affSColin Finck      */
1532c2c66affSColin Finck     DWORD key = urlcache_hash_key(lpszUrl);
1533c2c66affSColin Finck     DWORD offset = (key & (HASHTABLE_NUM_ENTRIES-1)) * HASHTABLE_BLOCKSIZE;
1534c2c66affSColin Finck     entry_hash_table* pHashEntry;
1535c2c66affSColin Finck     DWORD id = 0;
1536c2c66affSColin Finck 
1537c2c66affSColin Finck     key >>= HASHTABLE_FLAG_BITS;
1538c2c66affSColin Finck 
1539c2c66affSColin Finck     for (pHashEntry = urlcache_get_hash_table(pHeader, pHeader->hash_table_off);
1540c2c66affSColin Finck          pHashEntry; pHashEntry = urlcache_get_hash_table(pHeader, pHashEntry->next))
1541c2c66affSColin Finck     {
1542c2c66affSColin Finck         int i;
1543c2c66affSColin Finck         if (pHashEntry->id != id++)
1544c2c66affSColin Finck         {
1545c2c66affSColin Finck             ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->id, id);
1546c2c66affSColin Finck             continue;
1547c2c66affSColin Finck         }
1548c2c66affSColin Finck         /* make sure that it is in fact a hash entry */
1549c2c66affSColin Finck         if (pHashEntry->header.signature != HASH_SIGNATURE)
1550c2c66affSColin Finck         {
1551c2c66affSColin Finck             ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->header.signature);
1552c2c66affSColin Finck             continue;
1553c2c66affSColin Finck         }
1554c2c66affSColin Finck 
1555c2c66affSColin Finck         for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1556c2c66affSColin Finck         {
1557c2c66affSColin Finck             struct hash_entry *pHashElement = &pHashEntry->hash_table[offset + i];
1558c2c66affSColin Finck             if (key == pHashElement->key>>HASHTABLE_FLAG_BITS)
1559c2c66affSColin Finck             {
1560c2c66affSColin Finck                 /* FIXME: we should make sure that this is the right element
1561c2c66affSColin Finck                  * before returning and claiming that it is. We can do this
1562c2c66affSColin Finck                  * by doing a simple compare between the URL we were given
1563c2c66affSColin Finck                  * and the URL stored in the entry. However, this assumes
1564c2c66affSColin Finck                  * we know the format of all the entries stored in the
1565c2c66affSColin Finck                  * hash table */
1566c2c66affSColin Finck                 *ppHashEntry = pHashElement;
1567c2c66affSColin Finck                 return TRUE;
1568c2c66affSColin Finck             }
1569c2c66affSColin Finck         }
1570c2c66affSColin Finck     }
1571c2c66affSColin Finck     return FALSE;
1572c2c66affSColin Finck }
1573c2c66affSColin Finck 
1574c2c66affSColin Finck /***********************************************************************
1575c2c66affSColin Finck  *           urlcache_hash_entry_set_flags (Internal)
1576c2c66affSColin Finck  *
1577c2c66affSColin Finck  *  Sets special bits in hash key
1578c2c66affSColin Finck  *
1579c2c66affSColin Finck  * RETURNS
1580c2c66affSColin Finck  *    nothing
1581c2c66affSColin Finck  *
1582c2c66affSColin Finck  */
urlcache_hash_entry_set_flags(struct hash_entry * pHashEntry,DWORD dwFlag)1583c2c66affSColin Finck static void urlcache_hash_entry_set_flags(struct hash_entry *pHashEntry, DWORD dwFlag)
1584c2c66affSColin Finck {
1585c2c66affSColin Finck     pHashEntry->key = (pHashEntry->key >> HASHTABLE_FLAG_BITS << HASHTABLE_FLAG_BITS) | dwFlag;
1586c2c66affSColin Finck }
1587c2c66affSColin Finck 
1588c2c66affSColin Finck /***********************************************************************
1589c2c66affSColin Finck  *           urlcache_hash_entry_delete (Internal)
1590c2c66affSColin Finck  *
1591c2c66affSColin Finck  *  Searches all the hash tables in the index for the given URL and
1592c2c66affSColin Finck  * then if found deletes the entry.
1593c2c66affSColin Finck  *
1594c2c66affSColin Finck  * RETURNS
1595c2c66affSColin Finck  *    TRUE if the entry was found
1596c2c66affSColin Finck  *    FALSE if the entry could not be found
1597c2c66affSColin Finck  *
1598c2c66affSColin Finck  */
urlcache_hash_entry_delete(struct hash_entry * pHashEntry)1599c2c66affSColin Finck static BOOL urlcache_hash_entry_delete(struct hash_entry *pHashEntry)
1600c2c66affSColin Finck {
1601c2c66affSColin Finck     pHashEntry->key = HASHTABLE_DEL;
1602c2c66affSColin Finck     return TRUE;
1603c2c66affSColin Finck }
1604c2c66affSColin Finck 
1605c2c66affSColin Finck /***********************************************************************
1606c2c66affSColin Finck  *           urlcache_hash_entry_create (Internal)
1607c2c66affSColin Finck  *
1608c2c66affSColin Finck  *  Searches all the hash tables for a free slot based on the offset
1609c2c66affSColin Finck  * generated from the hash key. If a free slot is found, the offset and
1610c2c66affSColin Finck  * key are entered into the hash table.
1611c2c66affSColin Finck  *
1612c2c66affSColin Finck  * RETURNS
1613c2c66affSColin Finck  *    ERROR_SUCCESS if the entry was added
1614c2c66affSColin Finck  *    Any other Win32 error code if the entry could not be added
1615c2c66affSColin Finck  *
1616c2c66affSColin Finck  */
urlcache_hash_entry_create(urlcache_header * pHeader,LPCSTR lpszUrl,DWORD dwOffsetEntry,DWORD dwFieldType)1617c2c66affSColin Finck static DWORD urlcache_hash_entry_create(urlcache_header *pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry, DWORD dwFieldType)
1618c2c66affSColin Finck {
1619c2c66affSColin Finck     /* see urlcache_find_hash_entry for structure of hash tables */
1620c2c66affSColin Finck 
1621c2c66affSColin Finck     DWORD key = urlcache_hash_key(lpszUrl);
1622c2c66affSColin Finck     DWORD offset = (key & (HASHTABLE_NUM_ENTRIES-1)) * HASHTABLE_BLOCKSIZE;
1623c2c66affSColin Finck     entry_hash_table* pHashEntry, *pHashPrev = NULL;
1624c2c66affSColin Finck     DWORD id = 0;
1625c2c66affSColin Finck     DWORD error;
1626c2c66affSColin Finck 
1627c2c66affSColin Finck     key = ((key >> HASHTABLE_FLAG_BITS) << HASHTABLE_FLAG_BITS) + dwFieldType;
1628c2c66affSColin Finck 
1629c2c66affSColin Finck     for (pHashEntry = urlcache_get_hash_table(pHeader, pHeader->hash_table_off);
1630c2c66affSColin Finck          pHashEntry; pHashEntry = urlcache_get_hash_table(pHeader, pHashEntry->next))
1631c2c66affSColin Finck     {
1632c2c66affSColin Finck         int i;
1633c2c66affSColin Finck         pHashPrev = pHashEntry;
1634c2c66affSColin Finck 
1635c2c66affSColin Finck         if (pHashEntry->id != id++)
1636c2c66affSColin Finck         {
1637c2c66affSColin Finck             ERR("not right hash table number (%d) expected %d\n", pHashEntry->id, id);
1638c2c66affSColin Finck             break;
1639c2c66affSColin Finck         }
1640c2c66affSColin Finck         /* make sure that it is in fact a hash entry */
1641c2c66affSColin Finck         if (pHashEntry->header.signature != HASH_SIGNATURE)
1642c2c66affSColin Finck         {
1643c2c66affSColin Finck             ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->header.signature);
1644c2c66affSColin Finck             break;
1645c2c66affSColin Finck         }
1646c2c66affSColin Finck 
1647c2c66affSColin Finck         for (i = 0; i < HASHTABLE_BLOCKSIZE; i++)
1648c2c66affSColin Finck         {
1649c2c66affSColin Finck             struct hash_entry *pHashElement = &pHashEntry->hash_table[offset + i];
1650c2c66affSColin Finck             if (pHashElement->key==HASHTABLE_FREE || pHashElement->key==HASHTABLE_DEL) /* if the slot is free */
1651c2c66affSColin Finck             {
1652c2c66affSColin Finck                 pHashElement->key = key;
1653c2c66affSColin Finck                 pHashElement->offset = dwOffsetEntry;
1654c2c66affSColin Finck                 return ERROR_SUCCESS;
1655c2c66affSColin Finck             }
1656c2c66affSColin Finck         }
1657c2c66affSColin Finck     }
1658c2c66affSColin Finck     error = urlcache_create_hash_table(pHeader, pHashPrev, &pHashEntry);
1659c2c66affSColin Finck     if (error != ERROR_SUCCESS)
1660c2c66affSColin Finck         return error;
1661c2c66affSColin Finck 
1662c2c66affSColin Finck     pHashEntry->hash_table[offset].key = key;
1663c2c66affSColin Finck     pHashEntry->hash_table[offset].offset = dwOffsetEntry;
1664c2c66affSColin Finck     return ERROR_SUCCESS;
1665c2c66affSColin Finck }
1666c2c66affSColin Finck 
1667c2c66affSColin Finck /***********************************************************************
1668c2c66affSColin Finck  *           urlcache_enum_hash_tables (Internal)
1669c2c66affSColin Finck  *
1670c2c66affSColin Finck  *  Enumerates the hash tables in a container.
1671c2c66affSColin Finck  *
1672c2c66affSColin Finck  * RETURNS
1673c2c66affSColin Finck  *    TRUE if an entry was found
1674c2c66affSColin Finck  *    FALSE if there are no more tables to enumerate.
1675c2c66affSColin Finck  *
1676c2c66affSColin Finck  */
urlcache_enum_hash_tables(const urlcache_header * pHeader,DWORD * id,entry_hash_table ** ppHashEntry)1677c2c66affSColin Finck static BOOL urlcache_enum_hash_tables(const urlcache_header *pHeader, DWORD *id, entry_hash_table **ppHashEntry)
1678c2c66affSColin Finck {
1679c2c66affSColin Finck     for (*ppHashEntry = urlcache_get_hash_table(pHeader, pHeader->hash_table_off);
1680c2c66affSColin Finck          *ppHashEntry; *ppHashEntry = urlcache_get_hash_table(pHeader, (*ppHashEntry)->next))
1681c2c66affSColin Finck     {
1682c2c66affSColin Finck         TRACE("looking at hash table number %d\n", (*ppHashEntry)->id);
1683c2c66affSColin Finck         if ((*ppHashEntry)->id != *id)
1684c2c66affSColin Finck             continue;
1685c2c66affSColin Finck         /* make sure that it is in fact a hash entry */
1686c2c66affSColin Finck         if ((*ppHashEntry)->header.signature != HASH_SIGNATURE)
1687c2c66affSColin Finck         {
1688c2c66affSColin Finck             ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&(*ppHashEntry)->header.signature);
1689c2c66affSColin Finck             (*id)++;
1690c2c66affSColin Finck             continue;
1691c2c66affSColin Finck         }
1692c2c66affSColin Finck 
1693c2c66affSColin Finck         TRACE("hash table number %d found\n", *id);
1694c2c66affSColin Finck         return TRUE;
1695c2c66affSColin Finck     }
1696c2c66affSColin Finck     return FALSE;
1697c2c66affSColin Finck }
1698c2c66affSColin Finck 
1699c2c66affSColin Finck /***********************************************************************
1700c2c66affSColin Finck  *           urlcache_enum_hash_table_entries (Internal)
1701c2c66affSColin Finck  *
1702c2c66affSColin Finck  *  Enumerates entries in a hash table and returns the next non-free entry.
1703c2c66affSColin Finck  *
1704c2c66affSColin Finck  * RETURNS
1705c2c66affSColin Finck  *    TRUE if an entry was found
1706c2c66affSColin Finck  *    FALSE if the hash table is empty or there are no more entries to
1707c2c66affSColin Finck  *     enumerate.
1708c2c66affSColin Finck  *
1709c2c66affSColin Finck  */
urlcache_enum_hash_table_entries(const urlcache_header * pHeader,const entry_hash_table * pHashEntry,DWORD * index,const struct hash_entry ** ppHashEntry)1710c2c66affSColin Finck static BOOL urlcache_enum_hash_table_entries(const urlcache_header *pHeader, const entry_hash_table *pHashEntry,
1711c2c66affSColin Finck                                           DWORD * index, const struct hash_entry **ppHashEntry)
1712c2c66affSColin Finck {
1713c2c66affSColin Finck     for (; *index < HASHTABLE_SIZE ; (*index)++)
1714c2c66affSColin Finck     {
1715c2c66affSColin Finck         if (pHashEntry->hash_table[*index].key==HASHTABLE_FREE || pHashEntry->hash_table[*index].key==HASHTABLE_DEL)
1716c2c66affSColin Finck             continue;
1717c2c66affSColin Finck 
1718c2c66affSColin Finck         *ppHashEntry = &pHashEntry->hash_table[*index];
1719c2c66affSColin Finck         TRACE("entry found %d\n", *index);
1720c2c66affSColin Finck         return TRUE;
1721c2c66affSColin Finck     }
1722c2c66affSColin Finck     TRACE("no more entries (%d)\n", *index);
1723c2c66affSColin Finck     return FALSE;
1724c2c66affSColin Finck }
1725c2c66affSColin Finck 
1726c2c66affSColin Finck /***********************************************************************
1727c2c66affSColin Finck  *           cache_container_delete_dir (Internal)
1728c2c66affSColin Finck  *
1729c2c66affSColin Finck  *  Erase a directory containing an URL cache.
1730c2c66affSColin Finck  *
1731c2c66affSColin Finck  * RETURNS
1732c2c66affSColin Finck  *    TRUE success, FALSE failure/aborted.
1733c2c66affSColin Finck  *
1734c2c66affSColin Finck  */
cache_container_delete_dir(LPCWSTR lpszPath)1735c2c66affSColin Finck static BOOL cache_container_delete_dir(LPCWSTR lpszPath)
1736c2c66affSColin Finck {
1737c2c66affSColin Finck     DWORD path_len;
1738c2c66affSColin Finck     WCHAR path[MAX_PATH + 1];
1739c2c66affSColin Finck     SHFILEOPSTRUCTW shfos;
1740c2c66affSColin Finck     int ret;
1741c2c66affSColin Finck 
17425f12c8d7Swinesync     path_len = lstrlenW(lpszPath);
1743c2c66affSColin Finck     if (path_len >= MAX_PATH)
1744c2c66affSColin Finck         return FALSE;
17455f12c8d7Swinesync     lstrcpyW(path, lpszPath);
1746c2c66affSColin Finck     path[path_len + 1] = 0;  /* double-NUL-terminate path */
1747c2c66affSColin Finck 
1748c2c66affSColin Finck     shfos.hwnd = NULL;
1749c2c66affSColin Finck     shfos.wFunc = FO_DELETE;
1750c2c66affSColin Finck     shfos.pFrom = path;
1751c2c66affSColin Finck     shfos.pTo = NULL;
1752c2c66affSColin Finck     shfos.fFlags = FOF_NOCONFIRMATION;
1753c2c66affSColin Finck     shfos.fAnyOperationsAborted = FALSE;
1754c2c66affSColin Finck     ret = SHFileOperationW(&shfos);
1755c2c66affSColin Finck     if (ret)
1756c2c66affSColin Finck         ERR("SHFileOperationW on %s returned %i\n", debugstr_w(path), ret);
1757c2c66affSColin Finck     return !(ret || shfos.fAnyOperationsAborted);
1758c2c66affSColin Finck }
1759c2c66affSColin Finck 
1760c2c66affSColin Finck /***********************************************************************
1761c2c66affSColin Finck  *           urlcache_hash_entry_is_locked (Internal)
1762c2c66affSColin Finck  *
1763c2c66affSColin Finck  *  Checks if entry is locked. Unlocks it if possible.
1764c2c66affSColin Finck  */
urlcache_hash_entry_is_locked(struct hash_entry * hash_entry,entry_url * url_entry)1765c2c66affSColin Finck static BOOL urlcache_hash_entry_is_locked(struct hash_entry *hash_entry, entry_url *url_entry)
1766c2c66affSColin Finck {
1767c2c66affSColin Finck     FILETIME cur_time;
1768c2c66affSColin Finck     ULARGE_INTEGER acc_time, time;
1769c2c66affSColin Finck 
1770c2c66affSColin Finck     if ((hash_entry->key & ((1<<HASHTABLE_FLAG_BITS)-1)) != HASHTABLE_LOCK)
1771c2c66affSColin Finck         return FALSE;
1772c2c66affSColin Finck 
1773c2c66affSColin Finck     GetSystemTimeAsFileTime(&cur_time);
1774c2c66affSColin Finck     time.u.LowPart = cur_time.dwLowDateTime;
1775c2c66affSColin Finck     time.u.HighPart = cur_time.dwHighDateTime;
1776c2c66affSColin Finck 
1777c2c66affSColin Finck     acc_time.u.LowPart = url_entry->access_time.dwLowDateTime;
1778c2c66affSColin Finck     acc_time.u.HighPart = url_entry->access_time.dwHighDateTime;
1779c2c66affSColin Finck 
1780c2c66affSColin Finck     time.QuadPart -= acc_time.QuadPart;
1781c2c66affSColin Finck 
1782c2c66affSColin Finck     /* check if entry was locked for at least a day */
1783c2c66affSColin Finck     if(time.QuadPart > (ULONGLONG)24*60*60*FILETIME_SECOND) {
1784c2c66affSColin Finck         urlcache_hash_entry_set_flags(hash_entry, HASHTABLE_URL);
1785c2c66affSColin Finck         url_entry->use_count = 0;
1786c2c66affSColin Finck         return FALSE;
1787c2c66affSColin Finck     }
1788c2c66affSColin Finck 
1789c2c66affSColin Finck     return TRUE;
1790c2c66affSColin Finck }
1791c2c66affSColin Finck 
urlcache_get_entry_info(const char * url,void * entry_info,DWORD * size,DWORD flags,BOOL unicode)1792c2c66affSColin Finck static BOOL urlcache_get_entry_info(const char *url, void *entry_info,
1793c2c66affSColin Finck         DWORD *size, DWORD flags, BOOL unicode)
1794c2c66affSColin Finck {
1795c2c66affSColin Finck     urlcache_header *header;
1796c2c66affSColin Finck     struct hash_entry *hash_entry;
1797c2c66affSColin Finck     const entry_url *url_entry;
1798c2c66affSColin Finck     cache_container *container;
1799c2c66affSColin Finck     DWORD error;
1800c2c66affSColin Finck 
1801c2c66affSColin Finck     TRACE("(%s, %p, %p, %x, %x)\n", debugstr_a(url), entry_info, size, flags, unicode);
1802c2c66affSColin Finck 
1803c2c66affSColin Finck     if(flags & ~GET_INSTALLED_ENTRY)
1804c2c66affSColin Finck         FIXME("ignoring unsupported flags: %x\n", flags);
1805c2c66affSColin Finck 
1806c2c66affSColin Finck     error = cache_containers_find(url, &container);
1807c2c66affSColin Finck     if(error != ERROR_SUCCESS) {
1808c2c66affSColin Finck         SetLastError(error);
1809c2c66affSColin Finck         return FALSE;
1810c2c66affSColin Finck     }
1811c2c66affSColin Finck 
1812c2c66affSColin Finck     error = cache_container_open_index(container, MIN_BLOCK_NO);
1813c2c66affSColin Finck     if(error != ERROR_SUCCESS) {
1814c2c66affSColin Finck         SetLastError(error);
1815c2c66affSColin Finck         return FALSE;
1816c2c66affSColin Finck     }
1817c2c66affSColin Finck 
1818c2c66affSColin Finck     if(!(header = cache_container_lock_index(container)))
1819c2c66affSColin Finck         return FALSE;
1820c2c66affSColin Finck 
1821c2c66affSColin Finck     if(!urlcache_find_hash_entry(header, url, &hash_entry)) {
1822c2c66affSColin Finck         cache_container_unlock_index(container, header);
1823c2c66affSColin Finck         WARN("entry %s not found!\n", debugstr_a(url));
1824c2c66affSColin Finck         SetLastError(ERROR_FILE_NOT_FOUND);
1825c2c66affSColin Finck         return FALSE;
1826c2c66affSColin Finck     }
1827c2c66affSColin Finck 
1828c2c66affSColin Finck     url_entry = (const entry_url*)((LPBYTE)header + hash_entry->offset);
1829c2c66affSColin Finck     if(url_entry->header.signature != URL_SIGNATURE) {
1830c2c66affSColin Finck         FIXME("Trying to retrieve entry of unknown format %s\n",
1831c2c66affSColin Finck                 debugstr_an((LPCSTR)&url_entry->header.signature, sizeof(DWORD)));
1832ef9a828eSwinesync         cache_container_unlock_index(container, header);
1833c2c66affSColin Finck         SetLastError(ERROR_FILE_NOT_FOUND);
1834c2c66affSColin Finck         return FALSE;
1835c2c66affSColin Finck     }
1836c2c66affSColin Finck 
1837c2c66affSColin Finck     TRACE("Found URL: %s\n", debugstr_a((LPCSTR)url_entry + url_entry->url_off));
1838c2c66affSColin Finck     TRACE("Header info: %s\n", debugstr_an((LPCSTR)url_entry +
1839c2c66affSColin Finck                 url_entry->header_info_off, url_entry->header_info_size));
1840c2c66affSColin Finck 
1841c2c66affSColin Finck     if((flags & GET_INSTALLED_ENTRY) && !(url_entry->cache_entry_type & INSTALLED_CACHE_ENTRY)) {
1842c2c66affSColin Finck         cache_container_unlock_index(container, header);
1843c2c66affSColin Finck         SetLastError(ERROR_FILE_NOT_FOUND);
1844c2c66affSColin Finck         return FALSE;
1845c2c66affSColin Finck     }
1846c2c66affSColin Finck 
1847c2c66affSColin Finck     if(size) {
1848c2c66affSColin Finck         if(!entry_info)
1849c2c66affSColin Finck             *size = 0;
1850c2c66affSColin Finck 
1851c2c66affSColin Finck         error = urlcache_copy_entry(container, header, entry_info, size, url_entry, unicode);
1852c2c66affSColin Finck         if(error != ERROR_SUCCESS) {
1853c2c66affSColin Finck             cache_container_unlock_index(container, header);
1854c2c66affSColin Finck             SetLastError(error);
1855c2c66affSColin Finck             return FALSE;
1856c2c66affSColin Finck         }
1857c2c66affSColin Finck         if(url_entry->local_name_off)
1858c2c66affSColin Finck             TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)url_entry + url_entry->local_name_off));
1859c2c66affSColin Finck     }
1860c2c66affSColin Finck 
1861c2c66affSColin Finck     cache_container_unlock_index(container, header);
1862c2c66affSColin Finck     return TRUE;
1863c2c66affSColin Finck }
1864c2c66affSColin Finck 
1865c2c66affSColin Finck /***********************************************************************
1866c2c66affSColin Finck  *           GetUrlCacheEntryInfoExA (WININET.@)
1867c2c66affSColin Finck  *
1868c2c66affSColin Finck  */
GetUrlCacheEntryInfoExA(LPCSTR lpszUrl,LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,LPDWORD lpdwCacheEntryInfoBufSize,LPSTR lpszReserved,LPDWORD lpdwReserved,LPVOID lpReserved,DWORD dwFlags)1869c2c66affSColin Finck BOOL WINAPI GetUrlCacheEntryInfoExA(LPCSTR lpszUrl,
1870c2c66affSColin Finck         LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1871c2c66affSColin Finck         LPDWORD lpdwCacheEntryInfoBufSize, LPSTR lpszReserved,
1872c2c66affSColin Finck         LPDWORD lpdwReserved, LPVOID lpReserved, DWORD dwFlags)
1873c2c66affSColin Finck {
1874c2c66affSColin Finck     if(lpszReserved!=NULL || lpdwReserved!=NULL || lpReserved!=NULL) {
1875c2c66affSColin Finck         ERR("Reserved value was not 0\n");
1876c2c66affSColin Finck         SetLastError(ERROR_INVALID_PARAMETER);
1877c2c66affSColin Finck         return FALSE;
1878c2c66affSColin Finck     }
1879c2c66affSColin Finck 
1880c2c66affSColin Finck     return urlcache_get_entry_info(lpszUrl, lpCacheEntryInfo,
1881c2c66affSColin Finck             lpdwCacheEntryInfoBufSize, dwFlags, FALSE);
1882c2c66affSColin Finck }
1883c2c66affSColin Finck 
1884c2c66affSColin Finck /***********************************************************************
1885c2c66affSColin Finck  *           GetUrlCacheEntryInfoA (WININET.@)
1886c2c66affSColin Finck  *
1887c2c66affSColin Finck  */
GetUrlCacheEntryInfoA(LPCSTR lpszUrlName,LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,LPDWORD lpdwCacheEntryInfoBufferSize)1888c2c66affSColin Finck BOOL WINAPI GetUrlCacheEntryInfoA(LPCSTR lpszUrlName,
1889c2c66affSColin Finck     LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
1890c2c66affSColin Finck     LPDWORD lpdwCacheEntryInfoBufferSize)
1891c2c66affSColin Finck {
1892c2c66affSColin Finck     return GetUrlCacheEntryInfoExA(lpszUrlName, lpCacheEntryInfo,
1893c2c66affSColin Finck             lpdwCacheEntryInfoBufferSize, NULL, NULL, NULL, 0);
1894c2c66affSColin Finck }
1895c2c66affSColin Finck 
urlcache_encode_url(const WCHAR * url,char * encoded_url,int encoded_len)1896c2c66affSColin Finck static int urlcache_encode_url(const WCHAR *url, char *encoded_url, int encoded_len)
1897c2c66affSColin Finck {
1898c2c66affSColin Finck     URL_COMPONENTSW uc;
1899c2c66affSColin Finck     DWORD len, part_len;
1900c2c66affSColin Finck     WCHAR *punycode;
1901c2c66affSColin Finck 
1902c2c66affSColin Finck     TRACE("%s\n", debugstr_w(url));
1903c2c66affSColin Finck 
1904c2c66affSColin Finck     memset(&uc, 0, sizeof(uc));
1905c2c66affSColin Finck     uc.dwStructSize = sizeof(uc);
1906c2c66affSColin Finck     uc.dwHostNameLength = 1;
1907c2c66affSColin Finck     if(!InternetCrackUrlW(url, 0, 0, &uc))
1908c2c66affSColin Finck         uc.nScheme = INTERNET_SCHEME_UNKNOWN;
1909c2c66affSColin Finck 
1910c2c66affSColin Finck     if(uc.nScheme!=INTERNET_SCHEME_HTTP && uc.nScheme!=INTERNET_SCHEME_HTTPS)
1911c2c66affSColin Finck         return WideCharToMultiByte(CP_UTF8, 0, url, -1, encoded_url, encoded_len, NULL, NULL);
1912c2c66affSColin Finck 
1913c2c66affSColin Finck     len = WideCharToMultiByte(CP_UTF8, 0, url, uc.lpszHostName-url,
1914c2c66affSColin Finck             encoded_url, encoded_len, NULL, NULL);
1915c2c66affSColin Finck     if(!len)
1916c2c66affSColin Finck         return 0;
1917c2c66affSColin Finck     if(encoded_url)
1918c2c66affSColin Finck         encoded_len -= len;
1919c2c66affSColin Finck 
1920c2c66affSColin Finck     part_len = IdnToAscii(0, uc.lpszHostName, uc.dwHostNameLength, NULL, 0);
1921c2c66affSColin Finck     if(!part_len) {
1922c2c66affSColin Finck         SetLastError(ERROR_INTERNET_INVALID_URL);
1923c2c66affSColin Finck         return 0;
1924c2c66affSColin Finck     }
1925c2c66affSColin Finck 
1926c2c66affSColin Finck     punycode = heap_alloc(part_len*sizeof(WCHAR));
1927c2c66affSColin Finck     if(!punycode)
1928c2c66affSColin Finck         return 0;
1929c2c66affSColin Finck 
1930c2c66affSColin Finck     part_len = IdnToAscii(0, uc.lpszHostName, uc.dwHostNameLength, punycode, part_len);
1931c2c66affSColin Finck     if(!part_len) {
1932c2c66affSColin Finck         heap_free(punycode);
1933c2c66affSColin Finck         return 0;
1934c2c66affSColin Finck     }
1935c2c66affSColin Finck 
1936c2c66affSColin Finck     part_len = WideCharToMultiByte(CP_UTF8, 0, punycode, part_len,
1937c2c66affSColin Finck             encoded_url ? encoded_url+len : NULL, encoded_len, NULL, NULL);
1938c2c66affSColin Finck     heap_free(punycode);
1939c2c66affSColin Finck     if(!part_len)
1940c2c66affSColin Finck         return 0;
1941c2c66affSColin Finck     if(encoded_url)
1942c2c66affSColin Finck         encoded_len -= part_len;
1943c2c66affSColin Finck     len += part_len;
1944c2c66affSColin Finck 
1945c2c66affSColin Finck     part_len = WideCharToMultiByte(CP_UTF8, 0, uc.lpszHostName+uc.dwHostNameLength,
1946c2c66affSColin Finck             -1, encoded_url ? encoded_url+len : NULL, encoded_len, NULL, NULL);
1947c2c66affSColin Finck     if(!part_len)
1948c2c66affSColin Finck         return 0;
1949c2c66affSColin Finck     len += part_len;
1950c2c66affSColin Finck 
1951c2c66affSColin Finck     TRACE("got (%d)%s\n", len, debugstr_a(encoded_url));
1952c2c66affSColin Finck     return len;
1953c2c66affSColin Finck }
1954c2c66affSColin Finck 
urlcache_encode_url_alloc(const WCHAR * url,char ** encoded_url)1955c2c66affSColin Finck static BOOL urlcache_encode_url_alloc(const WCHAR *url, char **encoded_url)
1956c2c66affSColin Finck {
1957c2c66affSColin Finck     DWORD encoded_len;
1958c2c66affSColin Finck     char *ret;
1959c2c66affSColin Finck 
1960c2c66affSColin Finck     encoded_len = urlcache_encode_url(url, NULL, 0);
1961c2c66affSColin Finck     if(!encoded_len)
1962c2c66affSColin Finck         return FALSE;
1963c2c66affSColin Finck 
1964c2c66affSColin Finck     ret = heap_alloc(encoded_len*sizeof(WCHAR));
1965c2c66affSColin Finck     if(!ret)
1966c2c66affSColin Finck         return FALSE;
1967c2c66affSColin Finck 
1968c2c66affSColin Finck     encoded_len = urlcache_encode_url(url, ret, encoded_len);
1969c2c66affSColin Finck     if(!encoded_len) {
1970c2c66affSColin Finck         heap_free(ret);
1971c2c66affSColin Finck         return FALSE;
1972c2c66affSColin Finck     }
1973c2c66affSColin Finck 
1974c2c66affSColin Finck     *encoded_url = ret;
1975c2c66affSColin Finck     return TRUE;
1976c2c66affSColin Finck }
1977c2c66affSColin Finck 
1978c2c66affSColin Finck /***********************************************************************
1979c2c66affSColin Finck  *           GetUrlCacheEntryInfoExW (WININET.@)
1980c2c66affSColin Finck  *
1981c2c66affSColin Finck  */
GetUrlCacheEntryInfoExW(LPCWSTR lpszUrl,LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,LPDWORD lpdwCacheEntryInfoBufSize,LPWSTR lpszReserved,LPDWORD lpdwReserved,LPVOID lpReserved,DWORD dwFlags)1982c2c66affSColin Finck BOOL WINAPI GetUrlCacheEntryInfoExW(LPCWSTR lpszUrl,
1983c2c66affSColin Finck         LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
1984c2c66affSColin Finck         LPDWORD lpdwCacheEntryInfoBufSize, LPWSTR lpszReserved,
1985c2c66affSColin Finck         LPDWORD lpdwReserved, LPVOID lpReserved, DWORD dwFlags)
1986c2c66affSColin Finck {
1987c2c66affSColin Finck     char *url;
1988c2c66affSColin Finck     BOOL ret;
1989c2c66affSColin Finck 
1990c2c66affSColin Finck     if(lpszReserved!=NULL || lpdwReserved!=NULL || lpReserved!=NULL) {
1991c2c66affSColin Finck         ERR("Reserved value was not 0\n");
1992c2c66affSColin Finck         SetLastError(ERROR_INVALID_PARAMETER);
1993c2c66affSColin Finck         return FALSE;
1994c2c66affSColin Finck     }
1995c2c66affSColin Finck 
1996c2c66affSColin Finck     /* Ignore GET_INSTALLED_ENTRY flag in unicode version of function */
1997c2c66affSColin Finck     dwFlags &= ~GET_INSTALLED_ENTRY;
1998c2c66affSColin Finck 
1999c2c66affSColin Finck     if(!urlcache_encode_url_alloc(lpszUrl, &url))
2000c2c66affSColin Finck         return FALSE;
2001c2c66affSColin Finck 
2002c2c66affSColin Finck     ret = urlcache_get_entry_info(url, lpCacheEntryInfo,
2003c2c66affSColin Finck             lpdwCacheEntryInfoBufSize, dwFlags, TRUE);
2004c2c66affSColin Finck     heap_free(url);
2005c2c66affSColin Finck     return ret;
2006c2c66affSColin Finck }
2007c2c66affSColin Finck 
2008c2c66affSColin Finck /***********************************************************************
2009c2c66affSColin Finck  *           GetUrlCacheEntryInfoW (WININET.@)
2010c2c66affSColin Finck  *
2011c2c66affSColin Finck  */
GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,LPDWORD lpdwCacheEntryInfoBufferSize)2012c2c66affSColin Finck BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
2013c2c66affSColin Finck         LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2014c2c66affSColin Finck         LPDWORD lpdwCacheEntryInfoBufferSize)
2015c2c66affSColin Finck {
2016c2c66affSColin Finck     return GetUrlCacheEntryInfoExW(lpszUrl, lpCacheEntryInfo,
2017c2c66affSColin Finck             lpdwCacheEntryInfoBufferSize, NULL, NULL, NULL, 0);
2018c2c66affSColin Finck }
2019c2c66affSColin Finck 
2020c2c66affSColin Finck /***********************************************************************
2021c2c66affSColin Finck  *           SetUrlCacheEntryInfoA (WININET.@)
2022c2c66affSColin Finck  */
SetUrlCacheEntryInfoA(LPCSTR lpszUrlName,LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,DWORD dwFieldControl)2023c2c66affSColin Finck BOOL WINAPI SetUrlCacheEntryInfoA(LPCSTR lpszUrlName,
2024c2c66affSColin Finck         LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2025c2c66affSColin Finck         DWORD dwFieldControl)
2026c2c66affSColin Finck {
2027c2c66affSColin Finck     urlcache_header *pHeader;
2028c2c66affSColin Finck     struct hash_entry *pHashEntry;
2029c2c66affSColin Finck     entry_header *pEntry;
2030c2c66affSColin Finck     cache_container *pContainer;
2031c2c66affSColin Finck     DWORD error;
2032c2c66affSColin Finck 
2033c2c66affSColin Finck     TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
2034c2c66affSColin Finck 
2035c2c66affSColin Finck     error = cache_containers_find(lpszUrlName, &pContainer);
2036c2c66affSColin Finck     if (error != ERROR_SUCCESS)
2037c2c66affSColin Finck     {
2038c2c66affSColin Finck         SetLastError(error);
2039c2c66affSColin Finck         return FALSE;
2040c2c66affSColin Finck     }
2041c2c66affSColin Finck 
2042c2c66affSColin Finck     error = cache_container_open_index(pContainer, MIN_BLOCK_NO);
2043c2c66affSColin Finck     if (error != ERROR_SUCCESS)
2044c2c66affSColin Finck     {
2045c2c66affSColin Finck         SetLastError(error);
2046c2c66affSColin Finck         return FALSE;
2047c2c66affSColin Finck     }
2048c2c66affSColin Finck 
2049c2c66affSColin Finck     if (!(pHeader = cache_container_lock_index(pContainer)))
2050c2c66affSColin Finck         return FALSE;
2051c2c66affSColin Finck 
2052c2c66affSColin Finck     if (!urlcache_find_hash_entry(pHeader, lpszUrlName, &pHashEntry))
2053c2c66affSColin Finck     {
2054c2c66affSColin Finck         cache_container_unlock_index(pContainer, pHeader);
2055c2c66affSColin Finck         WARN("entry %s not found!\n", debugstr_a(lpszUrlName));
2056c2c66affSColin Finck         SetLastError(ERROR_FILE_NOT_FOUND);
2057c2c66affSColin Finck         return FALSE;
2058c2c66affSColin Finck     }
2059c2c66affSColin Finck 
2060c2c66affSColin Finck     pEntry = (entry_header*)((LPBYTE)pHeader + pHashEntry->offset);
2061c2c66affSColin Finck     if (pEntry->signature != URL_SIGNATURE)
2062c2c66affSColin Finck     {
2063c2c66affSColin Finck         FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->signature, sizeof(DWORD)));
2064ef9a828eSwinesync         cache_container_unlock_index(pContainer, pHeader);
2065c2c66affSColin Finck         SetLastError(ERROR_FILE_NOT_FOUND);
2066c2c66affSColin Finck         return FALSE;
2067c2c66affSColin Finck     }
2068c2c66affSColin Finck 
2069c2c66affSColin Finck     urlcache_set_entry_info((entry_url*)pEntry, lpCacheEntryInfo, dwFieldControl);
2070c2c66affSColin Finck 
2071c2c66affSColin Finck     cache_container_unlock_index(pContainer, pHeader);
2072c2c66affSColin Finck 
2073c2c66affSColin Finck     return TRUE;
2074c2c66affSColin Finck }
2075c2c66affSColin Finck 
2076c2c66affSColin Finck /***********************************************************************
2077c2c66affSColin Finck  *           SetUrlCacheEntryInfoW (WININET.@)
2078c2c66affSColin Finck  */
SetUrlCacheEntryInfoW(LPCWSTR lpszUrl,LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,DWORD dwFieldControl)2079c2c66affSColin Finck BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl,
2080c2c66affSColin Finck         LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2081c2c66affSColin Finck         DWORD dwFieldControl)
2082c2c66affSColin Finck {
2083c2c66affSColin Finck     char *url;
2084c2c66affSColin Finck     BOOL ret;
2085c2c66affSColin Finck 
2086c2c66affSColin Finck     if(!urlcache_encode_url_alloc(lpszUrl, &url))
2087c2c66affSColin Finck         return FALSE;
2088c2c66affSColin Finck 
2089c2c66affSColin Finck     ret = SetUrlCacheEntryInfoA(url, (INTERNET_CACHE_ENTRY_INFOA*)lpCacheEntryInfo, dwFieldControl);
2090c2c66affSColin Finck     heap_free(url);
2091c2c66affSColin Finck     return ret;
2092c2c66affSColin Finck }
2093c2c66affSColin Finck 
urlcache_entry_get_file(const char * url,void * entry_info,DWORD * size,BOOL unicode)2094c2c66affSColin Finck static BOOL urlcache_entry_get_file(const char *url, void *entry_info, DWORD *size, BOOL unicode)
2095c2c66affSColin Finck {
2096c2c66affSColin Finck     urlcache_header *header;
2097c2c66affSColin Finck     struct hash_entry *hash_entry;
2098c2c66affSColin Finck     entry_url *url_entry;
2099c2c66affSColin Finck     cache_container *container;
2100c2c66affSColin Finck     DWORD error;
2101c2c66affSColin Finck 
2102c2c66affSColin Finck     TRACE("(%s, %p, %p, %x)\n", debugstr_a(url), entry_info, size, unicode);
2103c2c66affSColin Finck 
2104c2c66affSColin Finck     if(!url || !size || (!entry_info && *size)) {
2105c2c66affSColin Finck         SetLastError(ERROR_INVALID_PARAMETER);
2106c2c66affSColin Finck         return FALSE;
2107c2c66affSColin Finck     }
2108c2c66affSColin Finck 
2109c2c66affSColin Finck     error = cache_containers_find(url, &container);
2110c2c66affSColin Finck     if(error != ERROR_SUCCESS) {
2111c2c66affSColin Finck         SetLastError(error);
2112c2c66affSColin Finck         return FALSE;
2113c2c66affSColin Finck     }
2114c2c66affSColin Finck 
2115c2c66affSColin Finck     error = cache_container_open_index(container, MIN_BLOCK_NO);
2116c2c66affSColin Finck     if (error != ERROR_SUCCESS) {
2117c2c66affSColin Finck         SetLastError(error);
2118c2c66affSColin Finck         return FALSE;
2119c2c66affSColin Finck     }
2120c2c66affSColin Finck 
2121c2c66affSColin Finck     if (!(header = cache_container_lock_index(container)))
2122c2c66affSColin Finck         return FALSE;
2123c2c66affSColin Finck 
2124c2c66affSColin Finck     if (!urlcache_find_hash_entry(header, url, &hash_entry)) {
2125c2c66affSColin Finck         cache_container_unlock_index(container, header);
2126c2c66affSColin Finck         TRACE("entry %s not found!\n", debugstr_a(url));
2127c2c66affSColin Finck         SetLastError(ERROR_FILE_NOT_FOUND);
2128c2c66affSColin Finck         return FALSE;
2129c2c66affSColin Finck     }
2130c2c66affSColin Finck 
2131c2c66affSColin Finck     url_entry = (entry_url*)((LPBYTE)header + hash_entry->offset);
2132c2c66affSColin Finck     if(url_entry->header.signature != URL_SIGNATURE) {
2133c2c66affSColin Finck         FIXME("Trying to retrieve entry of unknown format %s\n",
2134c2c66affSColin Finck                 debugstr_an((LPSTR)&url_entry->header.signature, sizeof(DWORD)));
2135ef9a828eSwinesync         cache_container_unlock_index(container, header);
2136c2c66affSColin Finck         SetLastError(ERROR_FILE_NOT_FOUND);
2137c2c66affSColin Finck         return FALSE;
2138c2c66affSColin Finck     }
2139c2c66affSColin Finck 
2140c2c66affSColin Finck     if(!url_entry->local_name_off) {
2141c2c66affSColin Finck         cache_container_unlock_index(container, header);
2142c2c66affSColin Finck         SetLastError(ERROR_INVALID_DATA);
2143c2c66affSColin Finck         return FALSE;
2144c2c66affSColin Finck     }
2145c2c66affSColin Finck 
2146c2c66affSColin Finck     TRACE("Found URL: %s\n", debugstr_a((LPCSTR)url_entry + url_entry->url_off));
2147c2c66affSColin Finck     TRACE("Header info: %s\n", debugstr_an((LPCSTR)url_entry + url_entry->header_info_off,
2148c2c66affSColin Finck                 url_entry->header_info_size));
2149c2c66affSColin Finck 
2150c2c66affSColin Finck     error = urlcache_copy_entry(container, header, entry_info,
2151c2c66affSColin Finck             size, url_entry, unicode);
2152c2c66affSColin Finck     if(error != ERROR_SUCCESS) {
2153c2c66affSColin Finck         cache_container_unlock_index(container, header);
2154c2c66affSColin Finck         SetLastError(error);
2155c2c66affSColin Finck         return FALSE;
2156c2c66affSColin Finck     }
2157c2c66affSColin Finck     TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)url_entry + url_entry->local_name_off));
2158c2c66affSColin Finck 
2159c2c66affSColin Finck     url_entry->hit_rate++;
2160c2c66affSColin Finck     url_entry->use_count++;
2161c2c66affSColin Finck     urlcache_hash_entry_set_flags(hash_entry, HASHTABLE_LOCK);
2162c2c66affSColin Finck     GetSystemTimeAsFileTime(&url_entry->access_time);
2163c2c66affSColin Finck 
2164c2c66affSColin Finck     cache_container_unlock_index(container, header);
2165c2c66affSColin Finck 
2166c2c66affSColin Finck     return TRUE;
2167c2c66affSColin Finck }
2168c2c66affSColin Finck 
2169c2c66affSColin Finck /***********************************************************************
2170c2c66affSColin Finck  *           RetrieveUrlCacheEntryFileA (WININET.@)
2171c2c66affSColin Finck  *
2172c2c66affSColin Finck  */
RetrieveUrlCacheEntryFileA(LPCSTR lpszUrlName,LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,LPDWORD lpdwCacheEntryInfoBufferSize,DWORD dwReserved)2173c2c66affSColin Finck BOOL WINAPI RetrieveUrlCacheEntryFileA(LPCSTR lpszUrlName,
2174c2c66affSColin Finck         LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
2175c2c66affSColin Finck         LPDWORD lpdwCacheEntryInfoBufferSize, DWORD dwReserved)
2176c2c66affSColin Finck {
2177c2c66affSColin Finck     return urlcache_entry_get_file(lpszUrlName, lpCacheEntryInfo,
2178c2c66affSColin Finck             lpdwCacheEntryInfoBufferSize, FALSE);
2179c2c66affSColin Finck }
2180c2c66affSColin Finck 
2181c2c66affSColin Finck /***********************************************************************
2182c2c66affSColin Finck  *           RetrieveUrlCacheEntryFileW (WININET.@)
2183c2c66affSColin Finck  *
2184c2c66affSColin Finck  */
RetrieveUrlCacheEntryFileW(LPCWSTR lpszUrlName,LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,LPDWORD lpdwCacheEntryInfoBufferSize,DWORD dwReserved)2185c2c66affSColin Finck BOOL WINAPI RetrieveUrlCacheEntryFileW(LPCWSTR lpszUrlName,
2186c2c66affSColin Finck         LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
2187c2c66affSColin Finck         LPDWORD lpdwCacheEntryInfoBufferSize, DWORD dwReserved)
2188c2c66affSColin Finck {
2189c2c66affSColin Finck     char *url;
2190c2c66affSColin Finck     BOOL ret;
2191c2c66affSColin Finck 
2192c2c66affSColin Finck     if(!urlcache_encode_url_alloc(lpszUrlName, &url))
2193c2c66affSColin Finck         return FALSE;
2194c2c66affSColin Finck 
2195c2c66affSColin Finck     ret = urlcache_entry_get_file(url, lpCacheEntryInfo,
2196c2c66affSColin Finck             lpdwCacheEntryInfoBufferSize, TRUE);
2197c2c66affSColin Finck     heap_free(url);
2198c2c66affSColin Finck     return ret;
2199c2c66affSColin Finck }
2200c2c66affSColin Finck 
urlcache_entry_delete(const cache_container * pContainer,urlcache_header * pHeader,struct hash_entry * pHashEntry)2201c2c66affSColin Finck static BOOL urlcache_entry_delete(const cache_container *pContainer,
2202c2c66affSColin Finck         urlcache_header *pHeader, struct hash_entry *pHashEntry)
2203c2c66affSColin Finck {
2204c2c66affSColin Finck     entry_header *pEntry;
2205c2c66affSColin Finck     entry_url * pUrlEntry;
2206c2c66affSColin Finck 
2207c2c66affSColin Finck     pEntry = (entry_header*)((LPBYTE)pHeader + pHashEntry->offset);
2208c2c66affSColin Finck     if (pEntry->signature != URL_SIGNATURE)
2209c2c66affSColin Finck     {
2210c2c66affSColin Finck         FIXME("Trying to delete entry of unknown format %s\n",
2211c2c66affSColin Finck               debugstr_an((LPCSTR)&pEntry->signature, sizeof(DWORD)));
2212c2c66affSColin Finck         SetLastError(ERROR_FILE_NOT_FOUND);
2213c2c66affSColin Finck         return FALSE;
2214c2c66affSColin Finck     }
2215c2c66affSColin Finck 
2216c2c66affSColin Finck     pUrlEntry = (entry_url *)pEntry;
2217c2c66affSColin Finck     if(urlcache_hash_entry_is_locked(pHashEntry, pUrlEntry))
2218c2c66affSColin Finck     {
2219c2c66affSColin Finck         TRACE("Trying to delete locked entry\n");
2220c2c66affSColin Finck         pUrlEntry->cache_entry_type |= PENDING_DELETE_CACHE_ENTRY;
2221c2c66affSColin Finck         SetLastError(ERROR_SHARING_VIOLATION);
2222c2c66affSColin Finck         return FALSE;
2223c2c66affSColin Finck     }
2224c2c66affSColin Finck 
2225c2c66affSColin Finck     if(!urlcache_delete_file(pContainer, pHeader, pUrlEntry))
2226c2c66affSColin Finck     {
2227c2c66affSColin Finck         urlcache_entry_free(pHeader, pEntry);
2228c2c66affSColin Finck     }
2229c2c66affSColin Finck     else
2230c2c66affSColin Finck     {
2231c2c66affSColin Finck         /* Add entry to leaked files list */
2232c2c66affSColin Finck         pUrlEntry->header.signature = LEAK_SIGNATURE;
2233c2c66affSColin Finck         pUrlEntry->exempt_delta = pHeader->options[CACHE_HEADER_DATA_ROOT_LEAK_OFFSET];
2234c2c66affSColin Finck         pHeader->options[CACHE_HEADER_DATA_ROOT_LEAK_OFFSET] = pHashEntry->offset;
2235c2c66affSColin Finck     }
2236c2c66affSColin Finck 
2237c2c66affSColin Finck     urlcache_hash_entry_delete(pHashEntry);
2238c2c66affSColin Finck     return TRUE;
2239c2c66affSColin Finck }
2240c2c66affSColin Finck 
2241c2c66affSColin Finck static HANDLE free_cache_running;
2242c2c66affSColin Finck static HANDLE dll_unload_event;
handle_full_cache_worker(void * param)2243c2c66affSColin Finck static DWORD WINAPI handle_full_cache_worker(void *param)
2244c2c66affSColin Finck {
2245c2c66affSColin Finck     FreeUrlCacheSpaceW(NULL, 20, 0);
2246c2c66affSColin Finck     ReleaseSemaphore(free_cache_running, 1, NULL);
2247c2c66affSColin Finck     return 0;
2248c2c66affSColin Finck }
2249c2c66affSColin Finck 
handle_full_cache(void)2250c2c66affSColin Finck static void handle_full_cache(void)
2251c2c66affSColin Finck {
2252c2c66affSColin Finck     if(WaitForSingleObject(free_cache_running, 0) == WAIT_OBJECT_0) {
2253c2c66affSColin Finck         if(!QueueUserWorkItem(handle_full_cache_worker, NULL, 0))
2254c2c66affSColin Finck             ReleaseSemaphore(free_cache_running, 1, NULL);
2255c2c66affSColin Finck     }
2256c2c66affSColin Finck }
2257c2c66affSColin Finck 
2258c2c66affSColin Finck /* Enumerates entries in cache, allows cache unlocking between calls. */
urlcache_next_entry(urlcache_header * header,DWORD * hash_table_off,DWORD * hash_table_entry,struct hash_entry ** hash_entry,entry_header ** entry)2259c2c66affSColin Finck static BOOL urlcache_next_entry(urlcache_header *header, DWORD *hash_table_off, DWORD *hash_table_entry,
2260c2c66affSColin Finck         struct hash_entry **hash_entry, entry_header **entry)
2261c2c66affSColin Finck {
2262c2c66affSColin Finck     entry_hash_table *hashtable_entry;
2263c2c66affSColin Finck 
2264c2c66affSColin Finck     *hash_entry = NULL;
2265c2c66affSColin Finck     *entry = NULL;
2266c2c66affSColin Finck 
2267c2c66affSColin Finck     if(!*hash_table_off) {
2268c2c66affSColin Finck         *hash_table_off = header->hash_table_off;
2269c2c66affSColin Finck         *hash_table_entry = 0;
2270c2c66affSColin Finck 
2271c2c66affSColin Finck         hashtable_entry = urlcache_get_hash_table(header, *hash_table_off);
2272c2c66affSColin Finck     }else {
2273c2c66affSColin Finck         if(*hash_table_off >= header->size) {
2274c2c66affSColin Finck             *hash_table_off = 0;
2275c2c66affSColin Finck             return FALSE;
2276c2c66affSColin Finck         }
2277c2c66affSColin Finck 
2278c2c66affSColin Finck         hashtable_entry = urlcache_get_hash_table(header, *hash_table_off);
2279c2c66affSColin Finck     }
2280c2c66affSColin Finck 
2281c2c66affSColin Finck     if(hashtable_entry->header.signature != HASH_SIGNATURE) {
2282c2c66affSColin Finck         *hash_table_off = 0;
2283c2c66affSColin Finck         return FALSE;
2284c2c66affSColin Finck     }
2285c2c66affSColin Finck 
2286c2c66affSColin Finck     while(1) {
2287c2c66affSColin Finck         if(*hash_table_entry >= HASHTABLE_SIZE) {
2288c2c66affSColin Finck             *hash_table_off = hashtable_entry->next;
2289c2c66affSColin Finck             if(!*hash_table_off) {
2290c2c66affSColin Finck                 *hash_table_off = 0;
2291c2c66affSColin Finck                 return FALSE;
2292c2c66affSColin Finck             }
2293c2c66affSColin Finck 
2294c2c66affSColin Finck             hashtable_entry = urlcache_get_hash_table(header, *hash_table_off);
2295c2c66affSColin Finck             *hash_table_entry = 0;
2296c2c66affSColin Finck         }
2297c2c66affSColin Finck 
2298c2c66affSColin Finck         if(hashtable_entry->hash_table[*hash_table_entry].key != HASHTABLE_DEL &&
2299c2c66affSColin Finck             hashtable_entry->hash_table[*hash_table_entry].key != HASHTABLE_FREE) {
2300c2c66affSColin Finck             *hash_entry = &hashtable_entry->hash_table[*hash_table_entry];
2301c2c66affSColin Finck             *entry = (entry_header*)((LPBYTE)header + hashtable_entry->hash_table[*hash_table_entry].offset);
2302c2c66affSColin Finck             (*hash_table_entry)++;
2303c2c66affSColin Finck             return TRUE;
2304c2c66affSColin Finck         }
2305c2c66affSColin Finck 
2306c2c66affSColin Finck         (*hash_table_entry)++;
2307c2c66affSColin Finck     }
2308c2c66affSColin Finck 
2309c2c66affSColin Finck     *hash_table_off = 0;
2310c2c66affSColin Finck     return FALSE;
2311c2c66affSColin Finck }
2312c2c66affSColin Finck 
2313c2c66affSColin Finck /* Rates an urlcache entry to determine if it can be deleted.
2314c2c66affSColin Finck  *
2315c2c66affSColin Finck  * Score 0 means that entry can safely be removed, the bigger rating
2316c2c66affSColin Finck  * the smaller chance of entry being removed.
2317c2c66affSColin Finck  * DWORD_MAX means that entry can't be deleted at all.
2318c2c66affSColin Finck  *
2319c2c66affSColin Finck  * Rating system is currently not fully compatible with native implementation.
2320c2c66affSColin Finck  */
urlcache_rate_entry(entry_url * url_entry,FILETIME * cur_time)2321c2c66affSColin Finck static DWORD urlcache_rate_entry(entry_url *url_entry, FILETIME *cur_time)
2322c2c66affSColin Finck {
2323c2c66affSColin Finck     ULARGE_INTEGER time, access_time;
2324c2c66affSColin Finck     DWORD rating;
2325c2c66affSColin Finck 
2326c2c66affSColin Finck     access_time.u.LowPart = url_entry->access_time.dwLowDateTime;
2327c2c66affSColin Finck     access_time.u.HighPart = url_entry->access_time.dwHighDateTime;
2328c2c66affSColin Finck 
2329c2c66affSColin Finck     time.u.LowPart = cur_time->dwLowDateTime;
2330c2c66affSColin Finck     time.u.HighPart = cur_time->dwHighDateTime;
2331c2c66affSColin Finck 
2332c2c66affSColin Finck     /* Don't touch entries that were added less than 10 minutes ago */
2333c2c66affSColin Finck     if(time.QuadPart < access_time.QuadPart + (ULONGLONG)10*60*FILETIME_SECOND)
2334c2c66affSColin Finck         return -1;
2335c2c66affSColin Finck 
2336c2c66affSColin Finck     if(url_entry->cache_entry_type & STICKY_CACHE_ENTRY)
2337c2c66affSColin Finck         if(time.QuadPart < access_time.QuadPart + (ULONGLONG)url_entry->exempt_delta*FILETIME_SECOND)
2338c2c66affSColin Finck             return -1;
2339c2c66affSColin Finck 
2340c2c66affSColin Finck     time.QuadPart = (time.QuadPart-access_time.QuadPart)/FILETIME_SECOND;
2341c2c66affSColin Finck     rating = 400*60*60*24/(60*60*24+time.QuadPart);
2342c2c66affSColin Finck 
2343c2c66affSColin Finck     if(url_entry->hit_rate > 100)
2344c2c66affSColin Finck         rating += 100;
2345c2c66affSColin Finck     else
2346c2c66affSColin Finck         rating += url_entry->hit_rate;
2347c2c66affSColin Finck 
2348c2c66affSColin Finck     return rating;
2349c2c66affSColin Finck }
2350c2c66affSColin Finck 
dword_cmp(const void * p1,const void * p2)23515f12c8d7Swinesync static int __cdecl dword_cmp(const void *p1, const void *p2)
2352c2c66affSColin Finck {
2353c2c66affSColin Finck     return *(const DWORD*)p1 - *(const DWORD*)p2;
2354c2c66affSColin Finck }
2355c2c66affSColin Finck 
2356c2c66affSColin Finck /***********************************************************************
2357c2c66affSColin Finck  *           FreeUrlCacheSpaceW (WININET.@)
2358c2c66affSColin Finck  *
2359c2c66affSColin Finck  * Frees up some cache.
2360c2c66affSColin Finck  *
2361c2c66affSColin Finck  * PARAMETERS
2362c2c66affSColin Finck  *   cache_path    [I] Which volume to free up from, or NULL if you don't care.
2363c2c66affSColin Finck  *   size          [I] Percentage of the cache that should be free.
2364c2c66affSColin Finck  *   filter        [I] Which entries can't be deleted (CacheEntryType)
2365c2c66affSColin Finck  *
2366c2c66affSColin Finck  * RETURNS
2367c2c66affSColin Finck  *   TRUE success. FALSE failure.
2368c2c66affSColin Finck  *
2369c2c66affSColin Finck  * IMPLEMENTATION
2370c2c66affSColin Finck  *   This implementation just retrieves the path of the cache directory, and
2371c2c66affSColin Finck  *   deletes its contents from the filesystem. The correct approach would
2372c2c66affSColin Finck  *   probably be to implement and use {FindFirst,FindNext,Delete}UrlCacheGroup().
2373c2c66affSColin Finck  */
FreeUrlCacheSpaceW(LPCWSTR cache_path,DWORD size,DWORD filter)2374c2c66affSColin Finck BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR cache_path, DWORD size, DWORD filter)
2375c2c66affSColin Finck {
2376c2c66affSColin Finck     cache_container *container;
2377c2c66affSColin Finck     DWORD path_len, err;
2378c2c66affSColin Finck 
2379c2c66affSColin Finck     TRACE("(%s, %x, %x)\n", debugstr_w(cache_path), size, filter);
2380c2c66affSColin Finck 
2381c2c66affSColin Finck     if(size<1 || size>100) {
2382c2c66affSColin Finck         SetLastError(ERROR_INVALID_PARAMETER);
2383c2c66affSColin Finck         return FALSE;
2384c2c66affSColin Finck     }
2385c2c66affSColin Finck 
2386c2c66affSColin Finck     if(cache_path) {
23875f12c8d7Swinesync         path_len = lstrlenW(cache_path);
2388c2c66affSColin Finck         if(cache_path[path_len-1] == '\\')
2389c2c66affSColin Finck             path_len--;
2390c2c66affSColin Finck     }else {
2391c2c66affSColin Finck         path_len = 0;
2392c2c66affSColin Finck     }
2393c2c66affSColin Finck 
2394c2c66affSColin Finck     if(size==100 && !filter) {
2395c2c66affSColin Finck         LIST_FOR_EACH_ENTRY(container, &UrlContainers, cache_container, entry)
2396c2c66affSColin Finck         {
2397c2c66affSColin Finck             /* When cache_path==NULL only clean Temporary Internet Files */
2398c2c66affSColin Finck             if((!path_len && container->cache_prefix[0]==0) ||
23995f12c8d7Swinesync                     (path_len && !wcsnicmp(container->path, cache_path, path_len) &&
2400c2c66affSColin Finck                      (container->path[path_len]=='\0' || container->path[path_len]=='\\')))
2401c2c66affSColin Finck             {
2402c2c66affSColin Finck                 BOOL ret_del;
2403c2c66affSColin Finck 
2404c2c66affSColin Finck                 WaitForSingleObject(container->mutex, INFINITE);
2405c2c66affSColin Finck 
2406c2c66affSColin Finck                 /* unlock, delete, recreate and lock cache */
2407c2c66affSColin Finck                 cache_container_close_index(container);
2408c2c66affSColin Finck                 ret_del = cache_container_delete_dir(container->path);
2409c2c66affSColin Finck                 err = cache_container_open_index(container, MIN_BLOCK_NO);
2410c2c66affSColin Finck 
2411c2c66affSColin Finck                 ReleaseMutex(container->mutex);
2412c2c66affSColin Finck                 if(!ret_del || (err != ERROR_SUCCESS))
2413c2c66affSColin Finck                     return FALSE;
2414c2c66affSColin Finck             }
2415c2c66affSColin Finck         }
2416c2c66affSColin Finck 
2417c2c66affSColin Finck         return TRUE;
2418c2c66affSColin Finck     }
2419c2c66affSColin Finck 
2420c2c66affSColin Finck     LIST_FOR_EACH_ENTRY(container, &UrlContainers, cache_container, entry)
2421c2c66affSColin Finck     {
2422c2c66affSColin Finck         urlcache_header *header;
2423c2c66affSColin Finck         struct hash_entry *hash_entry;
2424c2c66affSColin Finck         entry_header *entry;
2425c2c66affSColin Finck         entry_url *url_entry;
2426c2c66affSColin Finck         ULONGLONG desired_size, cur_size;
2427c2c66affSColin Finck         DWORD delete_factor, hash_table_off, hash_table_entry;
2428c2c66affSColin Finck         DWORD rate[100], rate_no;
2429c2c66affSColin Finck         FILETIME cur_time;
2430c2c66affSColin Finck 
2431c2c66affSColin Finck         if((path_len || container->cache_prefix[0]!=0) &&
24325f12c8d7Swinesync                 (!path_len || wcsnicmp(container->path, cache_path, path_len) ||
2433c2c66affSColin Finck                  (container->path[path_len]!='\0' && container->path[path_len]!='\\')))
2434c2c66affSColin Finck             continue;
2435c2c66affSColin Finck 
2436c2c66affSColin Finck         err = cache_container_open_index(container, MIN_BLOCK_NO);
2437c2c66affSColin Finck         if(err != ERROR_SUCCESS)
2438c2c66affSColin Finck             continue;
2439c2c66affSColin Finck 
2440c2c66affSColin Finck         header = cache_container_lock_index(container);
2441c2c66affSColin Finck         if(!header)
2442c2c66affSColin Finck             continue;
2443c2c66affSColin Finck 
2444c2c66affSColin Finck         urlcache_clean_leaked_entries(container, header);
2445c2c66affSColin Finck 
2446c2c66affSColin Finck         desired_size = header->cache_limit.QuadPart*(100-size)/100;
2447c2c66affSColin Finck         cur_size = header->cache_usage.QuadPart+header->exempt_usage.QuadPart;
2448c2c66affSColin Finck         if(cur_size <= desired_size)
2449c2c66affSColin Finck             delete_factor = 0;
2450c2c66affSColin Finck         else
2451c2c66affSColin Finck             delete_factor = (cur_size-desired_size)*100/cur_size;
2452c2c66affSColin Finck 
2453c2c66affSColin Finck         if(!delete_factor) {
2454c2c66affSColin Finck             cache_container_unlock_index(container, header);
2455c2c66affSColin Finck             continue;
2456c2c66affSColin Finck         }
2457c2c66affSColin Finck 
2458c2c66affSColin Finck         hash_table_off = 0;
2459c2c66affSColin Finck         hash_table_entry = 0;
2460c2c66affSColin Finck         rate_no = 0;
2461c2c66affSColin Finck         GetSystemTimeAsFileTime(&cur_time);
2462c239cdd4SAmine Khaldi         while(rate_no < ARRAY_SIZE(rate) &&
2463c2c66affSColin Finck                 urlcache_next_entry(header, &hash_table_off, &hash_table_entry, &hash_entry, &entry)) {
2464c2c66affSColin Finck             if(entry->signature != URL_SIGNATURE) {
2465c2c66affSColin Finck                 WARN("only url entries are currently supported\n");
2466c2c66affSColin Finck                 continue;
2467c2c66affSColin Finck             }
2468c2c66affSColin Finck 
2469c2c66affSColin Finck             url_entry = (entry_url*)entry;
2470c2c66affSColin Finck             if(url_entry->cache_entry_type & filter)
2471c2c66affSColin Finck                 continue;
2472c2c66affSColin Finck 
2473c2c66affSColin Finck             rate[rate_no] = urlcache_rate_entry(url_entry, &cur_time);
2474c2c66affSColin Finck             if(rate[rate_no] != -1)
2475c2c66affSColin Finck                 rate_no++;
2476c2c66affSColin Finck         }
2477c2c66affSColin Finck 
2478c2c66affSColin Finck         if(!rate_no) {
2479c2c66affSColin Finck             TRACE("nothing to delete\n");
2480c2c66affSColin Finck             cache_container_unlock_index(container, header);
2481c2c66affSColin Finck             continue;
2482c2c66affSColin Finck         }
2483c2c66affSColin Finck 
2484c2c66affSColin Finck         qsort(rate, rate_no, sizeof(DWORD), dword_cmp);
2485c2c66affSColin Finck 
2486c2c66affSColin Finck         delete_factor = delete_factor*rate_no/100;
2487c2c66affSColin Finck         delete_factor = rate[delete_factor];
2488c2c66affSColin Finck         TRACE("deleting files with rating %d or less\n", delete_factor);
2489c2c66affSColin Finck 
2490c2c66affSColin Finck         hash_table_off = 0;
2491c2c66affSColin Finck         while(urlcache_next_entry(header, &hash_table_off, &hash_table_entry, &hash_entry, &entry)) {
2492c2c66affSColin Finck             if(entry->signature != URL_SIGNATURE)
2493c2c66affSColin Finck                 continue;
2494c2c66affSColin Finck 
2495c2c66affSColin Finck             url_entry = (entry_url*)entry;
2496c2c66affSColin Finck             if(url_entry->cache_entry_type & filter)
2497c2c66affSColin Finck                 continue;
2498c2c66affSColin Finck 
2499c2c66affSColin Finck             if(urlcache_rate_entry(url_entry, &cur_time) <= delete_factor) {
2500c2c66affSColin Finck                 TRACE("deleting file: %s\n", debugstr_a((char*)url_entry+url_entry->local_name_off));
2501c2c66affSColin Finck                 urlcache_entry_delete(container, header, hash_entry);
2502c2c66affSColin Finck 
2503c2c66affSColin Finck                 if(header->cache_usage.QuadPart+header->exempt_usage.QuadPart <= desired_size)
2504c2c66affSColin Finck                     break;
2505c2c66affSColin Finck 
2506c2c66affSColin Finck                 /* Allow other threads to use cache while cleaning */
2507c2c66affSColin Finck                 cache_container_unlock_index(container, header);
2508c2c66affSColin Finck                 if(WaitForSingleObject(dll_unload_event, 0) == WAIT_OBJECT_0) {
2509c2c66affSColin Finck                     TRACE("got dll_unload_event - finishing\n");
2510c2c66affSColin Finck                     return TRUE;
2511c2c66affSColin Finck                 }
2512c2c66affSColin Finck                 Sleep(0);
2513c2c66affSColin Finck                 header = cache_container_lock_index(container);
2514c2c66affSColin Finck             }
2515c2c66affSColin Finck         }
2516c2c66affSColin Finck 
2517c2c66affSColin Finck         TRACE("cache size after cleaning 0x%s/0x%s\n",
2518c2c66affSColin Finck                 wine_dbgstr_longlong(header->cache_usage.QuadPart+header->exempt_usage.QuadPart),
2519c2c66affSColin Finck                 wine_dbgstr_longlong(header->cache_limit.QuadPart));
2520c2c66affSColin Finck         cache_container_unlock_index(container, header);
2521c2c66affSColin Finck     }
2522c2c66affSColin Finck 
2523c2c66affSColin Finck     return TRUE;
2524c2c66affSColin Finck }
2525c2c66affSColin Finck 
2526c2c66affSColin Finck /***********************************************************************
2527c2c66affSColin Finck  *           FreeUrlCacheSpaceA (WININET.@)
2528c2c66affSColin Finck  *
2529c2c66affSColin Finck  * See FreeUrlCacheSpaceW.
2530c2c66affSColin Finck  */
FreeUrlCacheSpaceA(LPCSTR lpszCachePath,DWORD dwSize,DWORD dwFilter)2531c2c66affSColin Finck BOOL WINAPI FreeUrlCacheSpaceA(LPCSTR lpszCachePath, DWORD dwSize, DWORD dwFilter)
2532c2c66affSColin Finck {
2533c2c66affSColin Finck     BOOL ret = FALSE;
2534c2c66affSColin Finck     LPWSTR path = heap_strdupAtoW(lpszCachePath);
2535c2c66affSColin Finck     if (lpszCachePath == NULL || path != NULL)
2536c2c66affSColin Finck         ret = FreeUrlCacheSpaceW(path, dwSize, dwFilter);
2537c2c66affSColin Finck     heap_free(path);
2538c2c66affSColin Finck     return ret;
2539c2c66affSColin Finck }
2540c2c66affSColin Finck 
2541c2c66affSColin Finck /***********************************************************************
2542c2c66affSColin Finck  *           UnlockUrlCacheEntryFileA (WININET.@)
2543c2c66affSColin Finck  *
2544c2c66affSColin Finck  */
UnlockUrlCacheEntryFileA(LPCSTR lpszUrlName,DWORD dwReserved)2545c2c66affSColin Finck BOOL WINAPI UnlockUrlCacheEntryFileA(LPCSTR lpszUrlName, DWORD dwReserved)
2546c2c66affSColin Finck {
2547c2c66affSColin Finck     urlcache_header *pHeader;
2548c2c66affSColin Finck     struct hash_entry *pHashEntry;
2549c2c66affSColin Finck     entry_header *pEntry;
2550c2c66affSColin Finck     entry_url * pUrlEntry;
2551c2c66affSColin Finck     cache_container *pContainer;
2552c2c66affSColin Finck     DWORD error;
2553c2c66affSColin Finck 
2554c2c66affSColin Finck     TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved);
2555c2c66affSColin Finck 
2556c2c66affSColin Finck     if (dwReserved)
2557c2c66affSColin Finck     {
2558c2c66affSColin Finck         ERR("dwReserved != 0\n");
2559c2c66affSColin Finck         SetLastError(ERROR_INVALID_PARAMETER);
2560c2c66affSColin Finck         return FALSE;
2561c2c66affSColin Finck     }
2562c2c66affSColin Finck 
2563c2c66affSColin Finck     error = cache_containers_find(lpszUrlName, &pContainer);
2564c2c66affSColin Finck     if (error != ERROR_SUCCESS)
2565c2c66affSColin Finck     {
2566c2c66affSColin Finck        SetLastError(error);
2567c2c66affSColin Finck        return FALSE;
2568c2c66affSColin Finck     }
2569c2c66affSColin Finck 
2570c2c66affSColin Finck     error = cache_container_open_index(pContainer, MIN_BLOCK_NO);
2571c2c66affSColin Finck     if (error != ERROR_SUCCESS)
2572c2c66affSColin Finck     {
2573c2c66affSColin Finck         SetLastError(error);
2574c2c66affSColin Finck         return FALSE;
2575c2c66affSColin Finck     }
2576c2c66affSColin Finck 
2577c2c66affSColin Finck     if (!(pHeader = cache_container_lock_index(pContainer)))
2578c2c66affSColin Finck         return FALSE;
2579c2c66affSColin Finck 
2580c2c66affSColin Finck     if (!urlcache_find_hash_entry(pHeader, lpszUrlName, &pHashEntry))
2581c2c66affSColin Finck     {
2582c2c66affSColin Finck         cache_container_unlock_index(pContainer, pHeader);
2583c2c66affSColin Finck         TRACE("entry %s not found!\n", debugstr_a(lpszUrlName));
2584c2c66affSColin Finck         SetLastError(ERROR_FILE_NOT_FOUND);
2585c2c66affSColin Finck         return FALSE;
2586c2c66affSColin Finck     }
2587c2c66affSColin Finck 
2588c2c66affSColin Finck     pEntry = (entry_header*)((LPBYTE)pHeader + pHashEntry->offset);
2589c2c66affSColin Finck     if (pEntry->signature != URL_SIGNATURE)
2590c2c66affSColin Finck     {
2591c2c66affSColin Finck         cache_container_unlock_index(pContainer, pHeader);
2592c2c66affSColin Finck         FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->signature, sizeof(DWORD)));
2593c2c66affSColin Finck         SetLastError(ERROR_FILE_NOT_FOUND);
2594c2c66affSColin Finck         return FALSE;
2595c2c66affSColin Finck     }
2596c2c66affSColin Finck 
2597c2c66affSColin Finck     pUrlEntry = (entry_url *)pEntry;
2598c2c66affSColin Finck 
2599c2c66affSColin Finck     if (pUrlEntry->use_count == 0)
2600c2c66affSColin Finck     {
2601c2c66affSColin Finck         cache_container_unlock_index(pContainer, pHeader);
2602c2c66affSColin Finck         return FALSE;
2603c2c66affSColin Finck     }
2604c2c66affSColin Finck     pUrlEntry->use_count--;
2605c2c66affSColin Finck     if (!pUrlEntry->use_count)
2606c2c66affSColin Finck     {
2607c2c66affSColin Finck         urlcache_hash_entry_set_flags(pHashEntry, HASHTABLE_URL);
2608c2c66affSColin Finck         if (pUrlEntry->cache_entry_type & PENDING_DELETE_CACHE_ENTRY)
2609c2c66affSColin Finck             urlcache_entry_delete(pContainer, pHeader, pHashEntry);
2610c2c66affSColin Finck     }
2611c2c66affSColin Finck 
2612c2c66affSColin Finck     cache_container_unlock_index(pContainer, pHeader);
2613c2c66affSColin Finck 
2614c2c66affSColin Finck     return TRUE;
2615c2c66affSColin Finck }
2616c2c66affSColin Finck 
2617c2c66affSColin Finck /***********************************************************************
2618c2c66affSColin Finck  *           UnlockUrlCacheEntryFileW (WININET.@)
2619c2c66affSColin Finck  *
2620c2c66affSColin Finck  */
UnlockUrlCacheEntryFileW(LPCWSTR lpszUrlName,DWORD dwReserved)2621c2c66affSColin Finck BOOL WINAPI UnlockUrlCacheEntryFileW(LPCWSTR lpszUrlName, DWORD dwReserved)
2622c2c66affSColin Finck {
2623c2c66affSColin Finck     char *url;
2624c2c66affSColin Finck     BOOL ret;
2625c2c66affSColin Finck 
2626c2c66affSColin Finck     if(!urlcache_encode_url_alloc(lpszUrlName, &url))
2627c2c66affSColin Finck         return FALSE;
2628c2c66affSColin Finck 
2629c2c66affSColin Finck     ret = UnlockUrlCacheEntryFileA(url, dwReserved);
2630c2c66affSColin Finck     heap_free(url);
2631c2c66affSColin Finck     return ret;
2632c2c66affSColin Finck }
2633c2c66affSColin Finck 
urlcache_entry_create(const char * url,const char * ext,WCHAR * full_path)2634c2c66affSColin Finck static BOOL urlcache_entry_create(const char *url, const char *ext, WCHAR *full_path)
2635c2c66affSColin Finck {
2636c2c66affSColin Finck     cache_container *container;
2637c2c66affSColin Finck     urlcache_header *header;
2638c2c66affSColin Finck     char file_name[MAX_PATH];
2639c2c66affSColin Finck     WCHAR extW[MAX_PATH];
2640c2c66affSColin Finck     BYTE cache_dir;
2641c2c66affSColin Finck     LONG full_path_len, ext_len = 0;
2642c2c66affSColin Finck     BOOL generate_name = FALSE;
2643c2c66affSColin Finck     DWORD error;
2644c2c66affSColin Finck     HANDLE file;
2645c2c66affSColin Finck     FILETIME ft;
2646c2c66affSColin Finck     URL_COMPONENTSA uc;
2647c2c66affSColin Finck     int i;
2648c2c66affSColin Finck 
2649c2c66affSColin Finck     TRACE("(%s, %s, %p)\n", debugstr_a(url), debugstr_a(ext), full_path);
2650c2c66affSColin Finck 
2651c2c66affSColin Finck     memset(&uc, 0, sizeof(uc));
2652c2c66affSColin Finck     uc.dwStructSize = sizeof(uc);
2653c2c66affSColin Finck     uc.dwUrlPathLength = 1;
2654c2c66affSColin Finck     uc.dwExtraInfoLength = 1;
2655c2c66affSColin Finck     if(!InternetCrackUrlA(url, 0, 0, &uc))
2656c2c66affSColin Finck         uc.dwUrlPathLength = 0;
2657c2c66affSColin Finck 
2658c2c66affSColin Finck     if(!uc.dwUrlPathLength) {
2659c2c66affSColin Finck         file_name[0] = 0;
2660c2c66affSColin Finck     }else {
2661c2c66affSColin Finck         char *p, *e;
2662c2c66affSColin Finck 
2663c2c66affSColin Finck         p = e = uc.lpszUrlPath+uc.dwUrlPathLength;
2664c2c66affSColin Finck         while(p>uc.lpszUrlPath && *(p-1)!='/' && *(p-1)!='\\' && *(p-1)!='.')
2665c2c66affSColin Finck             p--;
2666c2c66affSColin Finck         if(p>uc.lpszUrlPath && *(p-1)=='.') {
2667c2c66affSColin Finck             e = p-1;
2668c2c66affSColin Finck             while(p>uc.lpszUrlPath && *(p-1)!='/' && *(p-1)!='\\')
2669c2c66affSColin Finck                 p--;
2670c2c66affSColin Finck         }
2671c2c66affSColin Finck 
2672c2c66affSColin Finck         if(e-p >= MAX_PATH)
2673c2c66affSColin Finck             e = p+MAX_PATH-1;
2674c2c66affSColin Finck         memcpy(file_name, p, e-p);
2675c2c66affSColin Finck         file_name[e-p] = 0;
2676c2c66affSColin Finck 
2677c2c66affSColin Finck         for(p=file_name; *p; p++) {
2678c2c66affSColin Finck             switch(*p) {
2679c2c66affSColin Finck             case '<': case '>':
2680c2c66affSColin Finck             case ':': case '"':
2681c2c66affSColin Finck             case '|': case '?':
2682c2c66affSColin Finck             case '*':
2683c2c66affSColin Finck                 *p = '_'; break;
2684c2c66affSColin Finck             default: break;
2685c2c66affSColin Finck             }
2686c2c66affSColin Finck         }
2687c2c66affSColin Finck     }
2688c2c66affSColin Finck 
2689c2c66affSColin Finck     if(!file_name[0])
2690c2c66affSColin Finck         generate_name = TRUE;
2691c2c66affSColin Finck 
2692c2c66affSColin Finck     error = cache_containers_find(url, &container);
2693c2c66affSColin Finck     if(error != ERROR_SUCCESS) {
2694c2c66affSColin Finck         SetLastError(error);
2695c2c66affSColin Finck         return FALSE;
2696c2c66affSColin Finck     }
2697c2c66affSColin Finck 
2698c2c66affSColin Finck     error = cache_container_open_index(container, MIN_BLOCK_NO);
2699c2c66affSColin Finck     if(error != ERROR_SUCCESS) {
2700c2c66affSColin Finck         SetLastError(error);
2701c2c66affSColin Finck         return FALSE;
2702c2c66affSColin Finck     }
2703c2c66affSColin Finck 
2704c2c66affSColin Finck     if(!(header = cache_container_lock_index(container)))
2705c2c66affSColin Finck         return FALSE;
2706c2c66affSColin Finck 
2707c2c66affSColin Finck     if(header->dirs_no)
2708c2c66affSColin Finck         cache_dir = (BYTE)(rand() % header->dirs_no);
2709c2c66affSColin Finck     else
2710c2c66affSColin Finck         cache_dir = CACHE_CONTAINER_NO_SUBDIR;
2711c2c66affSColin Finck 
2712c2c66affSColin Finck     full_path_len = MAX_PATH * sizeof(WCHAR);
2713c2c66affSColin Finck     if(!urlcache_create_file_pathW(container, header, file_name, cache_dir, full_path, &full_path_len, TRUE)) {
2714c2c66affSColin Finck         WARN("Failed to get full path for filename %s, needed %u bytes.\n",
2715c2c66affSColin Finck                 debugstr_a(file_name), full_path_len);
2716c2c66affSColin Finck         cache_container_unlock_index(container, header);
2717c2c66affSColin Finck         return FALSE;
2718c2c66affSColin Finck     }
2719c2c66affSColin Finck     full_path_len = full_path_len/sizeof(WCHAR) - 1;
2720c2c66affSColin Finck 
2721c2c66affSColin Finck     cache_container_unlock_index(container, header);
2722c2c66affSColin Finck 
2723c2c66affSColin Finck     if(ext) {
2724c2c66affSColin Finck         WCHAR *p;
2725c2c66affSColin Finck 
2726c2c66affSColin Finck         extW[0] = '.';
2727c2c66affSColin Finck         ext_len = MultiByteToWideChar(CP_ACP, 0, ext, -1, extW+1, MAX_PATH-1);
2728c2c66affSColin Finck 
2729c2c66affSColin Finck         for(p=extW; *p; p++) {
2730c2c66affSColin Finck             switch(*p) {
2731c2c66affSColin Finck             case '<': case '>':
2732c2c66affSColin Finck             case ':': case '"':
2733c2c66affSColin Finck             case '|': case '?':
2734c2c66affSColin Finck             case '*':
2735c2c66affSColin Finck                 *p = '_'; break;
2736c2c66affSColin Finck             default: break;
2737c2c66affSColin Finck             }
2738c2c66affSColin Finck         }
2739c2c66affSColin Finck         if(p[-1]==' ' || p[-1]=='.')
2740c2c66affSColin Finck             p[-1] = '_';
2741c2c66affSColin Finck     }else {
2742c2c66affSColin Finck         extW[0] = '\0';
2743c2c66affSColin Finck     }
2744c2c66affSColin Finck 
2745c2c66affSColin Finck     if(!generate_name && full_path_len+5+ext_len>=MAX_PATH) { /* strlen("[255]") = 5 */
2746c2c66affSColin Finck         full_path_len = MAX_PATH-5-ext_len-1;
2747c2c66affSColin Finck     }
2748c2c66affSColin Finck 
2749c2c66affSColin Finck     for(i=0; i<255 && !generate_name; i++) {
2750*e152f78aSwinesync         wsprintfW(full_path+full_path_len, L"[%u]%s", i, extW);
2751c2c66affSColin Finck 
2752c2c66affSColin Finck         TRACE("Trying: %s\n", debugstr_w(full_path));
2753c2c66affSColin Finck         file = CreateFileW(full_path, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2754c2c66affSColin Finck         if(file != INVALID_HANDLE_VALUE) {
2755c2c66affSColin Finck             CloseHandle(file);
2756c2c66affSColin Finck             return TRUE;
2757c2c66affSColin Finck         }
2758c2c66affSColin Finck     }
2759c2c66affSColin Finck 
2760c2c66affSColin Finck     if(full_path_len+8+ext_len >= MAX_PATH)
2761c2c66affSColin Finck         full_path_len = MAX_PATH-8-ext_len-1;
2762c2c66affSColin Finck 
2763c2c66affSColin Finck     /* Try to generate random name */
2764c2c66affSColin Finck     GetSystemTimeAsFileTime(&ft);
27655f12c8d7Swinesync     lstrcpyW(full_path+full_path_len+8, extW);
2766c2c66affSColin Finck 
2767c2c66affSColin Finck     for(i=0; i<255; i++) {
2768c2c66affSColin Finck         int j;
2769c2c66affSColin Finck         ULONGLONG n = ft.dwHighDateTime;
2770c2c66affSColin Finck         n <<= 32;
2771c2c66affSColin Finck         n += ft.dwLowDateTime;
2772c2c66affSColin Finck         n ^= (ULONGLONG)i<<48;
2773c2c66affSColin Finck 
2774c2c66affSColin Finck         for(j=0; j<8; j++) {
2775c2c66affSColin Finck             int r = (n % 36);
2776c2c66affSColin Finck             n /= 37;
2777c2c66affSColin Finck             full_path[full_path_len+j] = (r < 10 ? '0' + r : 'A' + r - 10);
2778c2c66affSColin Finck         }
2779c2c66affSColin Finck 
2780c2c66affSColin Finck         TRACE("Trying: %s\n", debugstr_w(full_path));
2781c2c66affSColin Finck         file = CreateFileW(full_path, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
2782c2c66affSColin Finck         if(file != INVALID_HANDLE_VALUE) {
2783c2c66affSColin Finck             CloseHandle(file);
2784c2c66affSColin Finck             return TRUE;
2785c2c66affSColin Finck         }
2786c2c66affSColin Finck     }
2787c2c66affSColin Finck 
2788c2c66affSColin Finck     WARN("Could not find a unique filename\n");
2789c2c66affSColin Finck     return FALSE;
2790c2c66affSColin Finck }
2791c2c66affSColin Finck 
2792c2c66affSColin Finck /***********************************************************************
2793c2c66affSColin Finck  *           CreateUrlCacheEntryA (WININET.@)
2794c2c66affSColin Finck  *
2795c2c66affSColin Finck  */
CreateUrlCacheEntryA(LPCSTR lpszUrlName,DWORD dwExpectedFileSize,LPCSTR lpszFileExtension,LPSTR lpszFileName,DWORD dwReserved)2796c2c66affSColin Finck BOOL WINAPI CreateUrlCacheEntryA(LPCSTR lpszUrlName, DWORD dwExpectedFileSize,
2797c2c66affSColin Finck         LPCSTR lpszFileExtension, LPSTR lpszFileName, DWORD dwReserved)
2798c2c66affSColin Finck {
2799c2c66affSColin Finck     WCHAR file_name[MAX_PATH];
2800c2c66affSColin Finck 
2801c2c66affSColin Finck     if(dwReserved)
2802c2c66affSColin Finck         FIXME("dwReserved 0x%08x\n", dwReserved);
2803c2c66affSColin Finck 
2804c2c66affSColin Finck     if(!urlcache_entry_create(lpszUrlName, lpszFileExtension, file_name))
2805c2c66affSColin Finck         return FALSE;
2806c2c66affSColin Finck 
2807c2c66affSColin Finck     if(!WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL))
2808c2c66affSColin Finck         return FALSE;
2809c2c66affSColin Finck     return TRUE;
2810c2c66affSColin Finck }
2811c2c66affSColin Finck /***********************************************************************
2812c2c66affSColin Finck  *           CreateUrlCacheEntryW (WININET.@)
2813c2c66affSColin Finck  *
2814c2c66affSColin Finck  */
CreateUrlCacheEntryW(LPCWSTR lpszUrlName,DWORD dwExpectedFileSize,LPCWSTR lpszFileExtension,LPWSTR lpszFileName,DWORD dwReserved)2815c2c66affSColin Finck BOOL WINAPI CreateUrlCacheEntryW(LPCWSTR lpszUrlName, DWORD dwExpectedFileSize,
2816c2c66affSColin Finck         LPCWSTR lpszFileExtension, LPWSTR lpszFileName, DWORD dwReserved)
2817c2c66affSColin Finck {
2818c2c66affSColin Finck     char *url, *ext = NULL;
2819c2c66affSColin Finck     BOOL ret;
2820c2c66affSColin Finck 
2821c2c66affSColin Finck     if(dwReserved)
2822c2c66affSColin Finck         FIXME("dwReserved 0x%08x\n", dwReserved);
2823c2c66affSColin Finck 
2824c2c66affSColin Finck     if(lpszFileExtension) {
2825c2c66affSColin Finck         ext = heap_strdupWtoUTF8(lpszFileExtension);
2826c2c66affSColin Finck         if(!ext)
2827c2c66affSColin Finck             return FALSE;
2828c2c66affSColin Finck     }
2829c2c66affSColin Finck 
2830c2c66affSColin Finck     if(!urlcache_encode_url_alloc(lpszUrlName, &url)) {
2831c2c66affSColin Finck         heap_free(ext);
2832c2c66affSColin Finck         return FALSE;
2833c2c66affSColin Finck     }
2834c2c66affSColin Finck 
2835c2c66affSColin Finck     ret = urlcache_entry_create(url, ext, lpszFileName);
2836c2c66affSColin Finck     heap_free(ext);
2837c2c66affSColin Finck     heap_free(url);
2838c2c66affSColin Finck     return ret;
2839c2c66affSColin Finck }
2840c2c66affSColin Finck 
urlcache_entry_commit(const char * url,const WCHAR * file_name,FILETIME expire_time,FILETIME modify_time,DWORD entry_type,BYTE * header_info,DWORD header_size,const char * file_ext,const char * original_url)2841c2c66affSColin Finck static BOOL urlcache_entry_commit(const char *url, const WCHAR *file_name,
2842c2c66affSColin Finck     FILETIME expire_time, FILETIME modify_time, DWORD entry_type,
2843c2c66affSColin Finck     BYTE *header_info, DWORD header_size, const char *file_ext,
2844c2c66affSColin Finck     const char *original_url)
2845c2c66affSColin Finck {
2846c2c66affSColin Finck     cache_container *container;
2847c2c66affSColin Finck     urlcache_header *header;
2848c2c66affSColin Finck     struct hash_entry *hash_entry;
2849c2c66affSColin Finck     entry_header *entry;
2850c2c66affSColin Finck     entry_url *url_entry;
2851c2c66affSColin Finck     DWORD url_entry_offset;
2852c2c66affSColin Finck     DWORD size = DWORD_ALIGN(sizeof(*url_entry));
2853c2c66affSColin Finck     DWORD file_name_off = 0;
2854c2c66affSColin Finck     DWORD header_info_off = 0;
2855c2c66affSColin Finck     DWORD file_ext_off = 0;
2856c2c66affSColin Finck     WIN32_FILE_ATTRIBUTE_DATA file_attr;
2857c2c66affSColin Finck     LARGE_INTEGER file_size;
2858c2c66affSColin Finck     BYTE dir_id;
2859c2c66affSColin Finck     char file_name_no_container[MAX_PATH];
2860c2c66affSColin Finck     char *local_file_name = 0;
2861c2c66affSColin Finck     DWORD hit_rate = 0;
2862c2c66affSColin Finck     DWORD exempt_delta = 0;
2863c2c66affSColin Finck     DWORD error;
2864c2c66affSColin Finck 
2865c2c66affSColin Finck     TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n", debugstr_a(url), debugstr_w(file_name),
2866c2c66affSColin Finck             entry_type, header_info, header_size, debugstr_a(file_ext), debugstr_a(original_url));
2867c2c66affSColin Finck 
2868c2c66affSColin Finck     if(entry_type & STICKY_CACHE_ENTRY && !file_name) {
2869c2c66affSColin Finck         SetLastError(ERROR_INVALID_PARAMETER);
2870c2c66affSColin Finck         return FALSE;
2871c2c66affSColin Finck     }
2872c2c66affSColin Finck     if(original_url)
2873c2c66affSColin Finck         WARN(": original_url ignored\n");
2874c2c66affSColin Finck 
2875c2c66affSColin Finck     memset(&file_attr, 0, sizeof(file_attr));
2876c2c66affSColin Finck     if(file_name) {
2877c2c66affSColin Finck         if(!GetFileAttributesExW(file_name, GetFileExInfoStandard, &file_attr))
2878c2c66affSColin Finck             return FALSE;
2879c2c66affSColin Finck     }
2880c2c66affSColin Finck     file_size.u.LowPart = file_attr.nFileSizeLow;
2881c2c66affSColin Finck     file_size.u.HighPart = file_attr.nFileSizeHigh;
2882c2c66affSColin Finck 
2883c2c66affSColin Finck     error = cache_containers_find(url, &container);
2884c2c66affSColin Finck     if(error != ERROR_SUCCESS) {
2885c2c66affSColin Finck         SetLastError(error);
2886c2c66affSColin Finck         return FALSE;
2887c2c66affSColin Finck     }
2888c2c66affSColin Finck 
2889c2c66affSColin Finck     error = cache_container_open_index(container, MIN_BLOCK_NO);
2890c2c66affSColin Finck     if(error != ERROR_SUCCESS) {
2891c2c66affSColin Finck         SetLastError(error);
2892c2c66affSColin Finck         return FALSE;
2893c2c66affSColin Finck     }
2894c2c66affSColin Finck 
2895c2c66affSColin Finck     if(!(header = cache_container_lock_index(container)))
2896c2c66affSColin Finck         return FALSE;
2897c2c66affSColin Finck 
2898c2c66affSColin Finck     if(urlcache_find_hash_entry(header, url, &hash_entry)) {
2899c2c66affSColin Finck         entry_url *url_entry = (entry_url*)((LPBYTE)header + hash_entry->offset);
2900c2c66affSColin Finck 
2901c2c66affSColin Finck         if(urlcache_hash_entry_is_locked(hash_entry, url_entry)) {
2902c2c66affSColin Finck             TRACE("Trying to overwrite locked entry\n");
2903c2c66affSColin Finck             cache_container_unlock_index(container, header);
2904c2c66affSColin Finck             SetLastError(ERROR_SHARING_VIOLATION);
2905c2c66affSColin Finck             return FALSE;
2906c2c66affSColin Finck         }
2907c2c66affSColin Finck 
2908c2c66affSColin Finck         hit_rate = url_entry->hit_rate;
2909c2c66affSColin Finck         exempt_delta = url_entry->exempt_delta;
2910c2c66affSColin Finck         urlcache_entry_delete(container, header, hash_entry);
2911c2c66affSColin Finck     }
2912c2c66affSColin Finck 
2913c2c66affSColin Finck     if(header->dirs_no)
2914c2c66affSColin Finck         dir_id = 0;
2915c2c66affSColin Finck     else
2916c2c66affSColin Finck         dir_id = CACHE_CONTAINER_NO_SUBDIR;
2917c2c66affSColin Finck 
2918c2c66affSColin Finck     if(file_name) {
2919c2c66affSColin Finck         BOOL bFound = FALSE;
2920c2c66affSColin Finck 
29215f12c8d7Swinesync         if(wcsncmp(file_name, container->path, lstrlenW(container->path))) {
2922c2c66affSColin Finck             ERR("path %s must begin with cache content path %s\n", debugstr_w(file_name), debugstr_w(container->path));
2923c2c66affSColin Finck             cache_container_unlock_index(container, header);
2924c2c66affSColin Finck             SetLastError(ERROR_INVALID_PARAMETER);
2925c2c66affSColin Finck             return FALSE;
2926c2c66affSColin Finck         }
2927c2c66affSColin Finck 
2928c2c66affSColin Finck         /* skip container path prefix */
2929c2c66affSColin Finck         file_name += lstrlenW(container->path);
2930c2c66affSColin Finck 
2931c2c66affSColin Finck         WideCharToMultiByte(CP_ACP, 0, file_name, -1, file_name_no_container, MAX_PATH, NULL, NULL);
2932c2c66affSColin Finck 	local_file_name = file_name_no_container;
2933c2c66affSColin Finck 
2934c2c66affSColin Finck         if(header->dirs_no) {
2935c2c66affSColin Finck             for(dir_id = 0; dir_id < header->dirs_no; dir_id++) {
2936c2c66affSColin Finck                 if(!strncmp(header->directory_data[dir_id].name, local_file_name, DIR_LENGTH)) {
2937c2c66affSColin Finck                     bFound = TRUE;
2938c2c66affSColin Finck                     break;
2939c2c66affSColin Finck                 }
2940c2c66affSColin Finck             }
2941c2c66affSColin Finck 
2942c2c66affSColin Finck             if(!bFound) {
2943c2c66affSColin Finck                 ERR("cache directory not found in path %s\n", debugstr_w(file_name));
2944c2c66affSColin Finck                 cache_container_unlock_index(container, header);
2945c2c66affSColin Finck                 SetLastError(ERROR_INVALID_PARAMETER);
2946c2c66affSColin Finck                 return FALSE;
2947c2c66affSColin Finck             }
2948c2c66affSColin Finck 
2949c2c66affSColin Finck             file_name += DIR_LENGTH + 1;
2950c2c66affSColin Finck             local_file_name += DIR_LENGTH + 1;
2951c2c66affSColin Finck         }
2952c2c66affSColin Finck     }
2953c2c66affSColin Finck 
2954c2c66affSColin Finck     size = DWORD_ALIGN(size + strlen(url) + 1);
2955c2c66affSColin Finck     if(file_name) {
2956c2c66affSColin Finck         file_name_off = size;
2957c2c66affSColin Finck         size = DWORD_ALIGN(size + strlen(local_file_name) + 1);
2958c2c66affSColin Finck     }
2959c2c66affSColin Finck     if(header_info && header_size) {
2960c2c66affSColin Finck         header_info_off = size;
2961c2c66affSColin Finck         size = DWORD_ALIGN(size + header_size);
2962c2c66affSColin Finck     }
2963c2c66affSColin Finck     if(file_ext && (file_ext_off = strlen(file_ext))) {
2964c2c66affSColin Finck         DWORD len = file_ext_off;
2965c2c66affSColin Finck 
2966c2c66affSColin Finck         file_ext_off = size;
2967c2c66affSColin Finck         size = DWORD_ALIGN(size + len + 1);
2968c2c66affSColin Finck     }
2969c2c66affSColin Finck 
2970c2c66affSColin Finck     /* round up to next block */
2971c2c66affSColin Finck     if(size % BLOCKSIZE) {
2972c2c66affSColin Finck         size -= size % BLOCKSIZE;
2973c2c66affSColin Finck         size += BLOCKSIZE;
2974c2c66affSColin Finck     }
2975c2c66affSColin Finck 
2976c2c66affSColin Finck     error = urlcache_entry_alloc(header, size / BLOCKSIZE, &entry);
2977c2c66affSColin Finck     while(error == ERROR_HANDLE_DISK_FULL) {
2978c2c66affSColin Finck         error = cache_container_clean_index(container, &header);
2979c2c66affSColin Finck         if(error == ERROR_SUCCESS)
2980c2c66affSColin Finck             error = urlcache_entry_alloc(header, size / BLOCKSIZE, &entry);
2981c2c66affSColin Finck     }
2982c2c66affSColin Finck     if(error != ERROR_SUCCESS) {
2983c2c66affSColin Finck         cache_container_unlock_index(container, header);
2984c2c66affSColin Finck         SetLastError(error);
2985c2c66affSColin Finck         return FALSE;
2986c2c66affSColin Finck     }
2987c2c66affSColin Finck 
2988c2c66affSColin Finck     /* FindFirstFreeEntry fills in blocks used */
2989c2c66affSColin Finck     url_entry = (entry_url *)entry;
2990c2c66affSColin Finck     url_entry_offset = (LPBYTE)url_entry - (LPBYTE)header;
2991c2c66affSColin Finck     url_entry->header.signature = URL_SIGNATURE;
2992c2c66affSColin Finck     url_entry->cache_dir = dir_id;
2993c2c66affSColin Finck     url_entry->cache_entry_type = entry_type | container->default_entry_type;
2994c2c66affSColin Finck     url_entry->header_info_size = header_size;
2995c2c66affSColin Finck     if((entry_type & STICKY_CACHE_ENTRY) && !exempt_delta) {
2996c2c66affSColin Finck         /* Sticky entries have a default exempt time of one day */
2997c2c66affSColin Finck         exempt_delta = 86400;
2998c2c66affSColin Finck     }
2999c2c66affSColin Finck     url_entry->exempt_delta = exempt_delta;
3000c2c66affSColin Finck     url_entry->hit_rate = hit_rate+1;
3001c2c66affSColin Finck     url_entry->file_extension_off = file_ext_off;
3002c2c66affSColin Finck     url_entry->header_info_off = header_info_off;
3003c2c66affSColin Finck     url_entry->local_name_off = file_name_off;
3004c2c66affSColin Finck     url_entry->url_off = DWORD_ALIGN(sizeof(*url_entry));
3005c2c66affSColin Finck     url_entry->size.QuadPart = file_size.QuadPart;
3006c2c66affSColin Finck     url_entry->use_count = 0;
3007c2c66affSColin Finck     GetSystemTimeAsFileTime(&url_entry->access_time);
3008c2c66affSColin Finck     url_entry->modification_time = modify_time;
3009c2c66affSColin Finck     file_time_to_dos_date_time(&url_entry->access_time, &url_entry->sync_date, &url_entry->sync_time);
3010c2c66affSColin Finck     file_time_to_dos_date_time(&expire_time, &url_entry->expire_date, &url_entry->expire_time);
3011c2c66affSColin Finck     file_time_to_dos_date_time(&file_attr.ftLastWriteTime, &url_entry->write_date, &url_entry->write_time);
3012c2c66affSColin Finck 
3013c2c66affSColin Finck     /*** Unknowns ***/
3014c2c66affSColin Finck     url_entry->unk1 = 0;
3015c2c66affSColin Finck     url_entry->unk2 = 0;
3016c2c66affSColin Finck     url_entry->unk3 = 0x60;
3017c2c66affSColin Finck     url_entry->unk4 = 0;
3018c2c66affSColin Finck     url_entry->unk5 = 0x1010;
3019c2c66affSColin Finck     url_entry->unk7 = 0;
3020c2c66affSColin Finck     url_entry->unk8 = 0;
3021c2c66affSColin Finck 
3022c2c66affSColin Finck 
3023c2c66affSColin Finck     strcpy((LPSTR)url_entry + url_entry->url_off, url);
3024c2c66affSColin Finck     if(file_name_off)
3025c2c66affSColin Finck         strcpy((LPSTR)((LPBYTE)url_entry + file_name_off), local_file_name);
3026c2c66affSColin Finck     if(header_info_off)
3027c2c66affSColin Finck         memcpy((LPBYTE)url_entry + header_info_off, header_info, header_size);
3028c2c66affSColin Finck     if(file_ext_off)
3029c2c66affSColin Finck         strcpy((LPSTR)((LPBYTE)url_entry + file_ext_off), file_ext);
3030c2c66affSColin Finck 
3031c2c66affSColin Finck     error = urlcache_hash_entry_create(header, url, url_entry_offset, HASHTABLE_URL);
3032c2c66affSColin Finck     while(error == ERROR_HANDLE_DISK_FULL) {
3033c2c66affSColin Finck         error = cache_container_clean_index(container, &header);
3034c2c66affSColin Finck         if(error == ERROR_SUCCESS) {
3035c2c66affSColin Finck             url_entry = (entry_url *)((LPBYTE)header + url_entry_offset);
3036c2c66affSColin Finck             error = urlcache_hash_entry_create(header, url,
3037c2c66affSColin Finck                     url_entry_offset, HASHTABLE_URL);
3038c2c66affSColin Finck         }
3039c2c66affSColin Finck     }
3040c2c66affSColin Finck     if(error != ERROR_SUCCESS) {
3041c2c66affSColin Finck         urlcache_entry_free(header, &url_entry->header);
3042c2c66affSColin Finck         cache_container_unlock_index(container, header);
3043c2c66affSColin Finck         SetLastError(error);
3044c2c66affSColin Finck         return FALSE;
3045c2c66affSColin Finck     }
3046c2c66affSColin Finck 
3047c2c66affSColin Finck     if(url_entry->cache_dir < header->dirs_no)
3048c2c66affSColin Finck         header->directory_data[url_entry->cache_dir].files_no++;
3049c2c66affSColin Finck     if(entry_type & STICKY_CACHE_ENTRY)
3050c2c66affSColin Finck         header->exempt_usage.QuadPart += file_size.QuadPart;
3051c2c66affSColin Finck     else
3052c2c66affSColin Finck         header->cache_usage.QuadPart += file_size.QuadPart;
3053c2c66affSColin Finck     if(header->cache_usage.QuadPart+header->exempt_usage.QuadPart > header->cache_limit.QuadPart)
3054c2c66affSColin Finck             handle_full_cache();
3055c2c66affSColin Finck 
3056c2c66affSColin Finck     cache_container_unlock_index(container, header);
3057c2c66affSColin Finck     return TRUE;
3058c2c66affSColin Finck }
3059c2c66affSColin Finck 
3060c2c66affSColin Finck /***********************************************************************
3061c2c66affSColin Finck  *           CommitUrlCacheEntryA (WININET.@)
3062c2c66affSColin Finck  */
CommitUrlCacheEntryA(LPCSTR lpszUrlName,LPCSTR lpszLocalFileName,FILETIME ExpireTime,FILETIME LastModifiedTime,DWORD CacheEntryType,LPBYTE lpHeaderInfo,DWORD dwHeaderSize,LPCSTR lpszFileExtension,LPCSTR lpszOriginalUrl)3063c2c66affSColin Finck BOOL WINAPI CommitUrlCacheEntryA(LPCSTR lpszUrlName, LPCSTR lpszLocalFileName,
3064c2c66affSColin Finck         FILETIME ExpireTime, FILETIME LastModifiedTime, DWORD CacheEntryType,
3065c2c66affSColin Finck         LPBYTE lpHeaderInfo, DWORD dwHeaderSize, LPCSTR lpszFileExtension, LPCSTR lpszOriginalUrl)
3066c2c66affSColin Finck {
3067c2c66affSColin Finck     WCHAR *file_name = NULL;
3068c2c66affSColin Finck     BOOL ret;
3069c2c66affSColin Finck 
3070c2c66affSColin Finck     if(lpszLocalFileName) {
3071c2c66affSColin Finck         file_name = heap_strdupAtoW(lpszLocalFileName);
3072c2c66affSColin Finck         if(!file_name)
3073c2c66affSColin Finck             return FALSE;
3074c2c66affSColin Finck     }
3075c2c66affSColin Finck 
3076c2c66affSColin Finck     ret = urlcache_entry_commit(lpszUrlName, file_name, ExpireTime, LastModifiedTime,
3077c2c66affSColin Finck             CacheEntryType, lpHeaderInfo, dwHeaderSize, lpszFileExtension, lpszOriginalUrl);
3078c2c66affSColin Finck     heap_free(file_name);
3079c2c66affSColin Finck     return ret;
3080c2c66affSColin Finck }
3081c2c66affSColin Finck 
3082c2c66affSColin Finck /***********************************************************************
3083c2c66affSColin Finck  *           CommitUrlCacheEntryW (WININET.@)
3084c2c66affSColin Finck  */
CommitUrlCacheEntryW(LPCWSTR lpszUrlName,LPCWSTR lpszLocalFileName,FILETIME ExpireTime,FILETIME LastModifiedTime,DWORD CacheEntryType,LPWSTR lpHeaderInfo,DWORD dwHeaderSize,LPCWSTR lpszFileExtension,LPCWSTR lpszOriginalUrl)3085c2c66affSColin Finck BOOL WINAPI CommitUrlCacheEntryW(LPCWSTR lpszUrlName, LPCWSTR lpszLocalFileName,
3086c2c66affSColin Finck         FILETIME ExpireTime, FILETIME LastModifiedTime, DWORD CacheEntryType,
3087c2c66affSColin Finck         LPWSTR lpHeaderInfo, DWORD dwHeaderSize, LPCWSTR lpszFileExtension, LPCWSTR lpszOriginalUrl)
3088c2c66affSColin Finck {
3089c2c66affSColin Finck     char *url, *original_url=NULL, *file_ext=NULL, *header_info=NULL;
3090c2c66affSColin Finck     BOOL ret;
3091c2c66affSColin Finck 
3092c2c66affSColin Finck     if(!urlcache_encode_url_alloc(lpszUrlName, &url))
3093c2c66affSColin Finck         return FALSE;
3094c2c66affSColin Finck 
3095c2c66affSColin Finck     if(lpHeaderInfo) {
3096c2c66affSColin Finck         header_info = heap_strdupWtoUTF8(lpHeaderInfo);
3097c2c66affSColin Finck         if(!header_info) {
3098c2c66affSColin Finck             heap_free(url);
3099c2c66affSColin Finck             return FALSE;
3100c2c66affSColin Finck         }
3101c2c66affSColin Finck         dwHeaderSize = strlen(header_info);
3102c2c66affSColin Finck     }
3103c2c66affSColin Finck 
3104c2c66affSColin Finck     if(lpszFileExtension) {
3105c2c66affSColin Finck         file_ext = heap_strdupWtoA(lpszFileExtension);
3106c2c66affSColin Finck         if(!file_ext) {
3107c2c66affSColin Finck             heap_free(url);
3108c2c66affSColin Finck             heap_free(header_info);
3109c2c66affSColin Finck             return FALSE;
3110c2c66affSColin Finck         }
3111c2c66affSColin Finck     }
3112c2c66affSColin Finck 
3113c2c66affSColin Finck     if(lpszOriginalUrl && !urlcache_encode_url_alloc(lpszOriginalUrl, &original_url)) {
3114c2c66affSColin Finck         heap_free(url);
3115c2c66affSColin Finck         heap_free(header_info);
3116c2c66affSColin Finck         heap_free(file_ext);
3117c2c66affSColin Finck         return FALSE;
3118c2c66affSColin Finck     }
3119c2c66affSColin Finck 
3120c2c66affSColin Finck     ret = urlcache_entry_commit(url, lpszLocalFileName, ExpireTime, LastModifiedTime,
3121c2c66affSColin Finck             CacheEntryType, (BYTE*)header_info, dwHeaderSize, file_ext, original_url);
3122c2c66affSColin Finck     heap_free(url);
3123c2c66affSColin Finck     heap_free(header_info);
3124c2c66affSColin Finck     heap_free(file_ext);
3125c2c66affSColin Finck     heap_free(original_url);
3126c2c66affSColin Finck     return ret;
3127c2c66affSColin Finck }
3128c2c66affSColin Finck 
3129c2c66affSColin Finck /***********************************************************************
3130c2c66affSColin Finck  *           ReadUrlCacheEntryStream (WININET.@)
3131c2c66affSColin Finck  *
3132c2c66affSColin Finck  */
ReadUrlCacheEntryStream(IN HANDLE hUrlCacheStream,IN DWORD dwLocation,IN OUT LPVOID lpBuffer,IN OUT LPDWORD lpdwLen,IN DWORD dwReserved)3133c2c66affSColin Finck BOOL WINAPI ReadUrlCacheEntryStream(
3134c2c66affSColin Finck     IN HANDLE hUrlCacheStream,
3135c2c66affSColin Finck     IN  DWORD dwLocation,
3136c2c66affSColin Finck     IN OUT LPVOID lpBuffer,
3137c2c66affSColin Finck     IN OUT LPDWORD lpdwLen,
3138c2c66affSColin Finck     IN DWORD dwReserved
3139c2c66affSColin Finck     )
3140c2c66affSColin Finck {
3141c2c66affSColin Finck     /* Get handle to file from 'stream' */
3142c2c66affSColin Finck     stream_handle *pStream = (stream_handle*)hUrlCacheStream;
3143c2c66affSColin Finck 
3144c2c66affSColin Finck     if (dwReserved != 0)
3145c2c66affSColin Finck     {
3146c2c66affSColin Finck         ERR("dwReserved != 0\n");
3147c2c66affSColin Finck         SetLastError(ERROR_INVALID_PARAMETER);
3148c2c66affSColin Finck         return FALSE;
3149c2c66affSColin Finck     }
3150c2c66affSColin Finck 
3151c2c66affSColin Finck     if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->url, INTERNET_MAX_URL_LENGTH))
3152c2c66affSColin Finck     {
3153c2c66affSColin Finck         SetLastError(ERROR_INVALID_HANDLE);
3154c2c66affSColin Finck         return FALSE;
3155c2c66affSColin Finck     }
3156c2c66affSColin Finck 
3157c2c66affSColin Finck     if (SetFilePointer(pStream->file, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER)
3158c2c66affSColin Finck         return FALSE;
3159c2c66affSColin Finck     return ReadFile(pStream->file, lpBuffer, *lpdwLen, lpdwLen, NULL);
3160c2c66affSColin Finck }
3161c2c66affSColin Finck 
3162c2c66affSColin Finck /***********************************************************************
3163c2c66affSColin Finck  *           RetrieveUrlCacheEntryStreamA (WININET.@)
3164c2c66affSColin Finck  *
3165c2c66affSColin Finck  */
RetrieveUrlCacheEntryStreamA(LPCSTR lpszUrlName,LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,LPDWORD lpdwCacheEntryInfoBufferSize,BOOL fRandomRead,DWORD dwReserved)3166c2c66affSColin Finck HANDLE WINAPI RetrieveUrlCacheEntryStreamA(LPCSTR lpszUrlName,
3167c2c66affSColin Finck         LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo,
3168c2c66affSColin Finck         LPDWORD lpdwCacheEntryInfoBufferSize, BOOL fRandomRead, DWORD dwReserved)
3169c2c66affSColin Finck {
3170c2c66affSColin Finck     /* NOTE: this is not the same as the way that the native
3171c2c66affSColin Finck      * version allocates 'stream' handles. I did it this way
3172c2c66affSColin Finck      * as it is much easier and no applications should depend
3173c2c66affSColin Finck      * on this behaviour. (Native version appears to allocate
3174c2c66affSColin Finck      * indices into a table)
3175c2c66affSColin Finck      */
3176c2c66affSColin Finck     stream_handle *stream;
3177c2c66affSColin Finck     HANDLE file;
3178c2c66affSColin Finck 
3179c2c66affSColin Finck     TRACE("(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo,
3180c2c66affSColin Finck             lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved);
3181c2c66affSColin Finck 
3182c2c66affSColin Finck     if(!RetrieveUrlCacheEntryFileA(lpszUrlName, lpCacheEntryInfo,
3183c2c66affSColin Finck                 lpdwCacheEntryInfoBufferSize, dwReserved))
3184c2c66affSColin Finck         return NULL;
3185c2c66affSColin Finck 
3186c2c66affSColin Finck     file = CreateFileA(lpCacheEntryInfo->lpszLocalFileName, GENERIC_READ, FILE_SHARE_READ,
3187c2c66affSColin Finck             NULL, OPEN_EXISTING, fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0, NULL);
3188c2c66affSColin Finck     if(file == INVALID_HANDLE_VALUE) {
3189c2c66affSColin Finck         UnlockUrlCacheEntryFileA(lpszUrlName, 0);
3190c2c66affSColin Finck         return NULL;
3191c2c66affSColin Finck     }
3192c2c66affSColin Finck 
3193c2c66affSColin Finck     /* allocate handle storage space */
3194c2c66affSColin Finck     stream = heap_alloc(sizeof(stream_handle) + strlen(lpszUrlName) * sizeof(CHAR));
3195c2c66affSColin Finck     if(!stream) {
3196c2c66affSColin Finck         CloseHandle(file);
3197c2c66affSColin Finck         UnlockUrlCacheEntryFileA(lpszUrlName, 0);
3198c2c66affSColin Finck         SetLastError(ERROR_OUTOFMEMORY);
3199c2c66affSColin Finck         return NULL;
3200c2c66affSColin Finck     }
3201c2c66affSColin Finck 
3202c2c66affSColin Finck     stream->file = file;
3203c2c66affSColin Finck     strcpy(stream->url, lpszUrlName);
3204c2c66affSColin Finck     return stream;
3205c2c66affSColin Finck }
3206c2c66affSColin Finck 
3207c2c66affSColin Finck /***********************************************************************
3208c2c66affSColin Finck  *           RetrieveUrlCacheEntryStreamW (WININET.@)
3209c2c66affSColin Finck  *
3210c2c66affSColin Finck  */
RetrieveUrlCacheEntryStreamW(LPCWSTR lpszUrlName,LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,LPDWORD lpdwCacheEntryInfoBufferSize,BOOL fRandomRead,DWORD dwReserved)3211c2c66affSColin Finck HANDLE WINAPI RetrieveUrlCacheEntryStreamW(LPCWSTR lpszUrlName,
3212c2c66affSColin Finck         LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
3213c2c66affSColin Finck         LPDWORD lpdwCacheEntryInfoBufferSize, BOOL fRandomRead, DWORD dwReserved)
3214c2c66affSColin Finck {
3215c2c66affSColin Finck     DWORD len;
3216c2c66affSColin Finck     /* NOTE: this is not the same as the way that the native
3217c2c66affSColin Finck      * version allocates 'stream' handles. I did it this way
3218c2c66affSColin Finck      * as it is much easier and no applications should depend
3219c2c66affSColin Finck      * on this behaviour. (Native version appears to allocate
3220c2c66affSColin Finck      * indices into a table)
3221c2c66affSColin Finck      */
3222c2c66affSColin Finck     stream_handle *stream;
3223c2c66affSColin Finck     HANDLE file;
3224c2c66affSColin Finck 
3225c2c66affSColin Finck     TRACE("(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo,
3226c2c66affSColin Finck             lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved);
3227c2c66affSColin Finck 
3228c2c66affSColin Finck     if(!(len = urlcache_encode_url(lpszUrlName, NULL, 0)))
3229c2c66affSColin Finck         return NULL;
3230c2c66affSColin Finck 
3231c2c66affSColin Finck     if(!RetrieveUrlCacheEntryFileW(lpszUrlName, lpCacheEntryInfo,
3232c2c66affSColin Finck                 lpdwCacheEntryInfoBufferSize, dwReserved))
3233c2c66affSColin Finck         return NULL;
3234c2c66affSColin Finck 
3235c2c66affSColin Finck     file = CreateFileW(lpCacheEntryInfo->lpszLocalFileName, GENERIC_READ, FILE_SHARE_READ,
3236c2c66affSColin Finck             NULL, OPEN_EXISTING, fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0, NULL);
3237c2c66affSColin Finck     if(file == INVALID_HANDLE_VALUE) {
3238c2c66affSColin Finck         UnlockUrlCacheEntryFileW(lpszUrlName, 0);
3239c2c66affSColin Finck         return NULL;
3240c2c66affSColin Finck     }
3241c2c66affSColin Finck 
3242c2c66affSColin Finck     /* allocate handle storage space */
3243c2c66affSColin Finck     stream = heap_alloc(sizeof(stream_handle) + len*sizeof(WCHAR));
3244c2c66affSColin Finck     if(!stream) {
3245c2c66affSColin Finck         CloseHandle(file);
3246c2c66affSColin Finck         UnlockUrlCacheEntryFileW(lpszUrlName, 0);
3247c2c66affSColin Finck         SetLastError(ERROR_OUTOFMEMORY);
3248c2c66affSColin Finck         return NULL;
3249c2c66affSColin Finck     }
3250c2c66affSColin Finck 
3251c2c66affSColin Finck     stream->file = file;
3252c2c66affSColin Finck     if(!urlcache_encode_url(lpszUrlName, stream->url, len)) {
3253c2c66affSColin Finck         CloseHandle(file);
3254c2c66affSColin Finck         UnlockUrlCacheEntryFileW(lpszUrlName, 0);
3255c2c66affSColin Finck         heap_free(stream);
3256c2c66affSColin Finck         return NULL;
3257c2c66affSColin Finck     }
3258c2c66affSColin Finck     return stream;
3259c2c66affSColin Finck }
3260c2c66affSColin Finck 
3261c2c66affSColin Finck /***********************************************************************
3262c2c66affSColin Finck  *           UnlockUrlCacheEntryStream (WININET.@)
3263c2c66affSColin Finck  *
3264c2c66affSColin Finck  */
UnlockUrlCacheEntryStream(IN HANDLE hUrlCacheStream,IN DWORD dwReserved)3265c2c66affSColin Finck BOOL WINAPI UnlockUrlCacheEntryStream(
3266c2c66affSColin Finck     IN HANDLE hUrlCacheStream,
3267c2c66affSColin Finck     IN DWORD dwReserved
3268c2c66affSColin Finck )
3269c2c66affSColin Finck {
3270c2c66affSColin Finck     stream_handle *pStream = (stream_handle*)hUrlCacheStream;
3271c2c66affSColin Finck 
3272c2c66affSColin Finck     if (dwReserved != 0)
3273c2c66affSColin Finck     {
3274c2c66affSColin Finck         ERR("dwReserved != 0\n");
3275c2c66affSColin Finck         SetLastError(ERROR_INVALID_PARAMETER);
3276c2c66affSColin Finck         return FALSE;
3277c2c66affSColin Finck     }
3278c2c66affSColin Finck 
3279c2c66affSColin Finck     if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->url, INTERNET_MAX_URL_LENGTH))
3280c2c66affSColin Finck     {
3281c2c66affSColin Finck         SetLastError(ERROR_INVALID_HANDLE);
3282c2c66affSColin Finck         return FALSE;
3283c2c66affSColin Finck     }
3284c2c66affSColin Finck 
3285c2c66affSColin Finck     if (!UnlockUrlCacheEntryFileA(pStream->url, 0))
3286c2c66affSColin Finck         return FALSE;
3287c2c66affSColin Finck 
3288c2c66affSColin Finck     CloseHandle(pStream->file);
3289c2c66affSColin Finck     heap_free(pStream);
3290c2c66affSColin Finck     return TRUE;
3291c2c66affSColin Finck }
3292c2c66affSColin Finck 
3293c2c66affSColin Finck 
3294c2c66affSColin Finck /***********************************************************************
3295c2c66affSColin Finck  *           DeleteUrlCacheEntryA (WININET.@)
3296c2c66affSColin Finck  *
3297c2c66affSColin Finck  */
DeleteUrlCacheEntryA(LPCSTR lpszUrlName)3298c2c66affSColin Finck BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName)
3299c2c66affSColin Finck {
3300c2c66affSColin Finck     cache_container *pContainer;
3301c2c66affSColin Finck     urlcache_header *pHeader;
3302c2c66affSColin Finck     struct hash_entry *pHashEntry;
3303c2c66affSColin Finck     DWORD error;
3304c2c66affSColin Finck     BOOL ret;
3305c2c66affSColin Finck 
3306c2c66affSColin Finck     TRACE("(%s)\n", debugstr_a(lpszUrlName));
3307c2c66affSColin Finck 
3308c2c66affSColin Finck     error = cache_containers_find(lpszUrlName, &pContainer);
3309c2c66affSColin Finck     if (error != ERROR_SUCCESS)
3310c2c66affSColin Finck     {
3311c2c66affSColin Finck         SetLastError(error);
3312c2c66affSColin Finck         return FALSE;
3313c2c66affSColin Finck     }
3314c2c66affSColin Finck 
3315c2c66affSColin Finck     error = cache_container_open_index(pContainer, MIN_BLOCK_NO);
3316c2c66affSColin Finck     if (error != ERROR_SUCCESS)
3317c2c66affSColin Finck     {
3318c2c66affSColin Finck         SetLastError(error);
3319c2c66affSColin Finck         return FALSE;
3320c2c66affSColin Finck     }
3321c2c66affSColin Finck 
3322c2c66affSColin Finck     if (!(pHeader = cache_container_lock_index(pContainer)))
3323c2c66affSColin Finck         return FALSE;
3324c2c66affSColin Finck 
3325c2c66affSColin Finck     if (!urlcache_find_hash_entry(pHeader, lpszUrlName, &pHashEntry))
3326c2c66affSColin Finck     {
3327c2c66affSColin Finck         cache_container_unlock_index(pContainer, pHeader);
3328c2c66affSColin Finck         TRACE("entry %s not found!\n", debugstr_a(lpszUrlName));
3329c2c66affSColin Finck         SetLastError(ERROR_FILE_NOT_FOUND);
3330c2c66affSColin Finck         return FALSE;
3331c2c66affSColin Finck     }
3332c2c66affSColin Finck 
3333c2c66affSColin Finck     ret = urlcache_entry_delete(pContainer, pHeader, pHashEntry);
3334c2c66affSColin Finck 
3335c2c66affSColin Finck     cache_container_unlock_index(pContainer, pHeader);
3336c2c66affSColin Finck 
3337c2c66affSColin Finck     return ret;
3338c2c66affSColin Finck }
3339c2c66affSColin Finck 
3340c2c66affSColin Finck /***********************************************************************
3341c2c66affSColin Finck  *           DeleteUrlCacheEntryW (WININET.@)
3342c2c66affSColin Finck  *
3343c2c66affSColin Finck  */
DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)3344c2c66affSColin Finck BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName)
3345c2c66affSColin Finck {
3346c2c66affSColin Finck     char *url;
3347c2c66affSColin Finck     BOOL ret;
3348c2c66affSColin Finck 
3349c2c66affSColin Finck     if(!urlcache_encode_url_alloc(lpszUrlName, &url))
3350c2c66affSColin Finck         return FALSE;
3351c2c66affSColin Finck 
3352c2c66affSColin Finck     ret = DeleteUrlCacheEntryA(url);
3353c2c66affSColin Finck     heap_free(url);
3354c2c66affSColin Finck     return ret;
3355c2c66affSColin Finck }
3356c2c66affSColin Finck 
DeleteUrlCacheContainerA(DWORD d1,DWORD d2)3357c2c66affSColin Finck BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2)
3358c2c66affSColin Finck {
3359c2c66affSColin Finck     FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3360c2c66affSColin Finck     return TRUE;
3361c2c66affSColin Finck }
3362c2c66affSColin Finck 
DeleteUrlCacheContainerW(DWORD d1,DWORD d2)3363c2c66affSColin Finck BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2)
3364c2c66affSColin Finck {
3365c2c66affSColin Finck     FIXME("(0x%08x, 0x%08x) stub\n", d1, d2);
3366c2c66affSColin Finck     return TRUE;
3367c2c66affSColin Finck }
3368c2c66affSColin Finck 
3369c2c66affSColin Finck /***********************************************************************
3370c2c66affSColin Finck  *           CreateCacheContainerA (WININET.@)
3371c2c66affSColin Finck  */
CreateUrlCacheContainerA(DWORD d1,DWORD d2,DWORD d3,DWORD d4,DWORD d5,DWORD d6,DWORD d7,DWORD d8)3372c2c66affSColin Finck BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3373c2c66affSColin Finck                                      DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3374c2c66affSColin Finck {
3375c2c66affSColin Finck     FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3376c2c66affSColin Finck           d1, d2, d3, d4, d5, d6, d7, d8);
3377c2c66affSColin Finck     return TRUE;
3378c2c66affSColin Finck }
3379c2c66affSColin Finck 
3380c2c66affSColin Finck /***********************************************************************
3381c2c66affSColin Finck  *           CreateCacheContainerW (WININET.@)
3382c2c66affSColin Finck  */
CreateUrlCacheContainerW(DWORD d1,DWORD d2,DWORD d3,DWORD d4,DWORD d5,DWORD d6,DWORD d7,DWORD d8)3383c2c66affSColin Finck BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4,
3384c2c66affSColin Finck                                      DWORD d5, DWORD d6, DWORD d7, DWORD d8)
3385c2c66affSColin Finck {
3386c2c66affSColin Finck     FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3387c2c66affSColin Finck           d1, d2, d3, d4, d5, d6, d7, d8);
3388c2c66affSColin Finck     return TRUE;
3389c2c66affSColin Finck }
3390c2c66affSColin Finck 
3391c2c66affSColin Finck /***********************************************************************
3392c2c66affSColin Finck  *           FindFirstUrlCacheContainerA (WININET.@)
3393c2c66affSColin Finck  */
FindFirstUrlCacheContainerA(LPVOID p1,LPVOID p2,LPVOID p3,DWORD d1)3394c2c66affSColin Finck HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3395c2c66affSColin Finck {
3396c2c66affSColin Finck     FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3397c2c66affSColin Finck     return NULL;
3398c2c66affSColin Finck }
3399c2c66affSColin Finck 
3400c2c66affSColin Finck /***********************************************************************
3401c2c66affSColin Finck  *           FindFirstUrlCacheContainerW (WININET.@)
3402c2c66affSColin Finck  */
FindFirstUrlCacheContainerW(LPVOID p1,LPVOID p2,LPVOID p3,DWORD d1)3403c2c66affSColin Finck HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 )
3404c2c66affSColin Finck {
3405c2c66affSColin Finck     FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3406c2c66affSColin Finck     return NULL;
3407c2c66affSColin Finck }
3408c2c66affSColin Finck 
3409c2c66affSColin Finck /***********************************************************************
3410c2c66affSColin Finck  *           FindNextUrlCacheContainerA (WININET.@)
3411c2c66affSColin Finck  */
FindNextUrlCacheContainerA(HANDLE handle,LPVOID p1,LPVOID p2)3412c2c66affSColin Finck BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 )
3413c2c66affSColin Finck {
3414c2c66affSColin Finck     FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3415c2c66affSColin Finck     return FALSE;
3416c2c66affSColin Finck }
3417c2c66affSColin Finck 
3418c2c66affSColin Finck /***********************************************************************
3419c2c66affSColin Finck  *           FindNextUrlCacheContainerW (WININET.@)
3420c2c66affSColin Finck  */
FindNextUrlCacheContainerW(HANDLE handle,LPVOID p1,LPVOID p2)3421c2c66affSColin Finck BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 )
3422c2c66affSColin Finck {
3423c2c66affSColin Finck     FIXME("(%p, %p, %p) stub\n", handle, p1, p2 );
3424c2c66affSColin Finck     return FALSE;
3425c2c66affSColin Finck }
3426c2c66affSColin Finck 
FindFirstUrlCacheEntryExA(LPCSTR lpszUrlSearchPattern,DWORD dwFlags,DWORD dwFilter,GROUPID GroupId,LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,LPDWORD lpdwFirstCacheEntryInfoBufferSize,LPVOID lpReserved,LPDWORD pcbReserved2,LPVOID lpReserved3)3427c2c66affSColin Finck HANDLE WINAPI FindFirstUrlCacheEntryExA(
3428c2c66affSColin Finck   LPCSTR lpszUrlSearchPattern,
3429c2c66affSColin Finck   DWORD dwFlags,
3430c2c66affSColin Finck   DWORD dwFilter,
3431c2c66affSColin Finck   GROUPID GroupId,
3432c2c66affSColin Finck   LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3433c2c66affSColin Finck   LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3434c2c66affSColin Finck   LPVOID lpReserved,
3435c2c66affSColin Finck   LPDWORD pcbReserved2,
3436c2c66affSColin Finck   LPVOID lpReserved3
3437c2c66affSColin Finck )
3438c2c66affSColin Finck {
3439c2c66affSColin Finck     FIXME("(%s, 0x%08x, 0x%08x, 0x%s, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern),
3440c2c66affSColin Finck           dwFlags, dwFilter, wine_dbgstr_longlong(GroupId), lpFirstCacheEntryInfo,
3441c2c66affSColin Finck           lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3442c2c66affSColin Finck     SetLastError(ERROR_FILE_NOT_FOUND);
3443c2c66affSColin Finck     return NULL;
3444c2c66affSColin Finck }
3445c2c66affSColin Finck 
FindFirstUrlCacheEntryExW(LPCWSTR lpszUrlSearchPattern,DWORD dwFlags,DWORD dwFilter,GROUPID GroupId,LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,LPDWORD lpdwFirstCacheEntryInfoBufferSize,LPVOID lpReserved,LPDWORD pcbReserved2,LPVOID lpReserved3)3446c2c66affSColin Finck HANDLE WINAPI FindFirstUrlCacheEntryExW(
3447c2c66affSColin Finck   LPCWSTR lpszUrlSearchPattern,
3448c2c66affSColin Finck   DWORD dwFlags,
3449c2c66affSColin Finck   DWORD dwFilter,
3450c2c66affSColin Finck   GROUPID GroupId,
3451c2c66affSColin Finck   LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3452c2c66affSColin Finck   LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3453c2c66affSColin Finck   LPVOID lpReserved,
3454c2c66affSColin Finck   LPDWORD pcbReserved2,
3455c2c66affSColin Finck   LPVOID lpReserved3
3456c2c66affSColin Finck )
3457c2c66affSColin Finck {
3458c2c66affSColin Finck     FIXME("(%s, 0x%08x, 0x%08x, 0x%s, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern),
3459c2c66affSColin Finck           dwFlags, dwFilter, wine_dbgstr_longlong(GroupId), lpFirstCacheEntryInfo,
3460c2c66affSColin Finck           lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3);
3461c2c66affSColin Finck     SetLastError(ERROR_FILE_NOT_FOUND);
3462c2c66affSColin Finck     return NULL;
3463c2c66affSColin Finck }
3464c2c66affSColin Finck 
3465c2c66affSColin Finck /***********************************************************************
3466c2c66affSColin Finck  *           FindFirstUrlCacheEntryA (WININET.@)
3467c2c66affSColin Finck  *
3468c2c66affSColin Finck  */
FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,LPDWORD lpdwFirstCacheEntryInfoBufferSize)3469c2c66affSColin Finck INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern,
3470c2c66affSColin Finck  LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3471c2c66affSColin Finck {
3472c2c66affSColin Finck     find_handle *pEntryHandle;
3473c2c66affSColin Finck 
3474c2c66affSColin Finck     TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3475c2c66affSColin Finck 
3476c2c66affSColin Finck     pEntryHandle = heap_alloc(sizeof(*pEntryHandle));
3477c2c66affSColin Finck     if (!pEntryHandle)
3478c2c66affSColin Finck         return NULL;
3479c2c66affSColin Finck 
3480c2c66affSColin Finck     pEntryHandle->magic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3481c2c66affSColin Finck     if (lpszUrlSearchPattern)
3482c2c66affSColin Finck     {
3483c2c66affSColin Finck         pEntryHandle->url_search_pattern = heap_strdupA(lpszUrlSearchPattern);
3484c2c66affSColin Finck         if (!pEntryHandle->url_search_pattern)
3485c2c66affSColin Finck         {
3486c2c66affSColin Finck             heap_free(pEntryHandle);
3487c2c66affSColin Finck             return NULL;
3488c2c66affSColin Finck         }
3489c2c66affSColin Finck     }
3490c2c66affSColin Finck     else
3491c2c66affSColin Finck         pEntryHandle->url_search_pattern = NULL;
3492c2c66affSColin Finck     pEntryHandle->container_idx = 0;
3493c2c66affSColin Finck     pEntryHandle->hash_table_idx = 0;
3494c2c66affSColin Finck     pEntryHandle->hash_entry_idx = 0;
3495c2c66affSColin Finck 
3496c2c66affSColin Finck     if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3497c2c66affSColin Finck     {
3498c2c66affSColin Finck         heap_free(pEntryHandle);
3499c2c66affSColin Finck         return NULL;
3500c2c66affSColin Finck     }
3501c2c66affSColin Finck     return pEntryHandle;
3502c2c66affSColin Finck }
3503c2c66affSColin Finck 
3504c2c66affSColin Finck /***********************************************************************
3505c2c66affSColin Finck  *           FindFirstUrlCacheEntryW (WININET.@)
3506c2c66affSColin Finck  *
3507c2c66affSColin Finck  */
FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,LPDWORD lpdwFirstCacheEntryInfoBufferSize)3508c2c66affSColin Finck INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern,
3509c2c66affSColin Finck  LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize)
3510c2c66affSColin Finck {
3511c2c66affSColin Finck     find_handle *pEntryHandle;
3512c2c66affSColin Finck 
3513c2c66affSColin Finck     TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3514c2c66affSColin Finck 
3515c2c66affSColin Finck     pEntryHandle = heap_alloc(sizeof(*pEntryHandle));
3516c2c66affSColin Finck     if (!pEntryHandle)
3517c2c66affSColin Finck         return NULL;
3518c2c66affSColin Finck 
3519c2c66affSColin Finck     pEntryHandle->magic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC;
3520c2c66affSColin Finck     if (lpszUrlSearchPattern)
3521c2c66affSColin Finck     {
3522c2c66affSColin Finck         pEntryHandle->url_search_pattern = heap_strdupWtoA(lpszUrlSearchPattern);
3523c2c66affSColin Finck         if (!pEntryHandle->url_search_pattern)
3524c2c66affSColin Finck         {
3525c2c66affSColin Finck             heap_free(pEntryHandle);
3526c2c66affSColin Finck             return NULL;
3527c2c66affSColin Finck         }
3528c2c66affSColin Finck     }
3529c2c66affSColin Finck     else
3530c2c66affSColin Finck         pEntryHandle->url_search_pattern = NULL;
3531c2c66affSColin Finck     pEntryHandle->container_idx = 0;
3532c2c66affSColin Finck     pEntryHandle->hash_table_idx = 0;
3533c2c66affSColin Finck     pEntryHandle->hash_entry_idx = 0;
3534c2c66affSColin Finck 
3535c2c66affSColin Finck     if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize))
3536c2c66affSColin Finck     {
3537c2c66affSColin Finck         heap_free(pEntryHandle);
3538c2c66affSColin Finck         return NULL;
3539c2c66affSColin Finck     }
3540c2c66affSColin Finck     return pEntryHandle;
3541c2c66affSColin Finck }
3542c2c66affSColin Finck 
urlcache_find_next_entry(HANDLE hEnumHandle,LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,LPDWORD lpdwNextCacheEntryInfoBufferSize,BOOL unicode)3543c2c66affSColin Finck static BOOL urlcache_find_next_entry(
3544c2c66affSColin Finck   HANDLE hEnumHandle,
3545c2c66affSColin Finck   LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3546c2c66affSColin Finck   LPDWORD lpdwNextCacheEntryInfoBufferSize,
3547c2c66affSColin Finck   BOOL unicode)
3548c2c66affSColin Finck {
3549c2c66affSColin Finck     find_handle *pEntryHandle = (find_handle*)hEnumHandle;
3550c2c66affSColin Finck     cache_container *pContainer;
3551c2c66affSColin Finck 
3552c2c66affSColin Finck     if (pEntryHandle->magic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3553c2c66affSColin Finck     {
3554c2c66affSColin Finck         SetLastError(ERROR_INVALID_HANDLE);
3555c2c66affSColin Finck         return FALSE;
3556c2c66affSColin Finck     }
3557c2c66affSColin Finck 
3558c2c66affSColin Finck     for (; cache_containers_enum(pEntryHandle->url_search_pattern, pEntryHandle->container_idx, &pContainer);
3559c2c66affSColin Finck          pEntryHandle->container_idx++, pEntryHandle->hash_table_idx = 0)
3560c2c66affSColin Finck     {
3561c2c66affSColin Finck         urlcache_header *pHeader;
3562c2c66affSColin Finck         entry_hash_table *pHashTableEntry;
3563c2c66affSColin Finck         DWORD error;
3564c2c66affSColin Finck 
3565c2c66affSColin Finck         error = cache_container_open_index(pContainer, MIN_BLOCK_NO);
3566c2c66affSColin Finck         if (error != ERROR_SUCCESS)
3567c2c66affSColin Finck         {
3568c2c66affSColin Finck             SetLastError(error);
3569c2c66affSColin Finck             return FALSE;
3570c2c66affSColin Finck         }
3571c2c66affSColin Finck 
3572c2c66affSColin Finck         if (!(pHeader = cache_container_lock_index(pContainer)))
3573c2c66affSColin Finck             return FALSE;
3574c2c66affSColin Finck 
3575c2c66affSColin Finck         for (; urlcache_enum_hash_tables(pHeader, &pEntryHandle->hash_table_idx, &pHashTableEntry);
3576c2c66affSColin Finck              pEntryHandle->hash_table_idx++, pEntryHandle->hash_entry_idx = 0)
3577c2c66affSColin Finck         {
3578c2c66affSColin Finck             const struct hash_entry *pHashEntry = NULL;
3579c2c66affSColin Finck             for (; urlcache_enum_hash_table_entries(pHeader, pHashTableEntry, &pEntryHandle->hash_entry_idx, &pHashEntry);
3580c2c66affSColin Finck                  pEntryHandle->hash_entry_idx++)
3581c2c66affSColin Finck             {
3582c2c66affSColin Finck                 const entry_url *pUrlEntry;
3583c2c66affSColin Finck                 const entry_header *pEntry = (const entry_header*)((LPBYTE)pHeader + pHashEntry->offset);
3584c2c66affSColin Finck 
3585c2c66affSColin Finck                 if (pEntry->signature != URL_SIGNATURE)
3586c2c66affSColin Finck                     continue;
3587c2c66affSColin Finck 
3588c2c66affSColin Finck                 pUrlEntry = (const entry_url *)pEntry;
3589c2c66affSColin Finck                 TRACE("Found URL: %s\n",
3590c2c66affSColin Finck                       debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->url_off));
3591c2c66affSColin Finck                 TRACE("Header info: %s\n",
3592c2c66affSColin Finck                         debugstr_an((LPCSTR)pUrlEntry + pUrlEntry->header_info_off,
3593c2c66affSColin Finck                             pUrlEntry->header_info_size));
3594c2c66affSColin Finck 
3595c2c66affSColin Finck                 error = urlcache_copy_entry(
3596c2c66affSColin Finck                     pContainer,
3597c2c66affSColin Finck                     pHeader,
3598c2c66affSColin Finck                     lpNextCacheEntryInfo,
3599c2c66affSColin Finck                     lpdwNextCacheEntryInfoBufferSize,
3600c2c66affSColin Finck                     pUrlEntry,
3601c2c66affSColin Finck                     unicode);
3602c2c66affSColin Finck                 if (error != ERROR_SUCCESS)
3603c2c66affSColin Finck                 {
3604c2c66affSColin Finck                     cache_container_unlock_index(pContainer, pHeader);
3605c2c66affSColin Finck                     SetLastError(error);
3606c2c66affSColin Finck                     return FALSE;
3607c2c66affSColin Finck                 }
3608c2c66affSColin Finck                 if(pUrlEntry->local_name_off)
3609c2c66affSColin Finck                     TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->local_name_off));
3610c2c66affSColin Finck 
3611c2c66affSColin Finck                 /* increment the current index so that next time the function
3612c2c66affSColin Finck                  * is called the next entry is returned */
3613c2c66affSColin Finck                 pEntryHandle->hash_entry_idx++;
3614c2c66affSColin Finck                 cache_container_unlock_index(pContainer, pHeader);
3615c2c66affSColin Finck                 return TRUE;
3616c2c66affSColin Finck             }
3617c2c66affSColin Finck         }
3618c2c66affSColin Finck 
3619c2c66affSColin Finck         cache_container_unlock_index(pContainer, pHeader);
3620c2c66affSColin Finck     }
3621c2c66affSColin Finck 
3622c2c66affSColin Finck     SetLastError(ERROR_NO_MORE_ITEMS);
3623c2c66affSColin Finck     return FALSE;
3624c2c66affSColin Finck }
3625c2c66affSColin Finck 
3626c2c66affSColin Finck /***********************************************************************
3627c2c66affSColin Finck  *           FindNextUrlCacheEntryA (WININET.@)
3628c2c66affSColin Finck  */
FindNextUrlCacheEntryA(HANDLE hEnumHandle,LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,LPDWORD lpdwNextCacheEntryInfoBufferSize)3629c2c66affSColin Finck BOOL WINAPI FindNextUrlCacheEntryA(
3630c2c66affSColin Finck   HANDLE hEnumHandle,
3631c2c66affSColin Finck   LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo,
3632c2c66affSColin Finck   LPDWORD lpdwNextCacheEntryInfoBufferSize)
3633c2c66affSColin Finck {
3634c2c66affSColin Finck     TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3635c2c66affSColin Finck 
3636c2c66affSColin Finck     return urlcache_find_next_entry(hEnumHandle, lpNextCacheEntryInfo,
3637c2c66affSColin Finck             lpdwNextCacheEntryInfoBufferSize, FALSE /* not UNICODE */);
3638c2c66affSColin Finck }
3639c2c66affSColin Finck 
3640c2c66affSColin Finck /***********************************************************************
3641c2c66affSColin Finck  *           FindNextUrlCacheEntryW (WININET.@)
3642c2c66affSColin Finck  */
FindNextUrlCacheEntryW(HANDLE hEnumHandle,LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,LPDWORD lpdwNextCacheEntryInfoBufferSize)3643c2c66affSColin Finck BOOL WINAPI FindNextUrlCacheEntryW(
3644c2c66affSColin Finck   HANDLE hEnumHandle,
3645c2c66affSColin Finck   LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo,
3646c2c66affSColin Finck   LPDWORD lpdwNextCacheEntryInfoBufferSize
3647c2c66affSColin Finck )
3648c2c66affSColin Finck {
3649c2c66affSColin Finck     TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3650c2c66affSColin Finck 
3651c2c66affSColin Finck     return urlcache_find_next_entry(hEnumHandle,
3652c2c66affSColin Finck             (LPINTERNET_CACHE_ENTRY_INFOA)lpNextCacheEntryInfo,
3653c2c66affSColin Finck             lpdwNextCacheEntryInfoBufferSize, TRUE /* UNICODE */);
3654c2c66affSColin Finck }
3655c2c66affSColin Finck 
3656c2c66affSColin Finck /***********************************************************************
3657c2c66affSColin Finck  *           FindCloseUrlCache (WININET.@)
3658c2c66affSColin Finck  */
FindCloseUrlCache(HANDLE hEnumHandle)3659c2c66affSColin Finck BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle)
3660c2c66affSColin Finck {
3661c2c66affSColin Finck     find_handle *pEntryHandle = (find_handle*)hEnumHandle;
3662c2c66affSColin Finck 
3663c2c66affSColin Finck     TRACE("(%p)\n", hEnumHandle);
3664c2c66affSColin Finck 
3665c2c66affSColin Finck     if (!pEntryHandle || pEntryHandle->magic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC)
3666c2c66affSColin Finck     {
3667c2c66affSColin Finck         SetLastError(ERROR_INVALID_HANDLE);
3668c2c66affSColin Finck         return FALSE;
3669c2c66affSColin Finck     }
3670c2c66affSColin Finck 
3671c2c66affSColin Finck     pEntryHandle->magic = 0;
3672c2c66affSColin Finck     heap_free(pEntryHandle->url_search_pattern);
3673c2c66affSColin Finck     heap_free(pEntryHandle);
3674c2c66affSColin Finck     return TRUE;
3675c2c66affSColin Finck }
3676c2c66affSColin Finck 
FindFirstUrlCacheGroup(DWORD dwFlags,DWORD dwFilter,LPVOID lpSearchCondition,DWORD dwSearchCondition,GROUPID * lpGroupId,LPVOID lpReserved)3677c2c66affSColin Finck HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition,
3678c2c66affSColin Finck                                       DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved )
3679c2c66affSColin Finck {
3680c2c66affSColin Finck     FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition,
3681c2c66affSColin Finck           dwSearchCondition, lpGroupId, lpReserved);
3682c2c66affSColin Finck     return NULL;
3683c2c66affSColin Finck }
3684c2c66affSColin Finck 
FindNextUrlCacheEntryExA(HANDLE hEnumHandle,LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,LPDWORD lpdwFirstCacheEntryInfoBufferSize,LPVOID lpReserved,LPDWORD pcbReserved2,LPVOID lpReserved3)3685c2c66affSColin Finck BOOL WINAPI FindNextUrlCacheEntryExA(
3686c2c66affSColin Finck   HANDLE hEnumHandle,
3687c2c66affSColin Finck   LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo,
3688c2c66affSColin Finck   LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3689c2c66affSColin Finck   LPVOID lpReserved,
3690c2c66affSColin Finck   LPDWORD pcbReserved2,
3691c2c66affSColin Finck   LPVOID lpReserved3
3692c2c66affSColin Finck )
3693c2c66affSColin Finck {
3694c2c66affSColin Finck     FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3695c2c66affSColin Finck           lpReserved, pcbReserved2, lpReserved3);
3696c2c66affSColin Finck     return FALSE;
3697c2c66affSColin Finck }
3698c2c66affSColin Finck 
FindNextUrlCacheEntryExW(HANDLE hEnumHandle,LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,LPDWORD lpdwFirstCacheEntryInfoBufferSize,LPVOID lpReserved,LPDWORD pcbReserved2,LPVOID lpReserved3)3699c2c66affSColin Finck BOOL WINAPI FindNextUrlCacheEntryExW(
3700c2c66affSColin Finck   HANDLE hEnumHandle,
3701c2c66affSColin Finck   LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
3702c2c66affSColin Finck   LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3703c2c66affSColin Finck   LPVOID lpReserved,
3704c2c66affSColin Finck   LPDWORD pcbReserved2,
3705c2c66affSColin Finck   LPVOID lpReserved3
3706c2c66affSColin Finck )
3707c2c66affSColin Finck {
3708c2c66affSColin Finck     FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3709c2c66affSColin Finck           lpReserved, pcbReserved2, lpReserved3);
3710c2c66affSColin Finck     return FALSE;
3711c2c66affSColin Finck }
3712c2c66affSColin Finck 
FindNextUrlCacheGroup(HANDLE hFind,GROUPID * lpGroupId,LPVOID lpReserved)3713c2c66affSColin Finck BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved )
3714c2c66affSColin Finck {
3715c2c66affSColin Finck     FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved);
3716c2c66affSColin Finck     return FALSE;
3717c2c66affSColin Finck }
3718c2c66affSColin Finck 
3719c2c66affSColin Finck /***********************************************************************
3720c2c66affSColin Finck  *           CreateUrlCacheGroup (WININET.@)
3721c2c66affSColin Finck  *
3722c2c66affSColin Finck  */
CreateUrlCacheGroup(DWORD dwFlags,LPVOID lpReserved)3723c2c66affSColin Finck INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved)
3724c2c66affSColin Finck {
3725c2c66affSColin Finck   FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved);
3726c2c66affSColin Finck   return FALSE;
3727c2c66affSColin Finck }
3728c2c66affSColin Finck 
3729c2c66affSColin Finck /***********************************************************************
3730c2c66affSColin Finck  *           DeleteUrlCacheGroup (WININET.@)
3731c2c66affSColin Finck  *
3732c2c66affSColin Finck  */
DeleteUrlCacheGroup(GROUPID GroupId,DWORD dwFlags,LPVOID lpReserved)3733c2c66affSColin Finck BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved)
3734c2c66affSColin Finck {
3735c2c66affSColin Finck     FIXME("(0x%s, 0x%08x, %p) stub\n",
3736c2c66affSColin Finck           wine_dbgstr_longlong(GroupId), dwFlags, lpReserved);
3737c2c66affSColin Finck     return FALSE;
3738c2c66affSColin Finck }
3739c2c66affSColin Finck 
3740c2c66affSColin Finck /***********************************************************************
3741c2c66affSColin Finck  *           DeleteWpadCacheForNetworks (WININET.@)
3742c2c66affSColin Finck  *    Undocumented, added in IE8
3743c2c66affSColin Finck  */
DeleteWpadCacheForNetworks(DWORD unk1)3744c2c66affSColin Finck BOOL WINAPI DeleteWpadCacheForNetworks(DWORD unk1)
3745c2c66affSColin Finck {
3746c2c66affSColin Finck     FIXME("(%d) stub\n", unk1);
3747c2c66affSColin Finck     return FALSE;
3748c2c66affSColin Finck }
3749c2c66affSColin Finck 
3750c2c66affSColin Finck /***********************************************************************
3751c2c66affSColin Finck  *           SetUrlCacheEntryGroupA (WININET.@)
3752c2c66affSColin Finck  *
3753c2c66affSColin Finck  */
SetUrlCacheEntryGroupA(LPCSTR lpszUrlName,DWORD dwFlags,GROUPID GroupId,LPBYTE pbGroupAttributes,DWORD cbGroupAttributes,LPVOID lpReserved)3754c2c66affSColin Finck BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags,
3755c2c66affSColin Finck   GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3756c2c66affSColin Finck   LPVOID lpReserved)
3757c2c66affSColin Finck {
3758c2c66affSColin Finck     FIXME("(%s, 0x%08x, 0x%s, %p, 0x%08x, %p) stub\n",
3759c2c66affSColin Finck           debugstr_a(lpszUrlName), dwFlags, wine_dbgstr_longlong(GroupId),
3760c2c66affSColin Finck           pbGroupAttributes, cbGroupAttributes, lpReserved);
3761c2c66affSColin Finck     SetLastError(ERROR_FILE_NOT_FOUND);
3762c2c66affSColin Finck     return FALSE;
3763c2c66affSColin Finck }
3764c2c66affSColin Finck 
3765c2c66affSColin Finck /***********************************************************************
3766c2c66affSColin Finck  *           SetUrlCacheEntryGroupW (WININET.@)
3767c2c66affSColin Finck  *
3768c2c66affSColin Finck  */
SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName,DWORD dwFlags,GROUPID GroupId,LPBYTE pbGroupAttributes,DWORD cbGroupAttributes,LPVOID lpReserved)3769c2c66affSColin Finck BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags,
3770c2c66affSColin Finck   GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes,
3771c2c66affSColin Finck   LPVOID lpReserved)
3772c2c66affSColin Finck {
3773c2c66affSColin Finck     FIXME("(%s, 0x%08x, 0x%s, %p, 0x%08x, %p) stub\n",
3774c2c66affSColin Finck           debugstr_w(lpszUrlName), dwFlags, wine_dbgstr_longlong(GroupId),
3775c2c66affSColin Finck           pbGroupAttributes, cbGroupAttributes, lpReserved);
3776c2c66affSColin Finck     SetLastError(ERROR_FILE_NOT_FOUND);
3777c2c66affSColin Finck     return FALSE;
3778c2c66affSColin Finck }
3779c2c66affSColin Finck 
find_container(DWORD flags)3780c239cdd4SAmine Khaldi static cache_container *find_container(DWORD flags)
3781c239cdd4SAmine Khaldi {
3782c239cdd4SAmine Khaldi     cache_container *container;
3783c239cdd4SAmine Khaldi 
3784c239cdd4SAmine Khaldi     LIST_FOR_EACH_ENTRY(container, &UrlContainers, cache_container, entry)
3785c239cdd4SAmine Khaldi     {
3786c239cdd4SAmine Khaldi         switch (flags & (CACHE_CONFIG_CONTENT_PATHS_FC | CACHE_CONFIG_COOKIES_PATHS_FC | CACHE_CONFIG_HISTORY_PATHS_FC))
3787c239cdd4SAmine Khaldi         {
3788c239cdd4SAmine Khaldi         case 0:
3789c239cdd4SAmine Khaldi         case CACHE_CONFIG_CONTENT_PATHS_FC:
3790c239cdd4SAmine Khaldi             if (container->default_entry_type == NORMAL_CACHE_ENTRY)
3791c239cdd4SAmine Khaldi                 return container;
3792c239cdd4SAmine Khaldi             break;
3793c239cdd4SAmine Khaldi 
3794c239cdd4SAmine Khaldi         case CACHE_CONFIG_COOKIES_PATHS_FC:
3795c239cdd4SAmine Khaldi             if (container->default_entry_type == COOKIE_CACHE_ENTRY)
3796c239cdd4SAmine Khaldi                 return container;
3797c239cdd4SAmine Khaldi             break;
3798c239cdd4SAmine Khaldi 
3799c239cdd4SAmine Khaldi         case CACHE_CONFIG_HISTORY_PATHS_FC:
3800c239cdd4SAmine Khaldi             if (container->default_entry_type == URLHISTORY_CACHE_ENTRY)
3801c239cdd4SAmine Khaldi                 return container;
3802c239cdd4SAmine Khaldi             break;
3803c239cdd4SAmine Khaldi 
3804c239cdd4SAmine Khaldi         default:
3805c239cdd4SAmine Khaldi             FIXME("flags %08x not handled\n", flags);
3806c239cdd4SAmine Khaldi             break;
3807c239cdd4SAmine Khaldi         }
3808c239cdd4SAmine Khaldi     }
3809c239cdd4SAmine Khaldi 
3810c239cdd4SAmine Khaldi     return NULL;
3811c239cdd4SAmine Khaldi }
3812c239cdd4SAmine Khaldi 
3813c2c66affSColin Finck /***********************************************************************
3814c2c66affSColin Finck  *           GetUrlCacheConfigInfoW (WININET.@)
3815c2c66affSColin Finck  */
GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW info,LPDWORD size,DWORD flags)3816c239cdd4SAmine Khaldi BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW info, LPDWORD size, DWORD flags)
3817c2c66affSColin Finck {
3818c239cdd4SAmine Khaldi     cache_container *container;
3819c239cdd4SAmine Khaldi     DWORD error;
3820c239cdd4SAmine Khaldi 
3821c239cdd4SAmine Khaldi     FIXME("(%p, %p, %x): semi-stub\n", info, size, flags);
3822c239cdd4SAmine Khaldi 
3823c239cdd4SAmine Khaldi     if (!info || !(container = find_container(flags)))
3824c239cdd4SAmine Khaldi     {
3825c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3826c2c66affSColin Finck         return FALSE;
3827c2c66affSColin Finck     }
3828c2c66affSColin Finck 
3829c239cdd4SAmine Khaldi     error = cache_container_open_index(container, MIN_BLOCK_NO);
3830c239cdd4SAmine Khaldi     if (error != ERROR_SUCCESS)
3831c239cdd4SAmine Khaldi     {
3832c239cdd4SAmine Khaldi         INTERNET_SetLastError(error);
3833c239cdd4SAmine Khaldi         return FALSE;
3834c239cdd4SAmine Khaldi     }
3835c239cdd4SAmine Khaldi 
3836c239cdd4SAmine Khaldi     info->dwContainer = 0;
3837c239cdd4SAmine Khaldi     info->dwQuota = FILE_SIZE(MAX_BLOCK_NO) / 1024;
3838c239cdd4SAmine Khaldi     info->dwReserved4 = 0;
3839c239cdd4SAmine Khaldi     info->fPerUser = TRUE;
3840c239cdd4SAmine Khaldi     info->dwSyncMode = 0;
3841c239cdd4SAmine Khaldi     info->dwNumCachePaths = 1;
3842c239cdd4SAmine Khaldi     info->dwNormalUsage = 0;
3843c239cdd4SAmine Khaldi     info->dwExemptUsage = 0;
3844c239cdd4SAmine Khaldi     info->u.s.dwCacheSize = container->file_size / 1024;
3845c239cdd4SAmine Khaldi     lstrcpynW(info->u.s.CachePath, container->path, MAX_PATH);
3846c239cdd4SAmine Khaldi 
3847c239cdd4SAmine Khaldi     cache_container_close_index(container);
3848c239cdd4SAmine Khaldi 
3849c239cdd4SAmine Khaldi     TRACE("CachePath %s\n", debugstr_w(info->u.s.CachePath));
3850c239cdd4SAmine Khaldi 
3851c239cdd4SAmine Khaldi     return TRUE;
3852c239cdd4SAmine Khaldi }
3853c239cdd4SAmine Khaldi 
3854c2c66affSColin Finck /***********************************************************************
3855c2c66affSColin Finck  *           GetUrlCacheConfigInfoA (WININET.@)
3856c2c66affSColin Finck  */
GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA info,LPDWORD size,DWORD flags)3857c239cdd4SAmine Khaldi BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA info, LPDWORD size, DWORD flags)
3858c2c66affSColin Finck {
3859c239cdd4SAmine Khaldi     INTERNET_CACHE_CONFIG_INFOW infoW;
3860c239cdd4SAmine Khaldi 
3861c239cdd4SAmine Khaldi     TRACE("(%p, %p, %x)\n", info, size, flags);
3862c239cdd4SAmine Khaldi 
3863c239cdd4SAmine Khaldi     if (!info)
3864c239cdd4SAmine Khaldi     {
3865c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3866c2c66affSColin Finck         return FALSE;
3867c2c66affSColin Finck     }
3868c2c66affSColin Finck 
3869c239cdd4SAmine Khaldi     infoW.dwStructSize = sizeof(infoW);
3870c239cdd4SAmine Khaldi     if (!GetUrlCacheConfigInfoW(&infoW, size, flags))
3871c239cdd4SAmine Khaldi         return FALSE;
3872c239cdd4SAmine Khaldi 
3873c239cdd4SAmine Khaldi     info->dwContainer = infoW.dwContainer;
3874c239cdd4SAmine Khaldi     info->dwQuota = infoW.dwQuota;
3875c239cdd4SAmine Khaldi     info->dwReserved4 = infoW.dwReserved4;
3876c239cdd4SAmine Khaldi     info->fPerUser = infoW.fPerUser;
3877c239cdd4SAmine Khaldi     info->dwSyncMode = infoW.dwSyncMode;
3878c239cdd4SAmine Khaldi     info->dwNumCachePaths = infoW.dwNumCachePaths;
3879c239cdd4SAmine Khaldi     info->dwNormalUsage = infoW.dwNormalUsage;
3880c239cdd4SAmine Khaldi     info->dwExemptUsage = infoW.dwExemptUsage;
3881c239cdd4SAmine Khaldi     info->u.s.dwCacheSize = infoW.u.s.dwCacheSize;
3882c239cdd4SAmine Khaldi     WideCharToMultiByte(CP_ACP, 0, infoW.u.s.CachePath, -1, info->u.s.CachePath, MAX_PATH, NULL, NULL);
3883c239cdd4SAmine Khaldi 
3884c239cdd4SAmine Khaldi     return TRUE;
3885c239cdd4SAmine Khaldi }
3886c239cdd4SAmine Khaldi 
GetUrlCacheGroupAttributeA(GROUPID gid,DWORD dwFlags,DWORD dwAttributes,LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,LPDWORD lpdwGroupInfo,LPVOID lpReserved)3887c2c66affSColin Finck BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3888c2c66affSColin Finck                                         LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,
3889c2c66affSColin Finck                                         LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3890c2c66affSColin Finck {
3891c2c66affSColin Finck     FIXME("(0x%s, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3892c2c66affSColin Finck           wine_dbgstr_longlong(gid), dwFlags, dwAttributes, lpGroupInfo,
3893c2c66affSColin Finck           lpdwGroupInfo, lpReserved);
3894c2c66affSColin Finck     return FALSE;
3895c2c66affSColin Finck }
3896c2c66affSColin Finck 
GetUrlCacheGroupAttributeW(GROUPID gid,DWORD dwFlags,DWORD dwAttributes,LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,LPDWORD lpdwGroupInfo,LPVOID lpReserved)3897c2c66affSColin Finck BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3898c2c66affSColin Finck                                         LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
3899c2c66affSColin Finck                                         LPDWORD lpdwGroupInfo, LPVOID lpReserved )
3900c2c66affSColin Finck {
3901c2c66affSColin Finck     FIXME("(0x%s, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3902c2c66affSColin Finck           wine_dbgstr_longlong(gid), dwFlags, dwAttributes, lpGroupInfo,
3903c2c66affSColin Finck           lpdwGroupInfo, lpReserved);
3904c2c66affSColin Finck     return FALSE;
3905c2c66affSColin Finck }
3906c2c66affSColin Finck 
SetUrlCacheGroupAttributeA(GROUPID gid,DWORD dwFlags,DWORD dwAttributes,LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo,LPVOID lpReserved)3907c2c66affSColin Finck BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3908c2c66affSColin Finck                                         LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved )
3909c2c66affSColin Finck {
3910c2c66affSColin Finck     FIXME("(0x%s, 0x%08x, 0x%08x, %p, %p) stub\n",
3911c2c66affSColin Finck           wine_dbgstr_longlong(gid), dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3912c2c66affSColin Finck     return TRUE;
3913c2c66affSColin Finck }
3914c2c66affSColin Finck 
SetUrlCacheGroupAttributeW(GROUPID gid,DWORD dwFlags,DWORD dwAttributes,LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,LPVOID lpReserved)3915c2c66affSColin Finck BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes,
3916c2c66affSColin Finck                                         LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved )
3917c2c66affSColin Finck {
3918c2c66affSColin Finck     FIXME("(0x%s, 0x%08x, 0x%08x, %p, %p) stub\n",
3919c2c66affSColin Finck           wine_dbgstr_longlong(gid), dwFlags, dwAttributes, lpGroupInfo, lpReserved);
3920c2c66affSColin Finck     return TRUE;
3921c2c66affSColin Finck }
3922c2c66affSColin Finck 
SetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo,DWORD dwFieldControl)3923c2c66affSColin Finck BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl )
3924c2c66affSColin Finck {
3925c2c66affSColin Finck     FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3926c2c66affSColin Finck     return TRUE;
3927c2c66affSColin Finck }
3928c2c66affSColin Finck 
SetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo,DWORD dwFieldControl)3929c2c66affSColin Finck BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl )
3930c2c66affSColin Finck {
3931c2c66affSColin Finck     FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3932c2c66affSColin Finck     return TRUE;
3933c2c66affSColin Finck }
3934c2c66affSColin Finck 
3935c2c66affSColin Finck /***********************************************************************
3936c2c66affSColin Finck  *           DeleteIE3Cache (WININET.@)
3937c2c66affSColin Finck  *
3938c2c66affSColin Finck  * Deletes the files used by the IE3 URL caching system.
3939c2c66affSColin Finck  *
3940c2c66affSColin Finck  * PARAMS
3941c2c66affSColin Finck  *   hWnd        [I] A dummy window.
3942c2c66affSColin Finck  *   hInst       [I] Instance of process calling the function.
3943c2c66affSColin Finck  *   lpszCmdLine [I] Options used by function.
3944c2c66affSColin Finck  *   nCmdShow    [I] The nCmdShow value to use when showing windows created, if any.
3945c2c66affSColin Finck  */
DeleteIE3Cache(HWND hWnd,HINSTANCE hInst,LPSTR lpszCmdLine,int nCmdShow)3946c2c66affSColin Finck DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
3947c2c66affSColin Finck {
3948c2c66affSColin Finck     FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow);
3949c2c66affSColin Finck     return 0;
3950c2c66affSColin Finck }
3951c2c66affSColin Finck 
urlcache_entry_is_expired(const entry_url * pUrlEntry,FILETIME * pftLastModified)3952c2c66affSColin Finck static BOOL urlcache_entry_is_expired(const entry_url *pUrlEntry,
3953c2c66affSColin Finck         FILETIME *pftLastModified)
3954c2c66affSColin Finck {
3955c2c66affSColin Finck     BOOL ret;
3956c2c66affSColin Finck     FILETIME now, expired;
3957c2c66affSColin Finck 
3958c2c66affSColin Finck     *pftLastModified = pUrlEntry->modification_time;
3959c2c66affSColin Finck     GetSystemTimeAsFileTime(&now);
3960c2c66affSColin Finck     dos_date_time_to_file_time(pUrlEntry->expire_date,
3961c2c66affSColin Finck             pUrlEntry->expire_time, &expired);
3962c2c66affSColin Finck     /* If the expired time is 0, it's interpreted as not expired */
3963c2c66affSColin Finck     if (!expired.dwLowDateTime && !expired.dwHighDateTime)
3964c2c66affSColin Finck         ret = FALSE;
3965c2c66affSColin Finck     else
3966c2c66affSColin Finck         ret = CompareFileTime(&expired, &now) < 0;
3967c2c66affSColin Finck     return ret;
3968c2c66affSColin Finck }
3969c2c66affSColin Finck 
3970c2c66affSColin Finck /***********************************************************************
3971c2c66affSColin Finck  *           IsUrlCacheEntryExpiredA (WININET.@)
3972c2c66affSColin Finck  *
3973c2c66affSColin Finck  * PARAMS
3974c2c66affSColin Finck  *   url             [I] Url
3975c2c66affSColin Finck  *   dwFlags         [I] Unknown
3976c2c66affSColin Finck  *   pftLastModified [O] Last modified time
3977c2c66affSColin Finck  */
IsUrlCacheEntryExpiredA(LPCSTR url,DWORD dwFlags,FILETIME * pftLastModified)3978c2c66affSColin Finck BOOL WINAPI IsUrlCacheEntryExpiredA(LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified)
3979c2c66affSColin Finck {
3980c2c66affSColin Finck     urlcache_header *pHeader;
3981c2c66affSColin Finck     struct hash_entry *pHashEntry;
3982c2c66affSColin Finck     const entry_header *pEntry;
3983c2c66affSColin Finck     const entry_url * pUrlEntry;
3984c2c66affSColin Finck     cache_container *pContainer;
3985c2c66affSColin Finck     BOOL expired;
3986c2c66affSColin Finck 
3987c2c66affSColin Finck     TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified);
3988c2c66affSColin Finck 
3989c2c66affSColin Finck     if (!url || !pftLastModified)
3990c2c66affSColin Finck         return TRUE;
3991c2c66affSColin Finck     if (dwFlags)
3992c2c66affSColin Finck         FIXME("unknown flags 0x%08x\n", dwFlags);
3993c2c66affSColin Finck 
3994c2c66affSColin Finck     /* Any error implies that the URL is expired, i.e. not in the cache */
3995c2c66affSColin Finck     if (cache_containers_find(url, &pContainer))
3996c2c66affSColin Finck     {
3997c2c66affSColin Finck         memset(pftLastModified, 0, sizeof(*pftLastModified));
3998c2c66affSColin Finck         return TRUE;
3999c2c66affSColin Finck     }
4000c2c66affSColin Finck 
4001c2c66affSColin Finck     if (cache_container_open_index(pContainer, MIN_BLOCK_NO))
4002c2c66affSColin Finck     {
4003c2c66affSColin Finck         memset(pftLastModified, 0, sizeof(*pftLastModified));
4004c2c66affSColin Finck         return TRUE;
4005c2c66affSColin Finck     }
4006c2c66affSColin Finck 
4007c2c66affSColin Finck     if (!(pHeader = cache_container_lock_index(pContainer)))
4008c2c66affSColin Finck     {
4009c2c66affSColin Finck         memset(pftLastModified, 0, sizeof(*pftLastModified));
4010c2c66affSColin Finck         return TRUE;
4011c2c66affSColin Finck     }
4012c2c66affSColin Finck 
4013c2c66affSColin Finck     if (!urlcache_find_hash_entry(pHeader, url, &pHashEntry))
4014c2c66affSColin Finck     {
4015c2c66affSColin Finck         cache_container_unlock_index(pContainer, pHeader);
4016c2c66affSColin Finck         memset(pftLastModified, 0, sizeof(*pftLastModified));
4017c2c66affSColin Finck         TRACE("entry %s not found!\n", url);
4018c2c66affSColin Finck         return TRUE;
4019c2c66affSColin Finck     }
4020c2c66affSColin Finck 
4021c2c66affSColin Finck     pEntry = (const entry_header*)((LPBYTE)pHeader + pHashEntry->offset);
4022c2c66affSColin Finck     if (pEntry->signature != URL_SIGNATURE)
4023c2c66affSColin Finck     {
4024ef9a828eSwinesync         FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->signature, sizeof(DWORD)));
4025c2c66affSColin Finck         cache_container_unlock_index(pContainer, pHeader);
4026c2c66affSColin Finck         memset(pftLastModified, 0, sizeof(*pftLastModified));
4027c2c66affSColin Finck         return TRUE;
4028c2c66affSColin Finck     }
4029c2c66affSColin Finck 
4030c2c66affSColin Finck     pUrlEntry = (const entry_url *)pEntry;
4031c2c66affSColin Finck     expired = urlcache_entry_is_expired(pUrlEntry, pftLastModified);
4032c2c66affSColin Finck 
4033c2c66affSColin Finck     cache_container_unlock_index(pContainer, pHeader);
4034c2c66affSColin Finck 
4035c2c66affSColin Finck     return expired;
4036c2c66affSColin Finck }
4037c2c66affSColin Finck 
4038c2c66affSColin Finck /***********************************************************************
4039c2c66affSColin Finck  *           IsUrlCacheEntryExpiredW (WININET.@)
4040c2c66affSColin Finck  *
4041c2c66affSColin Finck  * PARAMS
4042c2c66affSColin Finck  *   url             [I] Url
4043c2c66affSColin Finck  *   dwFlags         [I] Unknown
4044c2c66affSColin Finck  *   pftLastModified [O] Last modified time
4045c2c66affSColin Finck  */
IsUrlCacheEntryExpiredW(LPCWSTR url,DWORD dwFlags,FILETIME * pftLastModified)4046c2c66affSColin Finck BOOL WINAPI IsUrlCacheEntryExpiredW(LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified)
4047c2c66affSColin Finck {
4048c2c66affSColin Finck     char *encoded_url;
4049c2c66affSColin Finck     BOOL ret;
4050c2c66affSColin Finck 
4051c2c66affSColin Finck     if(!urlcache_encode_url_alloc(url, &encoded_url))
4052c2c66affSColin Finck         return FALSE;
4053c2c66affSColin Finck 
4054c2c66affSColin Finck     ret = IsUrlCacheEntryExpiredA(encoded_url, dwFlags, pftLastModified);
4055c2c66affSColin Finck     heap_free(encoded_url);
4056c2c66affSColin Finck     return ret;
4057c2c66affSColin Finck }
4058c2c66affSColin Finck 
4059c2c66affSColin Finck /***********************************************************************
4060c2c66affSColin Finck  *           GetDiskInfoA (WININET.@)
4061c2c66affSColin Finck  */
GetDiskInfoA(PCSTR path,PDWORD cluster_size,PDWORDLONG free,PDWORDLONG total)4062c2c66affSColin Finck BOOL WINAPI GetDiskInfoA(PCSTR path, PDWORD cluster_size, PDWORDLONG free, PDWORDLONG total)
4063c2c66affSColin Finck {
4064c2c66affSColin Finck     BOOL ret;
4065c2c66affSColin Finck     ULARGE_INTEGER bytes_free, bytes_total;
4066c2c66affSColin Finck 
4067c2c66affSColin Finck     TRACE("(%s, %p, %p, %p)\n", debugstr_a(path), cluster_size, free, total);
4068c2c66affSColin Finck 
4069c2c66affSColin Finck     if (!path)
4070c2c66affSColin Finck     {
4071c2c66affSColin Finck         SetLastError(ERROR_INVALID_PARAMETER);
4072c2c66affSColin Finck         return FALSE;
4073c2c66affSColin Finck     }
4074c2c66affSColin Finck 
4075c2c66affSColin Finck     if ((ret = GetDiskFreeSpaceExA(path, NULL, &bytes_total, &bytes_free)))
4076c2c66affSColin Finck     {
4077c2c66affSColin Finck         if (cluster_size) *cluster_size = 1;
4078c2c66affSColin Finck         if (free) *free = bytes_free.QuadPart;
4079c2c66affSColin Finck         if (total) *total = bytes_total.QuadPart;
4080c2c66affSColin Finck     }
4081c2c66affSColin Finck     return ret;
4082c2c66affSColin Finck }
4083c2c66affSColin Finck 
4084c2c66affSColin Finck /***********************************************************************
4085c2c66affSColin Finck  *           RegisterUrlCacheNotification (WININET.@)
4086c2c66affSColin Finck  */
RegisterUrlCacheNotification(LPVOID a,DWORD b,DWORD c,DWORD d,DWORD e,DWORD f)4087c2c66affSColin Finck DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
4088c2c66affSColin Finck {
4089c2c66affSColin Finck     FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f);
4090c2c66affSColin Finck     return 0;
4091c2c66affSColin Finck }
4092c2c66affSColin Finck 
4093c2c66affSColin Finck /***********************************************************************
4094c2c66affSColin Finck  *           IncrementUrlCacheHeaderData (WININET.@)
4095c2c66affSColin Finck  */
IncrementUrlCacheHeaderData(DWORD index,LPDWORD data)4096c2c66affSColin Finck BOOL WINAPI IncrementUrlCacheHeaderData(DWORD index, LPDWORD data)
4097c2c66affSColin Finck {
4098c2c66affSColin Finck     FIXME("(%u, %p)\n", index, data);
4099c2c66affSColin Finck     return FALSE;
4100c2c66affSColin Finck }
4101c2c66affSColin Finck 
4102c2c66affSColin Finck /***********************************************************************
4103c2c66affSColin Finck  *           RunOnceUrlCache (WININET.@)
4104c2c66affSColin Finck  */
4105c2c66affSColin Finck 
RunOnceUrlCache(HWND hwnd,HINSTANCE hinst,LPSTR cmd,int cmdshow)4106c2c66affSColin Finck DWORD WINAPI RunOnceUrlCache(HWND hwnd, HINSTANCE hinst, LPSTR cmd, int cmdshow)
4107c2c66affSColin Finck {
4108c2c66affSColin Finck     FIXME("(%p, %p, %s, %d): stub\n", hwnd, hinst, debugstr_a(cmd), cmdshow);
4109c2c66affSColin Finck     return 0;
4110c2c66affSColin Finck }
4111c2c66affSColin Finck 
init_urlcache(void)4112c2c66affSColin Finck BOOL init_urlcache(void)
4113c2c66affSColin Finck {
4114c2c66affSColin Finck     dll_unload_event = CreateEventW(NULL, FALSE, FALSE, NULL);
4115c2c66affSColin Finck     if(!dll_unload_event)
4116c2c66affSColin Finck         return FALSE;
4117c2c66affSColin Finck 
4118c2c66affSColin Finck     free_cache_running = CreateSemaphoreW(NULL, 1, 1, NULL);
4119c2c66affSColin Finck     if(!free_cache_running) {
4120c2c66affSColin Finck         CloseHandle(dll_unload_event);
4121c2c66affSColin Finck         return FALSE;
4122c2c66affSColin Finck     }
4123c2c66affSColin Finck 
4124c2c66affSColin Finck #ifndef __REACTOS__
4125c2c66affSColin Finck     cache_containers_init();
4126c2c66affSColin Finck #endif
4127c2c66affSColin Finck     return TRUE;
4128c2c66affSColin Finck }
4129c2c66affSColin Finck 
free_urlcache(void)4130c2c66affSColin Finck void free_urlcache(void)
4131c2c66affSColin Finck {
4132c2c66affSColin Finck     SetEvent(dll_unload_event);
4133c2c66affSColin Finck     WaitForSingleObject(free_cache_running, INFINITE);
4134c2c66affSColin Finck     ReleaseSemaphore(free_cache_running, 1, NULL);
4135c2c66affSColin Finck     CloseHandle(free_cache_running);
4136c2c66affSColin Finck     CloseHandle(dll_unload_event);
4137c2c66affSColin Finck 
4138c2c66affSColin Finck     cache_containers_free();
4139c2c66affSColin Finck }
4140c2c66affSColin Finck 
4141c2c66affSColin Finck /***********************************************************************
4142c2c66affSColin Finck  *           LoadUrlCacheContent (WININET.@)
4143c2c66affSColin Finck  */
LoadUrlCacheContent(void)4144c2c66affSColin Finck BOOL WINAPI LoadUrlCacheContent(void)
4145c2c66affSColin Finck {
4146c2c66affSColin Finck     FIXME("stub!\n");
4147c2c66affSColin Finck     return FALSE;
4148c2c66affSColin Finck }
4149