wininet: Do case-insensitive compare when looking for scheme.
[wine] / dlls / wininet / tests / urlcache.c
1 /*
2  * URL Cache Tests
3  *
4  * Copyright 2008 Robert Shearman for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wininet.h"
28 #include "winineti.h"
29
30 #include "wine/test.h"
31
32 static const char test_url[] = "http://urlcachetest.winehq.org/index.html";
33 static const WCHAR test_urlW[] = {'h','t','t','p',':','/','/','u','r','l','c','a','c','h','e','t','e','s','t','.',
34     'w','i','n','e','h','q','.','o','r','g','/','i','n','d','e','x','.','h','t','m','l',0};
35 static const char test_url1[] = "Visited: user@http://urlcachetest.winehq.org/index.html";
36 static const char test_hash_collisions1[] = "Visited: http://winehq.org/doc0.html";
37 static const char test_hash_collisions2[] = "Visited: http://winehq.org/doc75651909.html";
38
39 static BOOL (WINAPI *pDeleteUrlCacheEntryA)(LPCSTR);
40 static BOOL (WINAPI *pUnlockUrlCacheEntryFileA)(LPCSTR,DWORD);
41
42 static char filenameA[MAX_PATH + 1];
43 static char filenameA1[MAX_PATH + 1];
44 static BOOL old_ie = FALSE;
45
46 static void check_cache_entry_infoA(const char *returnedfrom, LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo)
47 {
48     ok(lpCacheEntryInfo->dwStructSize == sizeof(*lpCacheEntryInfo), "%s: dwStructSize was %d\n", returnedfrom, lpCacheEntryInfo->dwStructSize);
49     ok(!strcmp(lpCacheEntryInfo->lpszSourceUrlName, test_url), "%s: lpszSourceUrlName should be %s instead of %s\n", returnedfrom, test_url, lpCacheEntryInfo->lpszSourceUrlName);
50     ok(!strcmp(lpCacheEntryInfo->lpszLocalFileName, filenameA), "%s: lpszLocalFileName should be %s instead of %s\n", returnedfrom, filenameA, lpCacheEntryInfo->lpszLocalFileName);
51     ok(!strcmp(lpCacheEntryInfo->lpszFileExtension, "html"), "%s: lpszFileExtension should be html instead of %s\n", returnedfrom, lpCacheEntryInfo->lpszFileExtension);
52 }
53
54 static void test_find_url_cache_entriesA(void)
55 {
56     BOOL ret;
57     HANDLE hEnumHandle;
58     BOOL found = FALSE;
59     DWORD cbCacheEntryInfo;
60     DWORD cbCacheEntryInfoSaved;
61     LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo;
62
63     cbCacheEntryInfo = 0;
64     SetLastError(0xdeadbeef);
65     hEnumHandle = FindFirstUrlCacheEntry(NULL, NULL, &cbCacheEntryInfo);
66     ok(!hEnumHandle, "FindFirstUrlCacheEntry should have failed\n");
67     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "FindFirstUrlCacheEntry should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError());
68     lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo * sizeof(char));
69     cbCacheEntryInfoSaved = cbCacheEntryInfo;
70     hEnumHandle = FindFirstUrlCacheEntry(NULL, lpCacheEntryInfo, &cbCacheEntryInfo);
71     ok(hEnumHandle != NULL, "FindFirstUrlCacheEntry failed with error %d\n", GetLastError());
72     while (TRUE)
73     {
74         if (!strcmp(lpCacheEntryInfo->lpszSourceUrlName, test_url))
75         {
76             found = TRUE;
77             ret = TRUE;
78             break;
79         }
80         SetLastError(0xdeadbeef);
81         cbCacheEntryInfo = cbCacheEntryInfoSaved;
82         ret = FindNextUrlCacheEntry(hEnumHandle, lpCacheEntryInfo, &cbCacheEntryInfo);
83         if (!ret)
84         {
85             if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
86             {
87                 lpCacheEntryInfo = HeapReAlloc(GetProcessHeap(), 0, lpCacheEntryInfo, cbCacheEntryInfo);
88                 cbCacheEntryInfoSaved = cbCacheEntryInfo;
89                 ret = FindNextUrlCacheEntry(hEnumHandle, lpCacheEntryInfo, &cbCacheEntryInfo);
90             }
91         }
92         if (!ret)
93             break;
94     }
95     ok(ret, "FindNextUrlCacheEntry failed with error %d\n", GetLastError());
96     ok(found, "Committed url cache entry not found during enumeration\n");
97
98     ret = FindCloseUrlCache(hEnumHandle);
99     ok(ret, "FindCloseUrlCache failed with error %d\n", GetLastError());
100 }
101
102 static void test_GetUrlCacheEntryInfoExA(void)
103 {
104     BOOL ret;
105     DWORD cbCacheEntryInfo, cbRedirectUrl;
106     LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo;
107
108     SetLastError(0xdeadbeef);
109     ret = GetUrlCacheEntryInfoEx(NULL, NULL, NULL, NULL, NULL, NULL, 0);
110     ok(!ret, "GetUrlCacheEntryInfoEx with NULL URL and NULL args should have failed\n");
111     ok(GetLastError() == ERROR_INVALID_PARAMETER,
112        "GetUrlCacheEntryInfoEx with NULL URL and NULL args should have set last error to ERROR_INVALID_PARAMETER instead of %d\n", GetLastError());
113
114     cbCacheEntryInfo = sizeof(INTERNET_CACHE_ENTRY_INFO);
115     SetLastError(0xdeadbeef);
116     ret = GetUrlCacheEntryInfoEx("", NULL, &cbCacheEntryInfo, NULL, NULL, NULL, 0);
117     ok(!ret, "GetUrlCacheEntryInfoEx with zero-length buffer should fail\n");
118     ok(GetLastError() == ERROR_FILE_NOT_FOUND,
119        "GetUrlCacheEntryInfoEx should have set last error to ERROR_FILE_NOT_FOUND instead of %d\n", GetLastError());
120
121     ret = GetUrlCacheEntryInfoEx(test_url, NULL, NULL, NULL, NULL, NULL, 0);
122     ok(ret, "GetUrlCacheEntryInfoEx with NULL args failed with error %d\n", GetLastError());
123
124     cbCacheEntryInfo = 0;
125     SetLastError(0xdeadbeef);
126     ret = GetUrlCacheEntryInfoEx(test_url, NULL, &cbCacheEntryInfo, NULL, NULL, NULL, 0);
127     ok(!ret, "GetUrlCacheEntryInfoEx with zero-length buffer should fail\n");
128     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
129        "GetUrlCacheEntryInfoEx should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError());
130
131     lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo);
132
133     SetLastError(0xdeadbeef);
134     ret = GetUrlCacheEntryInfoEx(test_url, NULL, NULL, NULL, NULL, NULL, 0x200 /*GET_INSTALLED_ENTRY*/);
135     ok(!ret, "GetUrlCacheEntryInfoEx succeeded\n");
136     ok(GetLastError() == ERROR_FILE_NOT_FOUND,
137        "GetUrlCacheEntryInfoEx should have set last error to ERROR_FILE_NOT_FOUND instead of %d\n", GetLastError());
138
139     /* Unicode version of function seems to ignore 0x200 flag */
140     ret = GetUrlCacheEntryInfoExW(test_urlW, NULL, NULL, NULL, NULL, NULL, 0x200 /*GET_INSTALLED_ENTRY*/);
141     ok(ret || broken(old_ie && !ret), "GetUrlCacheEntryInfoExW failed with error %d\n", GetLastError());
142
143     ret = GetUrlCacheEntryInfoEx(test_url, lpCacheEntryInfo, &cbCacheEntryInfo, NULL, NULL, NULL, 0);
144     ok(ret, "GetUrlCacheEntryInfoEx failed with error %d\n", GetLastError());
145
146     if (ret) check_cache_entry_infoA("GetUrlCacheEntryInfoEx", lpCacheEntryInfo);
147
148     lpCacheEntryInfo->CacheEntryType |= 0x10000000; /* INSTALLED_CACHE_ENTRY */
149     ret = SetUrlCacheEntryInfoA(test_url, lpCacheEntryInfo, CACHE_ENTRY_ATTRIBUTE_FC);
150     ok(ret, "SetUrlCacheEntryInfoA failed with error %d\n", GetLastError());
151
152     SetLastError(0xdeadbeef);
153     ret = GetUrlCacheEntryInfoEx(test_url, NULL, NULL, NULL, NULL, NULL, 0x200 /*GET_INSTALLED_ENTRY*/);
154     ok(ret, "GetUrlCacheEntryInfoEx failed with error %d\n", GetLastError());
155
156     cbCacheEntryInfo = 100000;
157     SetLastError(0xdeadbeef);
158     ret = GetUrlCacheEntryInfoEx(test_url, NULL, &cbCacheEntryInfo, NULL, NULL, NULL, 0);
159     ok(!ret, "GetUrlCacheEntryInfoEx with zero-length buffer should fail\n");
160     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetUrlCacheEntryInfoEx should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError());
161
162     HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo);
163
164     /* Querying the redirect URL fails with ERROR_INVALID_PARAMETER */
165     SetLastError(0xdeadbeef);
166     ret = GetUrlCacheEntryInfoEx(test_url, NULL, NULL, NULL, &cbRedirectUrl, NULL, 0);
167     ok(!ret, "GetUrlCacheEntryInfoEx should have failed\n");
168     ok(GetLastError() == ERROR_INVALID_PARAMETER,
169        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
170     SetLastError(0xdeadbeef);
171     ret = GetUrlCacheEntryInfoEx(test_url, NULL, &cbCacheEntryInfo, NULL, &cbRedirectUrl, NULL, 0);
172     ok(!ret, "GetUrlCacheEntryInfoEx should have failed\n");
173     ok(GetLastError() == ERROR_INVALID_PARAMETER,
174        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
175 }
176
177 static void test_RetrieveUrlCacheEntryA(void)
178 {
179     BOOL ret;
180     DWORD cbCacheEntryInfo;
181
182     cbCacheEntryInfo = 0;
183     SetLastError(0xdeadbeef);
184     ret = RetrieveUrlCacheEntryFile(NULL, NULL, &cbCacheEntryInfo, 0);
185     ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n");
186     ok(GetLastError() == ERROR_INVALID_PARAMETER, "RetrieveUrlCacheEntryFile should have set last error to ERROR_INVALID_PARAMETER instead of %d\n", GetLastError());
187
188     if (0)
189     {
190         /* Crashes on Win9x, NT4 and W2K */
191         SetLastError(0xdeadbeef);
192         ret = RetrieveUrlCacheEntryFile(test_url, NULL, NULL, 0);
193         ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n");
194         ok(GetLastError() == ERROR_INVALID_PARAMETER, "RetrieveUrlCacheEntryFile should have set last error to ERROR_INVALID_PARAMETER instead of %d\n", GetLastError());
195     }
196
197     SetLastError(0xdeadbeef);
198     cbCacheEntryInfo = 100000;
199     ret = RetrieveUrlCacheEntryFile(NULL, NULL, &cbCacheEntryInfo, 0);
200     ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n");
201     ok(GetLastError() == ERROR_INVALID_PARAMETER, "RetrieveUrlCacheEntryFile should have set last error to ERROR_INVALID_PARAMETER instead of %d\n", GetLastError());
202 }
203
204 static void test_IsUrlCacheEntryExpiredA(void)
205 {
206     static const char uncached_url[] =
207         "What's the airspeed velocity of an unladen swallow?";
208     BOOL ret;
209     FILETIME ft;
210     DWORD size;
211     LPINTERNET_CACHE_ENTRY_INFO info;
212     ULARGE_INTEGER exp_time;
213
214     /* The function returns TRUE when the output time is NULL or the tested URL
215      * is NULL.
216      */
217     ret = IsUrlCacheEntryExpiredA(NULL, 0, NULL);
218     ok(ret, "expected TRUE\n");
219     ft.dwLowDateTime = 0xdeadbeef;
220     ft.dwHighDateTime = 0xbaadf00d;
221     ret = IsUrlCacheEntryExpiredA(NULL, 0, &ft);
222     ok(ret, "expected TRUE\n");
223     ok(ft.dwLowDateTime == 0xdeadbeef && ft.dwHighDateTime == 0xbaadf00d,
224        "expected time to be unchanged, got (%u,%u)\n",
225        ft.dwLowDateTime, ft.dwHighDateTime);
226     ret = IsUrlCacheEntryExpiredA(test_url, 0, NULL);
227     ok(ret, "expected TRUE\n");
228
229     /* The return value should indicate whether the URL is expired,
230      * and the filetime indicates the last modified time, but a cache entry
231      * with a zero expire time is "not expired".
232      */
233     ft.dwLowDateTime = 0xdeadbeef;
234     ft.dwHighDateTime = 0xbaadf00d;
235     ret = IsUrlCacheEntryExpiredA(test_url, 0, &ft);
236     ok(!ret, "expected FALSE\n");
237     ok(!ft.dwLowDateTime && !ft.dwHighDateTime,
238        "expected time (0,0), got (%u,%u)\n",
239        ft.dwLowDateTime, ft.dwHighDateTime);
240
241     /* Same behavior with bogus flags. */
242     ft.dwLowDateTime = 0xdeadbeef;
243     ft.dwHighDateTime = 0xbaadf00d;
244     ret = IsUrlCacheEntryExpiredA(test_url, 0xffffffff, &ft);
245     ok(!ret, "expected FALSE\n");
246     ok(!ft.dwLowDateTime && !ft.dwHighDateTime,
247        "expected time (0,0), got (%u,%u)\n",
248        ft.dwLowDateTime, ft.dwHighDateTime);
249
250     /* Set the expire time to a point in the past.. */
251     ret = GetUrlCacheEntryInfo(test_url, NULL, &size);
252     ok(!ret, "GetUrlCacheEntryInfo should have failed\n");
253     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
254        "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
255     info = HeapAlloc(GetProcessHeap(), 0, size);
256     ret = GetUrlCacheEntryInfo(test_url, info, &size);
257     ok(ret, "GetUrlCacheEntryInfo failed: %d\n", GetLastError());
258     GetSystemTimeAsFileTime(&info->ExpireTime);
259     exp_time.u.LowPart = info->ExpireTime.dwLowDateTime;
260     exp_time.u.HighPart = info->ExpireTime.dwHighDateTime;
261     exp_time.QuadPart -= 10 * 60 * (ULONGLONG)10000000;
262     info->ExpireTime.dwLowDateTime = exp_time.u.LowPart;
263     info->ExpireTime.dwHighDateTime = exp_time.u.HighPart;
264     ret = SetUrlCacheEntryInfo(test_url, info, CACHE_ENTRY_EXPTIME_FC);
265     ok(ret, "SetUrlCacheEntryInfo failed: %d\n", GetLastError());
266     ft.dwLowDateTime = 0xdeadbeef;
267     ft.dwHighDateTime = 0xbaadf00d;
268     /* and the entry should be expired. */
269     ret = IsUrlCacheEntryExpiredA(test_url, 0, &ft);
270     ok(ret, "expected TRUE\n");
271     /* The modified time returned is 0. */
272     ok(!ft.dwLowDateTime && !ft.dwHighDateTime,
273        "expected time (0,0), got (%u,%u)\n",
274        ft.dwLowDateTime, ft.dwHighDateTime);
275     /* Set the expire time to a point in the future.. */
276     exp_time.QuadPart += 20 * 60 * (ULONGLONG)10000000;
277     info->ExpireTime.dwLowDateTime = exp_time.u.LowPart;
278     info->ExpireTime.dwHighDateTime = exp_time.u.HighPart;
279     ret = SetUrlCacheEntryInfo(test_url, info, CACHE_ENTRY_EXPTIME_FC);
280     ok(ret, "SetUrlCacheEntryInfo failed: %d\n", GetLastError());
281     ft.dwLowDateTime = 0xdeadbeef;
282     ft.dwHighDateTime = 0xbaadf00d;
283     /* and the entry should no longer be expired. */
284     ret = IsUrlCacheEntryExpiredA(test_url, 0, &ft);
285     ok(!ret, "expected FALSE\n");
286     /* The modified time returned is still 0. */
287     ok(!ft.dwLowDateTime && !ft.dwHighDateTime,
288        "expected time (0,0), got (%u,%u)\n",
289        ft.dwLowDateTime, ft.dwHighDateTime);
290     /* Set the modified time... */
291     GetSystemTimeAsFileTime(&info->LastModifiedTime);
292     ret = SetUrlCacheEntryInfo(test_url, info, CACHE_ENTRY_MODTIME_FC);
293     ok(ret, "SetUrlCacheEntryInfo failed: %d\n", GetLastError());
294     /* and the entry should still be unexpired.. */
295     ret = IsUrlCacheEntryExpiredA(test_url, 0, &ft);
296     ok(!ret, "expected FALSE\n");
297     /* but the modified time returned is the last modified time just set. */
298     ok(ft.dwLowDateTime == info->LastModifiedTime.dwLowDateTime &&
299        ft.dwHighDateTime == info->LastModifiedTime.dwHighDateTime,
300        "expected time (%u,%u), got (%u,%u)\n",
301        info->LastModifiedTime.dwLowDateTime,
302        info->LastModifiedTime.dwHighDateTime,
303        ft.dwLowDateTime, ft.dwHighDateTime);
304     HeapFree(GetProcessHeap(), 0, info);
305
306     /* An uncached URL is implicitly expired, but with unknown time. */
307     ft.dwLowDateTime = 0xdeadbeef;
308     ft.dwHighDateTime = 0xbaadf00d;
309     ret = IsUrlCacheEntryExpiredA(uncached_url, 0, &ft);
310     ok(ret, "expected TRUE\n");
311     ok(!ft.dwLowDateTime && !ft.dwHighDateTime,
312        "expected time (0,0), got (%u,%u)\n",
313        ft.dwLowDateTime, ft.dwHighDateTime);
314 }
315
316 static void _check_file_exists(LONG l, LPCSTR filename)
317 {
318     HANDLE file;
319
320     file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
321                        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
322     ok_(__FILE__,l)(file != INVALID_HANDLE_VALUE,
323                     "expected file to exist, CreateFile failed with error %d\n",
324                     GetLastError());
325     CloseHandle(file);
326 }
327
328 #define check_file_exists(f) _check_file_exists(__LINE__, f)
329
330 static void _check_file_not_exists(LONG l, LPCSTR filename)
331 {
332     HANDLE file;
333
334     file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
335                        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
336     ok_(__FILE__,l)(file == INVALID_HANDLE_VALUE,
337                     "expected file not to exist\n");
338     if (file != INVALID_HANDLE_VALUE)
339         CloseHandle(file);
340 }
341
342 #define check_file_not_exists(f) _check_file_not_exists(__LINE__, f)
343
344 static void create_and_write_file(LPCSTR filename, void *data, DWORD len)
345 {
346     HANDLE file;
347     DWORD written;
348     BOOL ret;
349
350     file = CreateFileA(filename, GENERIC_WRITE,
351                        FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
352                        FILE_ATTRIBUTE_NORMAL, NULL);
353     ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed with error %d\n", GetLastError());
354
355     ret = WriteFile(file, data, len, &written, NULL);
356     ok(ret, "WriteFile failed with error %d\n", GetLastError());
357
358     CloseHandle(file);
359 }
360
361 static void test_urlcacheA(void)
362 {
363     static char ok_header[] = "HTTP/1.0 200 OK\r\n\r\n";
364     BOOL ret;
365     HANDLE hFile;
366     BYTE zero_byte = 0;
367     LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo;
368     LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo2;
369     DWORD cbCacheEntryInfo;
370     static const FILETIME filetime_zero;
371     FILETIME now;
372
373     ret = CreateUrlCacheEntry(test_url, 0, "html", filenameA, 0);
374     ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError());
375
376     ret = CreateUrlCacheEntry(test_url, 0, "html", filenameA1, 0);
377     ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError());
378     check_file_exists(filenameA1);
379     DeleteFileA(filenameA1);
380
381     ok(lstrcmpiA(filenameA, filenameA1), "expected a different file name\n");
382
383     create_and_write_file(filenameA, &zero_byte, sizeof(zero_byte));
384
385     ret = CommitUrlCacheEntry(test_url1, NULL, filetime_zero, filetime_zero, NORMAL_CACHE_ENTRY, NULL, 0, "html", NULL);
386     ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError());
387     cbCacheEntryInfo = 0;
388     ret = GetUrlCacheEntryInfo(test_url1, NULL, &cbCacheEntryInfo);
389     ok(!ret, "GetUrlCacheEntryInfo should have failed\n");
390     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
391        "GetUrlCacheEntryInfo should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError());
392     lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo);
393     ret = GetUrlCacheEntryInfo(test_url1, lpCacheEntryInfo, &cbCacheEntryInfo);
394     ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError());
395     ok(!memcmp(&lpCacheEntryInfo->ExpireTime, &filetime_zero, sizeof(FILETIME)),
396        "expected zero ExpireTime\n");
397     ok(!memcmp(&lpCacheEntryInfo->LastModifiedTime, &filetime_zero, sizeof(FILETIME)),
398        "expected zero LastModifiedTime\n");
399     ok(lpCacheEntryInfo->CacheEntryType == (NORMAL_CACHE_ENTRY|URLHISTORY_CACHE_ENTRY) ||
400        broken(lpCacheEntryInfo->CacheEntryType == NORMAL_CACHE_ENTRY /* NT4/W2k */),
401        "expected type NORMAL_CACHE_ENTRY|URLHISTORY_CACHE_ENTRY, got %08x\n",
402        lpCacheEntryInfo->CacheEntryType);
403     ok(!U(*lpCacheEntryInfo).dwExemptDelta, "expected dwExemptDelta 0, got %d\n",
404        U(*lpCacheEntryInfo).dwExemptDelta);
405
406     /* Make sure there is a notable change in timestamps */
407     Sleep(1000);
408
409     /* A subsequent commit with a different time/type doesn't change most of the entry */
410     GetSystemTimeAsFileTime(&now);
411     ret = CommitUrlCacheEntry(test_url1, NULL, now, now, NORMAL_CACHE_ENTRY,
412             (LPBYTE)ok_header, strlen(ok_header), NULL, NULL);
413     ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError());
414     cbCacheEntryInfo = 0;
415     ret = GetUrlCacheEntryInfo(test_url1, NULL, &cbCacheEntryInfo);
416     ok(!ret, "GetUrlCacheEntryInfo should have failed\n");
417     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
418        "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
419     lpCacheEntryInfo2 = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo);
420     ret = GetUrlCacheEntryInfo(test_url1, lpCacheEntryInfo2, &cbCacheEntryInfo);
421     ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError());
422     /* but it does change the time.. */
423     ok(memcmp(&lpCacheEntryInfo2->ExpireTime, &filetime_zero, sizeof(FILETIME)),
424        "expected positive ExpireTime\n");
425     ok(memcmp(&lpCacheEntryInfo2->LastModifiedTime, &filetime_zero, sizeof(FILETIME)),
426        "expected positive LastModifiedTime\n");
427     ok(lpCacheEntryInfo2->CacheEntryType == (NORMAL_CACHE_ENTRY|URLHISTORY_CACHE_ENTRY) ||
428        broken(lpCacheEntryInfo2->CacheEntryType == NORMAL_CACHE_ENTRY /* NT4/W2k */),
429        "expected type NORMAL_CACHE_ENTRY|URLHISTORY_CACHE_ENTRY, got %08x\n",
430        lpCacheEntryInfo2->CacheEntryType);
431     /* and set the headers. */
432     ok(lpCacheEntryInfo2->dwHeaderInfoSize == 19,
433         "expected headers size 19, got %d\n",
434         lpCacheEntryInfo2->dwHeaderInfoSize);
435     /* Hit rate gets incremented by 1 */
436     ok((lpCacheEntryInfo->dwHitRate + 1) == lpCacheEntryInfo2->dwHitRate,
437         "HitRate not incremented by one on commit\n");
438     /* Last access time should be updated */
439     ok(!(lpCacheEntryInfo->LastAccessTime.dwHighDateTime == lpCacheEntryInfo2->LastAccessTime.dwHighDateTime &&
440         lpCacheEntryInfo->LastAccessTime.dwLowDateTime == lpCacheEntryInfo2->LastAccessTime.dwLowDateTime),
441         "Last accessed time was not updated by commit\n");
442     /* File extension should be unset */
443     ok(lpCacheEntryInfo2->lpszFileExtension == NULL,
444         "Fileextension isn't unset: %s\n",
445         lpCacheEntryInfo2->lpszFileExtension);
446     HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo);
447     HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo2);
448
449     ret = CommitUrlCacheEntry(test_url, filenameA, filetime_zero, filetime_zero, NORMAL_CACHE_ENTRY, NULL, 0, "html", NULL);
450     ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError());
451
452     cbCacheEntryInfo = 0;
453     SetLastError(0xdeadbeef);
454     ret = RetrieveUrlCacheEntryFile(test_url, NULL, &cbCacheEntryInfo, 0);
455     ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n");
456     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
457        "RetrieveUrlCacheEntryFile should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError());
458
459     lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo);
460     ret = RetrieveUrlCacheEntryFile(test_url, lpCacheEntryInfo, &cbCacheEntryInfo, 0);
461     ok(ret, "RetrieveUrlCacheEntryFile failed with error %d\n", GetLastError());
462
463     if (ret) check_cache_entry_infoA("RetrieveUrlCacheEntryFile", lpCacheEntryInfo);
464
465     HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo);
466
467     cbCacheEntryInfo = 0;
468     SetLastError(0xdeadbeef);
469     ret = RetrieveUrlCacheEntryFile(test_url1, NULL, &cbCacheEntryInfo, 0);
470     ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n");
471     ok(GetLastError() == ERROR_INVALID_DATA,
472        "RetrieveUrlCacheEntryFile should have set last error to ERROR_INVALID_DATA instead of %d\n", GetLastError());
473
474     if (pUnlockUrlCacheEntryFileA)
475     {
476         ret = pUnlockUrlCacheEntryFileA(test_url, 0);
477         ok(ret, "UnlockUrlCacheEntryFileA failed with error %d\n", GetLastError());
478     }
479
480     /* test Find*UrlCacheEntry functions */
481     test_find_url_cache_entriesA();
482
483     test_GetUrlCacheEntryInfoExA();
484     test_RetrieveUrlCacheEntryA();
485     test_IsUrlCacheEntryExpiredA();
486
487     if (pDeleteUrlCacheEntryA)
488     {
489         ret = pDeleteUrlCacheEntryA(test_url);
490         ok(ret, "DeleteUrlCacheEntryA failed with error %d\n", GetLastError());
491         ret = pDeleteUrlCacheEntryA(test_url1);
492         ok(ret, "DeleteUrlCacheEntryA failed with error %d\n", GetLastError());
493     }
494
495     SetLastError(0xdeadbeef);
496     ret = DeleteFile(filenameA);
497     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, "local file should no longer exist\n");
498
499     /* Creating two entries with the same URL */
500     ret = CreateUrlCacheEntry(test_url, 0, "html", filenameA, 0);
501     ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError());
502
503     ret = CreateUrlCacheEntry(test_url, 0, "html", filenameA1, 0);
504     ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError());
505
506     ok(lstrcmpiA(filenameA, filenameA1), "expected a different file name\n");
507
508     create_and_write_file(filenameA, &zero_byte, sizeof(zero_byte));
509     create_and_write_file(filenameA1, &zero_byte, sizeof(zero_byte));
510     check_file_exists(filenameA);
511     check_file_exists(filenameA1);
512
513     ret = CommitUrlCacheEntry(test_url, filenameA, filetime_zero,
514             filetime_zero, NORMAL_CACHE_ENTRY, (LPBYTE)ok_header,
515             strlen(ok_header), "html", NULL);
516     ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError());
517     check_file_exists(filenameA);
518     check_file_exists(filenameA1);
519     ret = CommitUrlCacheEntry(test_url, filenameA1, filetime_zero,
520             filetime_zero, COOKIE_CACHE_ENTRY, NULL, 0, "html", NULL);
521     ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError());
522     /* By committing the same URL a second time, the prior entry is
523      * overwritten...
524      */
525     cbCacheEntryInfo = 0;
526     SetLastError(0xdeadbeef);
527     ret = GetUrlCacheEntryInfo(test_url, NULL, &cbCacheEntryInfo);
528     ok(!ret, "GetUrlCacheEntryInfo should have failed\n");
529     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
530        "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
531     lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo);
532     ret = GetUrlCacheEntryInfo(test_url, lpCacheEntryInfo, &cbCacheEntryInfo);
533     ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError());
534     /* with the previous entry type retained.. */
535     ok(lpCacheEntryInfo->CacheEntryType & NORMAL_CACHE_ENTRY,
536        "expected cache entry type NORMAL_CACHE_ENTRY, got %d (0x%08x)\n",
537        lpCacheEntryInfo->CacheEntryType, lpCacheEntryInfo->CacheEntryType);
538     /* and the headers overwritten.. */
539     ok(!lpCacheEntryInfo->dwHeaderInfoSize, "expected headers size 0, got %d\n",
540        lpCacheEntryInfo->dwHeaderInfoSize);
541     HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo);
542     /* and the previous filename shouldn't exist. */
543     check_file_not_exists(filenameA);
544     check_file_exists(filenameA1);
545
546     if (pDeleteUrlCacheEntryA)
547     {
548         ret = pDeleteUrlCacheEntryA(test_url);
549         ok(ret, "DeleteUrlCacheEntryA failed with error %d\n", GetLastError());
550         check_file_not_exists(filenameA);
551         check_file_not_exists(filenameA1);
552         /* Just in case, clean up files */
553         DeleteFileA(filenameA1);
554         DeleteFileA(filenameA);
555     }
556
557     /* Check whether a retrieved cache entry can be deleted before it's
558      * unlocked:
559      */
560     ret = CreateUrlCacheEntry(test_url, 0, "html", filenameA, 0);
561     ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError());
562     ret = CommitUrlCacheEntry(test_url, filenameA, filetime_zero, filetime_zero,
563             NORMAL_CACHE_ENTRY, NULL, 0, "html", NULL);
564     ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError());
565
566     cbCacheEntryInfo = 0;
567     SetLastError(0xdeadbeef);
568     ret = RetrieveUrlCacheEntryFile(test_url, NULL, &cbCacheEntryInfo, 0);
569     ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n");
570     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
571        "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
572
573     lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo);
574     ret = RetrieveUrlCacheEntryFile(test_url, lpCacheEntryInfo,
575             &cbCacheEntryInfo, 0);
576     ok(ret, "RetrieveUrlCacheEntryFile failed with error %d\n", GetLastError());
577
578     HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo);
579
580     if (pDeleteUrlCacheEntryA)
581     {
582         ret = pDeleteUrlCacheEntryA(test_url);
583         ok(!ret, "Expected failure\n");
584         ok(GetLastError() == ERROR_SHARING_VIOLATION,
585            "Expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError());
586         check_file_exists(filenameA);
587     }
588
589     lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo);
590     memset(lpCacheEntryInfo, 0, cbCacheEntryInfo);
591     ret = GetUrlCacheEntryInfo(test_url, lpCacheEntryInfo, &cbCacheEntryInfo);
592     ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError());
593     ok(lpCacheEntryInfo->CacheEntryType & 0x400000,
594         "CacheEntryType hasn't PENDING_DELETE_CACHE_ENTRY set, (flags %08x)\n",
595         lpCacheEntryInfo->CacheEntryType);
596     HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo);
597
598     if (pUnlockUrlCacheEntryFileA)
599     {
600         check_file_exists(filenameA);
601         ret = pUnlockUrlCacheEntryFileA(test_url, 0);
602         ok(ret, "UnlockUrlCacheEntryFileA failed: %d\n", GetLastError());
603         /* By unlocking the already-deleted cache entry, the file associated
604          * with it is deleted..
605          */
606         check_file_not_exists(filenameA);
607         /* (just in case, delete file) */
608         DeleteFileA(filenameA);
609     }
610     if (pDeleteUrlCacheEntryA)
611     {
612         /* and a subsequent deletion should fail. */
613         ret = pDeleteUrlCacheEntryA(test_url);
614         ok(!ret, "Expected failure\n");
615         ok(GetLastError() == ERROR_FILE_NOT_FOUND,
616            "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
617     }
618
619     /* Test whether preventing a file from being deleted causes
620      * DeleteUrlCacheEntryA to fail.
621      */
622     ret = CreateUrlCacheEntry(test_url, 0, "html", filenameA, 0);
623     ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError());
624
625     create_and_write_file(filenameA, &zero_byte, sizeof(zero_byte));
626     check_file_exists(filenameA);
627
628     ret = CommitUrlCacheEntry(test_url, filenameA, filetime_zero,
629             filetime_zero, NORMAL_CACHE_ENTRY, (LPBYTE)ok_header,
630             strlen(ok_header), "html", NULL);
631     ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError());
632     check_file_exists(filenameA);
633     hFile = CreateFileA(filenameA, GENERIC_READ, 0, NULL, OPEN_EXISTING,
634             FILE_ATTRIBUTE_NORMAL, NULL);
635     ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA failed: %d\n",
636        GetLastError());
637     if (pDeleteUrlCacheEntryA)
638     {
639         /* DeleteUrlCacheEntryA should succeed.. */
640         ret = pDeleteUrlCacheEntryA(test_url);
641         ok(ret, "DeleteUrlCacheEntryA failed with error %d\n", GetLastError());
642     }
643     CloseHandle(hFile);
644     if (pDeleteUrlCacheEntryA)
645     {
646         /* and a subsequent deletion should fail.. */
647         ret = pDeleteUrlCacheEntryA(test_url);
648         ok(!ret, "Expected failure\n");
649         ok(GetLastError() == ERROR_FILE_NOT_FOUND,
650            "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
651     }
652     /* and the file should be untouched. */
653     check_file_exists(filenameA);
654     DeleteFileA(filenameA);
655
656     /* Try creating a sticky entry.  Unlike non-sticky entries, the filename
657      * must have been set already.
658      */
659     SetLastError(0xdeadbeef);
660     ret = CommitUrlCacheEntry(test_url, NULL, filetime_zero, filetime_zero,
661             STICKY_CACHE_ENTRY, (LPBYTE)ok_header, strlen(ok_header), "html",
662             NULL);
663     ok(!ret, "expected failure\n");
664     ok(GetLastError() == ERROR_INVALID_PARAMETER,
665        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
666     SetLastError(0xdeadbeef);
667     ret = CommitUrlCacheEntry(test_url, NULL, filetime_zero, filetime_zero,
668             NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY,
669             (LPBYTE)ok_header, strlen(ok_header), "html", NULL);
670     ok(!ret, "expected failure\n");
671     ok(GetLastError() == ERROR_INVALID_PARAMETER,
672        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
673
674     ret = CreateUrlCacheEntry(test_url, 0, "html", filenameA, 0);
675     ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError());
676     create_and_write_file(filenameA, &zero_byte, sizeof(zero_byte));
677     ret = CommitUrlCacheEntry(test_url, filenameA, filetime_zero, filetime_zero,
678             NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY,
679             (LPBYTE)ok_header, strlen(ok_header), "html", NULL);
680     ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError());
681     cbCacheEntryInfo = 0;
682     SetLastError(0xdeadbeef);
683     ret = GetUrlCacheEntryInfo(test_url, NULL, &cbCacheEntryInfo);
684     ok(!ret, "GetUrlCacheEntryInfo should have failed\n");
685     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
686        "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
687     lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo);
688     ret = GetUrlCacheEntryInfo(test_url, lpCacheEntryInfo, &cbCacheEntryInfo);
689     ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError());
690     ok(lpCacheEntryInfo->CacheEntryType & (NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY),
691        "expected cache entry type NORMAL_CACHE_ENTRY | STICKY_CACHE_ENTRY, got %d (0x%08x)\n",
692        lpCacheEntryInfo->CacheEntryType, lpCacheEntryInfo->CacheEntryType);
693     ok(U(*lpCacheEntryInfo).dwExemptDelta == 86400,
694        "expected dwExemptDelta 86400, got %d\n",
695        U(*lpCacheEntryInfo).dwExemptDelta);
696     HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo);
697     if (pDeleteUrlCacheEntryA)
698     {
699         ret = pDeleteUrlCacheEntryA(test_url);
700         ok(ret, "DeleteUrlCacheEntryA failed with error %d\n", GetLastError());
701         /* When explicitly deleting the cache entry, the file is also deleted */
702         check_file_not_exists(filenameA);
703     }
704     /* Test once again, setting the exempt delta via SetUrlCacheEntryInfo */
705     ret = CreateUrlCacheEntry(test_url, 0, "html", filenameA, 0);
706     ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError());
707     create_and_write_file(filenameA, &zero_byte, sizeof(zero_byte));
708     ret = CommitUrlCacheEntry(test_url, filenameA, filetime_zero, filetime_zero,
709             NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY,
710             (LPBYTE)ok_header, strlen(ok_header), "html", NULL);
711     ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError());
712     cbCacheEntryInfo = 0;
713     SetLastError(0xdeadbeef);
714     ret = GetUrlCacheEntryInfo(test_url, NULL, &cbCacheEntryInfo);
715     ok(!ret, "GetUrlCacheEntryInfo should have failed\n");
716     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
717        "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
718     lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo);
719     ret = GetUrlCacheEntryInfo(test_url, lpCacheEntryInfo, &cbCacheEntryInfo);
720     ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError());
721     ok(lpCacheEntryInfo->CacheEntryType & (NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY),
722        "expected cache entry type NORMAL_CACHE_ENTRY | STICKY_CACHE_ENTRY, got %d (0x%08x)\n",
723        lpCacheEntryInfo->CacheEntryType, lpCacheEntryInfo->CacheEntryType);
724     ok(U(*lpCacheEntryInfo).dwExemptDelta == 86400,
725        "expected dwExemptDelta 86400, got %d\n",
726        U(*lpCacheEntryInfo).dwExemptDelta);
727     U(*lpCacheEntryInfo).dwExemptDelta = 0;
728     ret = SetUrlCacheEntryInfoA(test_url, lpCacheEntryInfo,
729             CACHE_ENTRY_EXEMPT_DELTA_FC);
730     ok(ret, "SetUrlCacheEntryInfo failed: %d\n", GetLastError());
731     ret = GetUrlCacheEntryInfo(test_url, lpCacheEntryInfo, &cbCacheEntryInfo);
732     ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError());
733     ok(!U(*lpCacheEntryInfo).dwExemptDelta, "expected dwExemptDelta 0, got %d\n",
734        U(*lpCacheEntryInfo).dwExemptDelta);
735     /* See whether a sticky cache entry has the flag cleared once the exempt
736      * delta is meaningless.
737      */
738     ok(lpCacheEntryInfo->CacheEntryType & (NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY),
739        "expected cache entry type NORMAL_CACHE_ENTRY | STICKY_CACHE_ENTRY, got %d (0x%08x)\n",
740        lpCacheEntryInfo->CacheEntryType, lpCacheEntryInfo->CacheEntryType);
741
742     /* Recommit of Url entry keeps dwExemptDelta */
743     U(*lpCacheEntryInfo).dwExemptDelta = 8600;
744     ret = SetUrlCacheEntryInfoA(test_url, lpCacheEntryInfo,
745             CACHE_ENTRY_EXEMPT_DELTA_FC);
746     ok(ret, "SetUrlCacheEntryInfo failed: %d\n", GetLastError());
747
748     ret = CreateUrlCacheEntry(test_url, 0, "html", filenameA1, 0);
749     ok(ret, "CreateUrlCacheEntry failed with error %d\n", GetLastError());
750     create_and_write_file(filenameA1, &zero_byte, sizeof(zero_byte));
751
752     ret = CommitUrlCacheEntry(test_url, filenameA1, filetime_zero, filetime_zero,
753             NORMAL_CACHE_ENTRY|STICKY_CACHE_ENTRY,
754             (LPBYTE)ok_header, strlen(ok_header), "html", NULL);
755     ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError());
756
757     ret = GetUrlCacheEntryInfo(test_url, lpCacheEntryInfo, &cbCacheEntryInfo);
758     ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError());
759     ok(U(*lpCacheEntryInfo).dwExemptDelta == 8600,
760        "expected dwExemptDelta 8600, got %d\n",
761        U(*lpCacheEntryInfo).dwExemptDelta);
762
763     HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo);
764
765     if (pDeleteUrlCacheEntryA)
766     {
767         ret = pDeleteUrlCacheEntryA(test_url);
768         ok(ret, "DeleteUrlCacheEntryA failed with error %d\n", GetLastError());
769         check_file_not_exists(filenameA);
770     }
771
772     /* Test if files with identical hash keys are handled correctly */
773     ret = CommitUrlCacheEntryA(test_hash_collisions1, NULL, filetime_zero, filetime_zero, NORMAL_CACHE_ENTRY, NULL, 0, "html", NULL);
774     ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError());
775     ret = CommitUrlCacheEntryA(test_hash_collisions2, NULL, filetime_zero, filetime_zero, NORMAL_CACHE_ENTRY, NULL, 0, "html", NULL);
776     ok(ret, "CommitUrlCacheEntry failed with error %d\n", GetLastError());
777
778     cbCacheEntryInfo = 0;
779     ret = GetUrlCacheEntryInfo(test_hash_collisions1, NULL, &cbCacheEntryInfo);
780     ok(!ret, "GetUrlCacheEntryInfo should have failed\n");
781     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
782             "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
783     lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo);
784     ret = GetUrlCacheEntryInfo(test_hash_collisions1, lpCacheEntryInfo, &cbCacheEntryInfo);
785     ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError());
786     ok(!strcmp(lpCacheEntryInfo->lpszSourceUrlName, test_hash_collisions1),
787             "got incorrect entry: %s\n", lpCacheEntryInfo->lpszSourceUrlName);
788     HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo);
789
790     cbCacheEntryInfo = 0;
791     ret = GetUrlCacheEntryInfo(test_hash_collisions2, NULL, &cbCacheEntryInfo);
792     ok(!ret, "GetUrlCacheEntryInfo should have failed\n");
793     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
794             "expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
795     lpCacheEntryInfo = HeapAlloc(GetProcessHeap(), 0, cbCacheEntryInfo);
796     ret = GetUrlCacheEntryInfo(test_hash_collisions2, lpCacheEntryInfo, &cbCacheEntryInfo);
797     ok(ret, "GetUrlCacheEntryInfo failed with error %d\n", GetLastError());
798     ok(!strcmp(lpCacheEntryInfo->lpszSourceUrlName, test_hash_collisions2),
799             "got incorrect entry: %s\n", lpCacheEntryInfo->lpszSourceUrlName);
800     HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo);
801
802     if (pDeleteUrlCacheEntryA) {
803         ret = pDeleteUrlCacheEntryA(test_hash_collisions1);
804         ok(ret, "DeleteUrlCacheEntry failed: %d\n", GetLastError());
805         ret = pDeleteUrlCacheEntryA(test_hash_collisions2);
806         ok(ret, "DeleteUrlCacheEntry failed: %d\n", GetLastError());
807     }
808 }
809
810 static void test_FindCloseUrlCache(void)
811 {
812     BOOL r;
813     DWORD err;
814
815     SetLastError(0xdeadbeef);
816     r = FindCloseUrlCache(NULL);
817     err = GetLastError();
818     ok(0 == r, "expected 0, got %d\n", r);
819     ok(ERROR_INVALID_HANDLE == err, "expected %d, got %d\n", ERROR_INVALID_HANDLE, err);
820 }
821
822 static void test_GetDiskInfoA(void)
823 {
824     BOOL ret;
825     DWORD error, cluster_size;
826     DWORDLONG free, total;
827     char path[MAX_PATH], *p;
828
829     GetSystemDirectoryA(path, MAX_PATH);
830     if ((p = strchr(path, '\\'))) *++p = 0;
831
832     ret = GetDiskInfoA(path, &cluster_size, &free, &total);
833     ok(ret, "GetDiskInfoA failed %u\n", GetLastError());
834
835     ret = GetDiskInfoA(path, &cluster_size, &free, NULL);
836     ok(ret, "GetDiskInfoA failed %u\n", GetLastError());
837
838     ret = GetDiskInfoA(path, &cluster_size, NULL, NULL);
839     ok(ret, "GetDiskInfoA failed %u\n", GetLastError());
840
841     ret = GetDiskInfoA(path, NULL, NULL, NULL);
842     ok(ret, "GetDiskInfoA failed %u\n", GetLastError());
843
844     SetLastError(0xdeadbeef);
845     strcpy(p, "\\non\\existing\\path");
846     ret = GetDiskInfoA(path, NULL, NULL, NULL);
847     error = GetLastError();
848     ok(!ret ||
849        broken(old_ie && ret), /* < IE7 */
850        "GetDiskInfoA succeeded\n");
851     ok(error == ERROR_PATH_NOT_FOUND ||
852        broken(old_ie && error == 0xdeadbeef), /* < IE7 */
853        "got %u expected ERROR_PATH_NOT_FOUND\n", error);
854
855     SetLastError(0xdeadbeef);
856     ret = GetDiskInfoA(NULL, NULL, NULL, NULL);
857     error = GetLastError();
858     ok(!ret, "GetDiskInfoA succeeded\n");
859     ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error);
860 }
861
862 START_TEST(urlcache)
863 {
864     HMODULE hdll;
865     hdll = GetModuleHandleA("wininet.dll");
866
867     if(!GetProcAddress(hdll, "InternetGetCookieExW")) {
868         win_skip("Too old IE (older than 6.0)\n");
869         return;
870     }
871     if(!GetProcAddress(hdll, "InternetGetSecurityInfoByURL")) /* < IE7 */
872         old_ie = TRUE;
873
874     pDeleteUrlCacheEntryA = (void*)GetProcAddress(hdll, "DeleteUrlCacheEntryA");
875     pUnlockUrlCacheEntryFileA = (void*)GetProcAddress(hdll, "UnlockUrlCacheEntryFileA");
876     test_urlcacheA();
877     test_FindCloseUrlCache();
878     test_GetDiskInfoA();
879 }