2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003-2008 Robert Shearman
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
31 #if defined(__MINGW32__) || defined (_MSC_VER)
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
63 #define ENTRY_START_OFFSET 0x4000
66 #define HASHTABLE_SIZE 448
67 #define HASHTABLE_NUM_ENTRIES 64 /* this needs to be power of 2, that divides HASHTABLE_SIZE */
68 #define HASHTABLE_BLOCKSIZE (HASHTABLE_SIZE / HASHTABLE_NUM_ENTRIES)
69 #define ALLOCATION_TABLE_OFFSET 0x250
70 #define ALLOCATION_TABLE_SIZE (ENTRY_START_OFFSET - ALLOCATION_TABLE_OFFSET)
71 #define MIN_BLOCK_NO 0x80
72 #define MAX_BLOCK_NO (ALLOCATION_TABLE_SIZE * 8)
73 #define FILE_SIZE(blocks) ((blocks) * BLOCKSIZE + ENTRY_START_OFFSET)
75 #define HASHTABLE_URL 0
76 #define HASHTABLE_DEL 1
77 #define HASHTABLE_LOCK 2
78 #define HASHTABLE_FREE 3
79 #define HASHTABLE_REDR 5
80 #define HASHTABLE_FLAG_BITS 4
82 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
83 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
84 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
85 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
86 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
88 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
90 typedef struct _CACHEFILE_ENTRY
94 DWORD dwSignature
; /* e.g. "URL " */
95 /* CHAR szSignature[4];
97 DWORD dwBlocksUsed
; /* number of 128byte blocks used by this entry */
100 typedef struct _URL_CACHEFILE_ENTRY
102 CACHEFILE_ENTRY CacheFileEntry
;
103 FILETIME LastModifiedTime
;
104 FILETIME LastAccessTime
;
105 WORD wExpiredDate
; /* expire date in dos format */
106 WORD wExpiredTime
; /* expire time in dos format */
107 DWORD dwUnknown1
; /* usually zero */
108 ULARGE_INTEGER size
; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow/High */
109 DWORD dwUnknown2
; /* usually zero */
110 DWORD dwExemptDelta
; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
111 DWORD dwUnknown3
; /* usually 0x60 */
112 DWORD dwOffsetUrl
; /* offset of start of url from start of entry */
113 BYTE CacheDir
; /* index of cache directory this url is stored in */
114 BYTE Unknown4
; /* usually zero */
115 WORD wUnknown5
; /* usually 0x1010 */
116 DWORD dwOffsetLocalName
; /* offset of start of local filename from start of entry */
117 DWORD CacheEntryType
; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
118 DWORD dwOffsetHeaderInfo
; /* offset of start of header info from start of entry */
119 DWORD dwHeaderInfoSize
;
120 DWORD dwOffsetFileExtension
; /* offset of start of file extension from start of entry */
121 WORD wLastSyncDate
; /* last sync date in dos format */
122 WORD wLastSyncTime
; /* last sync time in dos format */
123 DWORD dwHitRate
; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
124 DWORD dwUseCount
; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
125 WORD wUnknownDate
; /* usually same as wLastSyncDate */
126 WORD wUnknownTime
; /* usually same as wLastSyncTime */
127 DWORD dwUnknown7
; /* usually zero */
128 DWORD dwUnknown8
; /* usually zero */
129 /* packing to dword align start of next field */
130 /* CHAR szSourceUrlName[]; (url) */
131 /* packing to dword align start of next field */
132 /* CHAR szLocalFileName[]; (local file name excluding path) */
133 /* packing to dword align start of next field */
134 /* CHAR szHeaderInfo[]; (header info) */
135 } URL_CACHEFILE_ENTRY
;
143 typedef struct _HASH_CACHEFILE_ENTRY
145 CACHEFILE_ENTRY CacheFileEntry
;
147 DWORD dwHashTableNumber
;
148 struct _HASH_ENTRY HashTable
[HASHTABLE_SIZE
];
149 } HASH_CACHEFILE_ENTRY
;
151 typedef struct _DIRECTORY_DATA
154 char filename
[DIR_LENGTH
];
157 typedef struct _URLCACHE_HEADER
159 char szSignature
[28];
161 DWORD dwOffsetFirstHashTable
;
162 DWORD dwIndexCapacityInBlocks
;
165 ULARGE_INTEGER CacheLimit
;
166 ULARGE_INTEGER CacheUsage
;
167 ULARGE_INTEGER ExemptUsage
;
168 DWORD DirectoryCount
; /* number of directory_data's */
169 DIRECTORY_DATA directory_data
[1]; /* first directory entry */
170 } URLCACHE_HEADER
, *LPURLCACHE_HEADER
;
171 typedef const URLCACHE_HEADER
*LPCURLCACHE_HEADER
;
173 typedef struct _STREAM_HANDLE
179 typedef struct _URLCACHECONTAINER
181 struct list entry
; /* part of a list */
182 LPWSTR cache_prefix
; /* string that has to be prefixed for this container to be used */
183 LPWSTR path
; /* path to url container directory */
184 HANDLE hMapping
; /* handle of file mapping */
185 DWORD file_size
; /* size of file when mapping was opened */
186 HANDLE hMutex
; /* handle of mutex */
190 /* List of all containers available */
191 static struct list UrlContainers
= LIST_INIT(UrlContainers
);
193 static DWORD
URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader
, HASH_CACHEFILE_ENTRY
*pPrevHash
, HASH_CACHEFILE_ENTRY
**ppHash
);
195 /***********************************************************************
196 * URLCache_PathToObjectName (Internal)
198 * Converts a path to a name suitable for use as a Win32 object name.
199 * Replaces '\\' characters in-place with the specified character
200 * (usually '_' or '!')
206 static void URLCache_PathToObjectName(LPWSTR lpszPath
, WCHAR replace
)
208 for (; *lpszPath
; lpszPath
++)
210 if (*lpszPath
== '\\')
215 /***********************************************************************
216 * URLCacheContainer_OpenIndex (Internal)
218 * Opens the index file and saves mapping handle in hCacheIndexMapping
221 * ERROR_SUCCESS if succeeded
222 * Any other Win32 error code if failed
225 static DWORD
URLCacheContainer_OpenIndex(URLCACHECONTAINER
* pContainer
, DWORD blocks_no
)
228 WCHAR wszFilePath
[MAX_PATH
];
229 DWORD dwFileSize
, new_file_size
;
231 static const WCHAR wszIndex
[] = {'i','n','d','e','x','.','d','a','t',0};
232 static const WCHAR wszMappingFormat
[] = {'%','s','%','s','_','%','l','u',0};
234 WaitForSingleObject(pContainer
->hMutex
, INFINITE
);
236 if (pContainer
->hMapping
) {
237 ReleaseMutex(pContainer
->hMutex
);
238 return ERROR_SUCCESS
;
241 strcpyW(wszFilePath
, pContainer
->path
);
242 strcatW(wszFilePath
, wszIndex
);
244 hFile
= CreateFileW(wszFilePath
, GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, 0, NULL
);
245 if (hFile
== INVALID_HANDLE_VALUE
)
247 /* Maybe the directory wasn't there? Try to create it */
248 if (CreateDirectoryW(pContainer
->path
, 0))
249 hFile
= CreateFileW(wszFilePath
, GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, 0, NULL
);
251 if (hFile
== INVALID_HANDLE_VALUE
)
253 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath
));
254 ReleaseMutex(pContainer
->hMutex
);
255 return GetLastError();
258 dwFileSize
= GetFileSize(hFile
, NULL
);
259 if (dwFileSize
== INVALID_FILE_SIZE
)
261 ReleaseMutex(pContainer
->hMutex
);
262 return GetLastError();
265 if (blocks_no
< MIN_BLOCK_NO
)
266 blocks_no
= MIN_BLOCK_NO
;
267 else if (blocks_no
> MAX_BLOCK_NO
)
268 blocks_no
= MAX_BLOCK_NO
;
269 new_file_size
= FILE_SIZE(blocks_no
);
271 if (dwFileSize
< new_file_size
)
273 static const CHAR szCacheContent
[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content";
275 char achZeroes
[0x1000];
277 DWORD dwError
= ERROR_SUCCESS
;
279 if (SetFilePointer(hFile
, 0, NULL
, FILE_END
) == INVALID_SET_FILE_POINTER
)
280 dwError
= GetLastError();
282 /* Write zeroes to the entire file so we can safely map it without
283 * fear of getting a SEGV because the disk is full.
285 memset(achZeroes
, 0, sizeof(achZeroes
));
286 for (dwOffset
= dwFileSize
; dwOffset
<new_file_size
&& dwError
==ERROR_SUCCESS
;
287 dwOffset
+= sizeof(achZeroes
))
289 DWORD dwWrite
= sizeof(achZeroes
);
292 if (new_file_size
- dwOffset
< dwWrite
)
293 dwWrite
= new_file_size
- dwOffset
;
294 if (!WriteFile(hFile
, achZeroes
, dwWrite
, &dwWritten
, 0) ||
295 dwWritten
!= dwWrite
)
297 /* If we fail to write, we need to return the error that
298 * cause the problem and also make sure the file is no
299 * longer there, if possible.
301 dwError
= GetLastError();
305 if (dwError
== ERROR_SUCCESS
)
307 HANDLE hMapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READWRITE
, 0, 0, NULL
);
311 URLCACHE_HEADER
*pHeader
= MapViewOfFile(hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
313 if (pHeader
&& dwFileSize
)
315 pHeader
->dwFileSize
= new_file_size
;
316 pHeader
->dwIndexCapacityInBlocks
= blocks_no
;
321 WCHAR wszDirPath
[MAX_PATH
];
324 HASH_CACHEFILE_ENTRY
*pHashEntry
;
326 /* First set some constants and defaults in the header */
327 strcpy(pHeader
->szSignature
, "WINE URLCache Ver 0.2005001");
328 pHeader
->dwFileSize
= new_file_size
;
329 pHeader
->dwIndexCapacityInBlocks
= blocks_no
;
330 /* 127MB - taken from default for Windows 2000 */
331 pHeader
->CacheLimit
.QuadPart
= 0x07ff5400;
332 /* Copied from a Windows 2000 cache index */
333 pHeader
->DirectoryCount
= 4;
335 /* If the registry has a cache size set, use the registry value */
336 if (RegOpenKeyA(HKEY_CURRENT_USER
, szCacheContent
, &key
) == ERROR_SUCCESS
)
339 DWORD len
= sizeof(dw
);
342 if (RegQueryValueExA(key
, "CacheLimit", NULL
, &keytype
,
343 (BYTE
*) &dw
, &len
) == ERROR_SUCCESS
&&
344 keytype
== REG_DWORD
)
346 pHeader
->CacheLimit
.QuadPart
= (ULONGLONG
)dw
* 1024;
351 URLCache_CreateHashTable(pHeader
, NULL
, &pHashEntry
);
353 /* Last step - create the directories */
355 strcpyW(wszDirPath
, pContainer
->path
);
356 pwchDir
= wszDirPath
+ strlenW(wszDirPath
);
359 GetSystemTimeAsFileTime(&ft
);
361 for (i
= 0; !dwError
&& i
< pHeader
->DirectoryCount
; ++i
)
363 pHeader
->directory_data
[i
].dwNumFiles
= 0;
367 ULONGLONG n
= ft
.dwHighDateTime
;
369 /* Generate a file name to attempt to create.
370 * This algorithm will create what will appear
371 * to be random and unrelated directory names
372 * of up to 9 characters in length.
375 n
+= ft
.dwLowDateTime
;
376 n
^= ((ULONGLONG
) i
<< 56) | ((ULONGLONG
) j
<< 48);
378 for (k
= 0; k
< 8; ++k
)
382 /* Dividing by a prime greater than 36 helps
383 * with the appearance of randomness
388 pwchDir
[k
] = '0' + r
;
390 pwchDir
[k
] = 'A' + (r
- 10);
393 if (CreateDirectoryW(wszDirPath
, 0))
395 /* The following is OK because we generated an
396 * 8 character directory name made from characters
397 * [A-Z0-9], which are equivalent for all code
398 * pages and for UTF-16
400 for (k
= 0; k
< 8; ++k
)
401 pHeader
->directory_data
[i
].filename
[k
] = pwchDir
[k
];
406 /* Give up. The most likely cause of this
407 * is a full disk, but whatever the cause
408 * is, it should be more than apparent that
411 dwError
= GetLastError();
417 UnmapViewOfFile(pHeader
);
421 dwError
= GetLastError();
423 CloseHandle(hMapping
);
427 dwError
= GetLastError();
434 DeleteFileW(wszFilePath
);
435 ReleaseMutex(pContainer
->hMutex
);
441 pContainer
->file_size
= new_file_size
;
442 wsprintfW(wszFilePath
, wszMappingFormat
, pContainer
->path
, wszIndex
, new_file_size
);
443 URLCache_PathToObjectName(wszFilePath
, '_');
444 pContainer
->hMapping
= OpenFileMappingW(FILE_MAP_WRITE
, FALSE
, wszFilePath
);
445 if (!pContainer
->hMapping
)
446 pContainer
->hMapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READWRITE
, 0, 0, wszFilePath
);
448 if (!pContainer
->hMapping
)
450 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
451 ReleaseMutex(pContainer
->hMutex
);
452 return GetLastError();
455 ReleaseMutex(pContainer
->hMutex
);
457 return ERROR_SUCCESS
;
460 /***********************************************************************
461 * URLCacheContainer_CloseIndex (Internal)
469 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER
* pContainer
)
471 CloseHandle(pContainer
->hMapping
);
472 pContainer
->hMapping
= NULL
;
475 static BOOL
URLCacheContainers_AddContainer(LPCWSTR cache_prefix
, LPCWSTR path
, LPWSTR mutex_name
)
477 URLCACHECONTAINER
* pContainer
= heap_alloc(sizeof(URLCACHECONTAINER
));
478 int cache_prefix_len
= strlenW(cache_prefix
);
485 pContainer
->hMapping
= NULL
;
486 pContainer
->file_size
= 0;
488 pContainer
->path
= heap_strdupW(path
);
489 if (!pContainer
->path
)
491 heap_free(pContainer
);
495 pContainer
->cache_prefix
= heap_alloc((cache_prefix_len
+ 1) * sizeof(WCHAR
));
496 if (!pContainer
->cache_prefix
)
498 heap_free(pContainer
->path
);
499 heap_free(pContainer
);
503 memcpy(pContainer
->cache_prefix
, cache_prefix
, (cache_prefix_len
+ 1) * sizeof(WCHAR
));
505 CharLowerW(mutex_name
);
506 URLCache_PathToObjectName(mutex_name
, '!');
508 if ((pContainer
->hMutex
= CreateMutexW(NULL
, FALSE
, mutex_name
)) == NULL
)
510 ERR("couldn't create mutex (error is %d)\n", GetLastError());
511 heap_free(pContainer
->path
);
512 heap_free(pContainer
);
516 list_add_head(&UrlContainers
, &pContainer
->entry
);
521 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER
* pContainer
)
523 list_remove(&pContainer
->entry
);
525 URLCacheContainer_CloseIndex(pContainer
);
526 CloseHandle(pContainer
->hMutex
);
527 heap_free(pContainer
->path
);
528 heap_free(pContainer
->cache_prefix
);
529 heap_free(pContainer
);
532 void URLCacheContainers_CreateDefaults(void)
534 static const WCHAR UrlSuffix
[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
535 static const WCHAR UrlPrefix
[] = {0};
536 static const WCHAR HistorySuffix
[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
537 static const WCHAR HistoryPrefix
[] = {'V','i','s','i','t','e','d',':',0};
538 static const WCHAR CookieSuffix
[] = {0};
539 static const WCHAR CookiePrefix
[] = {'C','o','o','k','i','e',':',0};
542 int nFolder
; /* CSIDL_* constant */
543 const WCHAR
* shpath_suffix
; /* suffix on path returned by SHGetSpecialFolderPath */
544 const WCHAR
* cache_prefix
; /* prefix used to reference the container */
545 } DefaultContainerData
[] =
547 { CSIDL_INTERNET_CACHE
, UrlSuffix
, UrlPrefix
},
548 { CSIDL_HISTORY
, HistorySuffix
, HistoryPrefix
},
549 { CSIDL_COOKIES
, CookieSuffix
, CookiePrefix
},
553 for (i
= 0; i
< sizeof(DefaultContainerData
) / sizeof(DefaultContainerData
[0]); i
++)
555 WCHAR wszCachePath
[MAX_PATH
];
556 WCHAR wszMutexName
[MAX_PATH
];
557 int path_len
, suffix_len
;
559 if (!SHGetSpecialFolderPathW(NULL
, wszCachePath
, DefaultContainerData
[i
].nFolder
, TRUE
))
561 ERR("Couldn't get path for default container %u\n", i
);
564 path_len
= strlenW(wszCachePath
);
565 suffix_len
= strlenW(DefaultContainerData
[i
].shpath_suffix
);
567 if (path_len
+ suffix_len
+ 2 > MAX_PATH
)
569 ERR("Path too long\n");
573 wszCachePath
[path_len
] = '\\';
574 wszCachePath
[path_len
+1] = 0;
576 strcpyW(wszMutexName
, wszCachePath
);
580 memcpy(wszCachePath
+ path_len
+ 1, DefaultContainerData
[i
].shpath_suffix
, (suffix_len
+ 1) * sizeof(WCHAR
));
581 wszCachePath
[path_len
+ suffix_len
+ 1] = '\\';
582 wszCachePath
[path_len
+ suffix_len
+ 2] = '\0';
585 URLCacheContainers_AddContainer(DefaultContainerData
[i
].cache_prefix
, wszCachePath
, wszMutexName
);
589 void URLCacheContainers_DeleteAll(void)
591 while(!list_empty(&UrlContainers
))
592 URLCacheContainer_DeleteContainer(
593 LIST_ENTRY(list_head(&UrlContainers
), URLCACHECONTAINER
, entry
)
597 static DWORD
URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl
, URLCACHECONTAINER
** ppContainer
)
599 URLCACHECONTAINER
* pContainer
;
601 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl
));
604 return ERROR_INVALID_PARAMETER
;
606 LIST_FOR_EACH_ENTRY(pContainer
, &UrlContainers
, URLCACHECONTAINER
, entry
)
608 int prefix_len
= strlenW(pContainer
->cache_prefix
);
609 if (!strncmpW(pContainer
->cache_prefix
, lpwszUrl
, prefix_len
))
611 TRACE("found container with prefix %s for URL %s\n", debugstr_w(pContainer
->cache_prefix
), debugstr_w(lpwszUrl
));
612 *ppContainer
= pContainer
;
613 return ERROR_SUCCESS
;
616 ERR("no container found\n");
617 return ERROR_FILE_NOT_FOUND
;
620 static DWORD
URLCacheContainers_FindContainerA(LPCSTR lpszUrl
, URLCACHECONTAINER
** ppContainer
)
625 if (lpszUrl
&& !(url
= heap_strdupAtoW(lpszUrl
)))
626 return ERROR_OUTOFMEMORY
;
628 ret
= URLCacheContainers_FindContainerW(url
, ppContainer
);
633 static BOOL
URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern
, DWORD dwIndex
, URLCACHECONTAINER
** ppContainer
)
636 URLCACHECONTAINER
* pContainer
;
638 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern
));
640 /* non-NULL search pattern only returns one container ever */
641 if (lpwszSearchPattern
&& dwIndex
> 0)
644 LIST_FOR_EACH_ENTRY(pContainer
, &UrlContainers
, URLCACHECONTAINER
, entry
)
646 if (lpwszSearchPattern
)
648 if (!strcmpW(pContainer
->cache_prefix
, lpwszSearchPattern
))
650 TRACE("found container with prefix %s\n", debugstr_w(pContainer
->cache_prefix
));
651 *ppContainer
= pContainer
;
659 TRACE("found container with prefix %s\n", debugstr_w(pContainer
->cache_prefix
));
660 *ppContainer
= pContainer
;
669 /***********************************************************************
670 * URLCacheContainer_LockIndex (Internal)
672 * Locks the index for system-wide exclusive access.
675 * Cache file header if successful
676 * NULL if failed and calls SetLastError.
678 static LPURLCACHE_HEADER
URLCacheContainer_LockIndex(URLCACHECONTAINER
* pContainer
)
682 URLCACHE_HEADER
* pHeader
;
686 WaitForSingleObject(pContainer
->hMutex
, INFINITE
);
688 pIndexData
= MapViewOfFile(pContainer
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
692 ReleaseMutex(pContainer
->hMutex
);
693 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
696 pHeader
= (URLCACHE_HEADER
*)pIndexData
;
698 /* file has grown - we need to remap to prevent us getting
699 * access violations when we try and access beyond the end
700 * of the memory mapped file */
701 if (pHeader
->dwFileSize
!= pContainer
->file_size
)
703 UnmapViewOfFile( pHeader
);
704 URLCacheContainer_CloseIndex(pContainer
);
705 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
706 if (error
!= ERROR_SUCCESS
)
708 ReleaseMutex(pContainer
->hMutex
);
712 pIndexData
= MapViewOfFile(pContainer
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
716 ReleaseMutex(pContainer
->hMutex
);
717 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
720 pHeader
= (URLCACHE_HEADER
*)pIndexData
;
723 TRACE("Signature: %s, file size: %d bytes\n", pHeader
->szSignature
, pHeader
->dwFileSize
);
725 for (index
= 0; index
< pHeader
->DirectoryCount
; index
++)
727 TRACE("Directory[%d] = \"%.8s\"\n", index
, pHeader
->directory_data
[index
].filename
);
733 /***********************************************************************
734 * URLCacheContainer_UnlockIndex (Internal)
737 static BOOL
URLCacheContainer_UnlockIndex(URLCACHECONTAINER
* pContainer
, LPURLCACHE_HEADER pHeader
)
740 ReleaseMutex(pContainer
->hMutex
);
741 return UnmapViewOfFile(pHeader
);
744 /***********************************************************************
745 * URLCacheContainer_CleanIndex (Internal)
747 * This function is meant to make place in index file by removing old
748 * entries and resizing the file.
750 * CAUTION: file view may get mapped to new memory
751 * TODO: implement entries cleaning
754 * ERROR_SUCCESS when new memory is available
755 * error code otherwise
757 static DWORD
URLCacheContainer_CleanIndex(URLCACHECONTAINER
*container
, URLCACHE_HEADER
**file_view
)
759 URLCACHE_HEADER
*header
= *file_view
;
762 FIXME("(%s %s) semi-stub\n", debugstr_w(container
->cache_prefix
), debugstr_w(container
->path
));
764 if(header
->dwFileSize
>= ALLOCATION_TABLE_SIZE
*8*BLOCKSIZE
+ ENTRY_START_OFFSET
) {
765 WARN("index file has maximal size\n");
766 return ERROR_NOT_ENOUGH_MEMORY
;
769 URLCacheContainer_CloseIndex(container
);
770 ret
= URLCacheContainer_OpenIndex(container
, header
->dwIndexCapacityInBlocks
*2);
771 if(ret
!= ERROR_SUCCESS
)
773 header
= MapViewOfFile(container
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
775 return GetLastError();
777 UnmapViewOfFile(*file_view
);
779 return ERROR_SUCCESS
;
783 #define CHAR_BIT (8 * sizeof(CHAR))
786 /***********************************************************************
787 * URLCache_Allocation_BlockIsFree (Internal)
789 * Is the specified block number free?
796 static inline BYTE
URLCache_Allocation_BlockIsFree(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
798 BYTE mask
= 1 << (dwBlockNumber
% CHAR_BIT
);
799 return (AllocationTable
[dwBlockNumber
/ CHAR_BIT
] & mask
) == 0;
802 /***********************************************************************
803 * URLCache_Allocation_BlockFree (Internal)
805 * Marks the specified block as free
811 static inline void URLCache_Allocation_BlockFree(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
813 BYTE mask
= ~(1 << (dwBlockNumber
% CHAR_BIT
));
814 AllocationTable
[dwBlockNumber
/ CHAR_BIT
] &= mask
;
817 /***********************************************************************
818 * URLCache_Allocation_BlockAllocate (Internal)
820 * Marks the specified block as allocated
826 static inline void URLCache_Allocation_BlockAllocate(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
828 BYTE mask
= 1 << (dwBlockNumber
% CHAR_BIT
);
829 AllocationTable
[dwBlockNumber
/ CHAR_BIT
] |= mask
;
832 /***********************************************************************
833 * URLCache_FindFirstFreeEntry (Internal)
835 * Finds and allocates the first block of free space big enough and
836 * sets ppEntry to point to it.
839 * ERROR_SUCCESS when free memory block was found
840 * Any other Win32 error code if the entry could not be added
843 static DWORD
URLCache_FindFirstFreeEntry(URLCACHE_HEADER
* pHeader
, DWORD dwBlocksNeeded
, CACHEFILE_ENTRY
** ppEntry
)
845 LPBYTE AllocationTable
= (LPBYTE
)pHeader
+ ALLOCATION_TABLE_OFFSET
;
848 for (dwBlockNumber
= 0; dwBlockNumber
< pHeader
->dwIndexCapacityInBlocks
; dwBlockNumber
++)
850 for (dwFreeCounter
= 0;
851 dwFreeCounter
< dwBlocksNeeded
&&
852 dwFreeCounter
+ dwBlockNumber
< pHeader
->dwIndexCapacityInBlocks
&&
853 URLCache_Allocation_BlockIsFree(AllocationTable
, dwBlockNumber
+ dwFreeCounter
);
855 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber
, ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
857 if (dwFreeCounter
== dwBlocksNeeded
)
860 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber
, ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
861 for (index
= 0; index
< dwBlocksNeeded
; index
++)
862 URLCache_Allocation_BlockAllocate(AllocationTable
, dwBlockNumber
+ index
);
863 *ppEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
864 for (index
= 0; index
< dwBlocksNeeded
* BLOCKSIZE
/ sizeof(DWORD
); index
++)
865 ((DWORD
*)*ppEntry
)[index
] = 0xdeadbeef;
866 (*ppEntry
)->dwBlocksUsed
= dwBlocksNeeded
;
867 return ERROR_SUCCESS
;
871 return ERROR_HANDLE_DISK_FULL
;
874 /***********************************************************************
875 * URLCache_DeleteEntry (Internal)
877 * Deletes the specified entry and frees the space allocated to it
880 * TRUE if it succeeded
884 static BOOL
URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader
, CACHEFILE_ENTRY
* pEntry
)
888 BYTE
* AllocationTable
= (LPBYTE
)pHeader
+ ALLOCATION_TABLE_OFFSET
;
890 /* update allocation table */
891 dwStartBlock
= ((DWORD
)((BYTE
*)pEntry
- (BYTE
*)pHeader
) - ENTRY_START_OFFSET
) / BLOCKSIZE
;
892 for (dwBlock
= dwStartBlock
; dwBlock
< dwStartBlock
+ pEntry
->dwBlocksUsed
; dwBlock
++)
893 URLCache_Allocation_BlockFree(AllocationTable
, dwBlock
);
898 /***********************************************************************
899 * URLCache_LocalFileNameToPathW (Internal)
901 * Copies the full path to the specified buffer given the local file
902 * name and the index of the directory it is in. Always sets value in
903 * lpBufferSize to the required buffer size (in bytes).
906 * TRUE if the buffer was big enough
907 * FALSE if the buffer was too small
910 static BOOL
URLCache_LocalFileNameToPathW(
911 const URLCACHECONTAINER
* pContainer
,
912 LPCURLCACHE_HEADER pHeader
,
913 LPCSTR szLocalFileName
,
919 int path_len
= strlenW(pContainer
->path
);
920 int file_name_len
= MultiByteToWideChar(CP_ACP
, 0, szLocalFileName
, -1, NULL
, 0);
921 if (Directory
>= pHeader
->DirectoryCount
)
927 nRequired
= (path_len
+ DIR_LENGTH
+ file_name_len
+ 1) * sizeof(WCHAR
);
928 if (nRequired
<= *lpBufferSize
)
932 memcpy(wszPath
, pContainer
->path
, path_len
* sizeof(WCHAR
));
933 dir_len
= MultiByteToWideChar(CP_ACP
, 0, pHeader
->directory_data
[Directory
].filename
, DIR_LENGTH
, wszPath
+ path_len
, DIR_LENGTH
);
934 wszPath
[dir_len
+ path_len
] = '\\';
935 MultiByteToWideChar(CP_ACP
, 0, szLocalFileName
, -1, wszPath
+ dir_len
+ path_len
+ 1, file_name_len
);
936 *lpBufferSize
= nRequired
;
939 *lpBufferSize
= nRequired
;
943 /***********************************************************************
944 * URLCache_LocalFileNameToPathA (Internal)
946 * Copies the full path to the specified buffer given the local file
947 * name and the index of the directory it is in. Always sets value in
948 * lpBufferSize to the required buffer size.
951 * TRUE if the buffer was big enough
952 * FALSE if the buffer was too small
955 static BOOL
URLCache_LocalFileNameToPathA(
956 const URLCACHECONTAINER
* pContainer
,
957 LPCURLCACHE_HEADER pHeader
,
958 LPCSTR szLocalFileName
,
964 int path_len
, file_name_len
, dir_len
;
966 if (Directory
>= pHeader
->DirectoryCount
)
972 path_len
= WideCharToMultiByte(CP_ACP
, 0, pContainer
->path
, -1, NULL
, 0, NULL
, NULL
) - 1;
973 file_name_len
= strlen(szLocalFileName
) + 1 /* for nul-terminator */;
974 dir_len
= DIR_LENGTH
;
976 nRequired
= (path_len
+ dir_len
+ 1 + file_name_len
) * sizeof(char);
977 if (nRequired
< *lpBufferSize
)
979 WideCharToMultiByte(CP_ACP
, 0, pContainer
->path
, -1, szPath
, path_len
, NULL
, NULL
);
980 memcpy(szPath
+path_len
, pHeader
->directory_data
[Directory
].filename
, dir_len
);
981 szPath
[path_len
+ dir_len
] = '\\';
982 memcpy(szPath
+ path_len
+ dir_len
+ 1, szLocalFileName
, file_name_len
);
983 *lpBufferSize
= nRequired
;
986 *lpBufferSize
= nRequired
;
990 /* Just like DosDateTimeToFileTime, except that it also maps the special
991 * case of a DOS date/time of (0,0) to a filetime of (0,0).
993 static void URLCache_DosDateTimeToFileTime(WORD fatdate
, WORD fattime
,
996 if (!fatdate
&& !fattime
)
997 ft
->dwLowDateTime
= ft
->dwHighDateTime
= 0;
999 DosDateTimeToFileTime(fatdate
, fattime
, ft
);
1002 /***********************************************************************
1003 * URLCache_CopyEntry (Internal)
1005 * Copies an entry from the cache index file to the Win32 structure
1008 * ERROR_SUCCESS if the buffer was big enough
1009 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1012 static DWORD
URLCache_CopyEntry(
1013 URLCACHECONTAINER
* pContainer
,
1014 LPCURLCACHE_HEADER pHeader
,
1015 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1016 LPDWORD lpdwBufferSize
,
1017 const URL_CACHEFILE_ENTRY
* pUrlEntry
,
1021 DWORD dwRequiredSize
= sizeof(*lpCacheEntryInfo
);
1023 if (*lpdwBufferSize
>= dwRequiredSize
)
1025 lpCacheEntryInfo
->lpHeaderInfo
= NULL
;
1026 lpCacheEntryInfo
->lpszFileExtension
= NULL
;
1027 lpCacheEntryInfo
->lpszLocalFileName
= NULL
;
1028 lpCacheEntryInfo
->lpszSourceUrlName
= NULL
;
1029 lpCacheEntryInfo
->CacheEntryType
= pUrlEntry
->CacheEntryType
;
1030 lpCacheEntryInfo
->u
.dwExemptDelta
= pUrlEntry
->dwExemptDelta
;
1031 lpCacheEntryInfo
->dwHeaderInfoSize
= pUrlEntry
->dwHeaderInfoSize
;
1032 lpCacheEntryInfo
->dwHitRate
= pUrlEntry
->dwHitRate
;
1033 lpCacheEntryInfo
->dwSizeHigh
= pUrlEntry
->size
.u
.HighPart
;
1034 lpCacheEntryInfo
->dwSizeLow
= pUrlEntry
->size
.u
.LowPart
;
1035 lpCacheEntryInfo
->dwStructSize
= sizeof(*lpCacheEntryInfo
);
1036 lpCacheEntryInfo
->dwUseCount
= pUrlEntry
->dwUseCount
;
1037 URLCache_DosDateTimeToFileTime(pUrlEntry
->wExpiredDate
, pUrlEntry
->wExpiredTime
, &lpCacheEntryInfo
->ExpireTime
);
1038 lpCacheEntryInfo
->LastAccessTime
.dwHighDateTime
= pUrlEntry
->LastAccessTime
.dwHighDateTime
;
1039 lpCacheEntryInfo
->LastAccessTime
.dwLowDateTime
= pUrlEntry
->LastAccessTime
.dwLowDateTime
;
1040 lpCacheEntryInfo
->LastModifiedTime
.dwHighDateTime
= pUrlEntry
->LastModifiedTime
.dwHighDateTime
;
1041 lpCacheEntryInfo
->LastModifiedTime
.dwLowDateTime
= pUrlEntry
->LastModifiedTime
.dwLowDateTime
;
1042 URLCache_DosDateTimeToFileTime(pUrlEntry
->wLastSyncDate
, pUrlEntry
->wLastSyncTime
, &lpCacheEntryInfo
->LastSyncTime
);
1045 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1046 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1047 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1049 lenUrl
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, -1, NULL
, 0);
1051 lenUrl
= strlen((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
1052 dwRequiredSize
+= (lenUrl
+ 1) * (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
1054 /* FIXME: is source url optional? */
1055 if (*lpdwBufferSize
>= dwRequiredSize
)
1057 DWORD lenUrlBytes
= (lenUrl
+1) * (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
1059 lpCacheEntryInfo
->lpszSourceUrlName
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
- lenUrlBytes
;
1061 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, -1, (LPWSTR
)lpCacheEntryInfo
->lpszSourceUrlName
, lenUrl
+ 1);
1063 memcpy(lpCacheEntryInfo
->lpszSourceUrlName
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, lenUrlBytes
);
1066 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1067 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1068 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1070 if (pUrlEntry
->dwOffsetLocalName
)
1072 LONG nLocalFilePathSize
;
1073 LPSTR lpszLocalFileName
;
1074 lpszLocalFileName
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
;
1075 nLocalFilePathSize
= *lpdwBufferSize
- dwRequiredSize
;
1076 if ((bUnicode
&& URLCache_LocalFileNameToPathW(pContainer
, pHeader
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
, pUrlEntry
->CacheDir
, (LPWSTR
)lpszLocalFileName
, &nLocalFilePathSize
)) ||
1077 (!bUnicode
&& URLCache_LocalFileNameToPathA(pContainer
, pHeader
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
, pUrlEntry
->CacheDir
, lpszLocalFileName
, &nLocalFilePathSize
)))
1079 lpCacheEntryInfo
->lpszLocalFileName
= lpszLocalFileName
;
1081 dwRequiredSize
+= nLocalFilePathSize
* (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
)) ;
1083 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1084 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1085 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1087 dwRequiredSize
+= pUrlEntry
->dwHeaderInfoSize
+ 1;
1089 if (*lpdwBufferSize
>= dwRequiredSize
)
1091 lpCacheEntryInfo
->lpHeaderInfo
= (LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
- pUrlEntry
->dwHeaderInfoSize
- 1;
1092 memcpy(lpCacheEntryInfo
->lpHeaderInfo
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
, pUrlEntry
->dwHeaderInfoSize
);
1093 ((LPBYTE
)lpCacheEntryInfo
)[dwRequiredSize
- 1] = '\0';
1095 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1096 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1097 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1099 if (pUrlEntry
->dwOffsetFileExtension
)
1104 lenExtension
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, -1, NULL
, 0);
1106 lenExtension
= strlen((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
) + 1;
1107 dwRequiredSize
+= lenExtension
* (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
1109 if (*lpdwBufferSize
>= dwRequiredSize
)
1111 lpCacheEntryInfo
->lpszFileExtension
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
- lenExtension
;
1113 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, -1, (LPWSTR
)lpCacheEntryInfo
->lpszSourceUrlName
, lenExtension
);
1115 memcpy(lpCacheEntryInfo
->lpszFileExtension
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, lenExtension
* sizeof(CHAR
));
1118 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1119 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1120 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1123 if (dwRequiredSize
> *lpdwBufferSize
)
1125 *lpdwBufferSize
= dwRequiredSize
;
1126 return ERROR_INSUFFICIENT_BUFFER
;
1128 *lpdwBufferSize
= dwRequiredSize
;
1129 return ERROR_SUCCESS
;
1132 /* Just like FileTimeToDosDateTime, except that it also maps the special
1133 * case of a filetime of (0,0) to a DOS date/time of (0,0).
1135 static void URLCache_FileTimeToDosDateTime(const FILETIME
*ft
, WORD
*fatdate
,
1138 if (!ft
->dwLowDateTime
&& !ft
->dwHighDateTime
)
1139 *fatdate
= *fattime
= 0;
1141 FileTimeToDosDateTime(ft
, fatdate
, fattime
);
1144 /***********************************************************************
1145 * URLCache_SetEntryInfo (Internal)
1147 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1148 * according to the flags set by dwFieldControl.
1151 * ERROR_SUCCESS if the buffer was big enough
1152 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small
1155 static DWORD
URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY
* pUrlEntry
, const INTERNET_CACHE_ENTRY_INFOW
* lpCacheEntryInfo
, DWORD dwFieldControl
)
1157 if (dwFieldControl
& CACHE_ENTRY_ACCTIME_FC
)
1158 pUrlEntry
->LastAccessTime
= lpCacheEntryInfo
->LastAccessTime
;
1159 if (dwFieldControl
& CACHE_ENTRY_ATTRIBUTE_FC
)
1160 pUrlEntry
->CacheEntryType
= lpCacheEntryInfo
->CacheEntryType
;
1161 if (dwFieldControl
& CACHE_ENTRY_EXEMPT_DELTA_FC
)
1162 pUrlEntry
->dwExemptDelta
= lpCacheEntryInfo
->u
.dwExemptDelta
;
1163 if (dwFieldControl
& CACHE_ENTRY_EXPTIME_FC
)
1164 URLCache_FileTimeToDosDateTime(&lpCacheEntryInfo
->ExpireTime
, &pUrlEntry
->wExpiredDate
, &pUrlEntry
->wExpiredTime
);
1165 if (dwFieldControl
& CACHE_ENTRY_HEADERINFO_FC
)
1166 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1167 if (dwFieldControl
& CACHE_ENTRY_HITRATE_FC
)
1168 pUrlEntry
->dwHitRate
= lpCacheEntryInfo
->dwHitRate
;
1169 if (dwFieldControl
& CACHE_ENTRY_MODTIME_FC
)
1170 pUrlEntry
->LastModifiedTime
= lpCacheEntryInfo
->LastModifiedTime
;
1171 if (dwFieldControl
& CACHE_ENTRY_SYNCTIME_FC
)
1172 URLCache_FileTimeToDosDateTime(&lpCacheEntryInfo
->LastAccessTime
, &pUrlEntry
->wLastSyncDate
, &pUrlEntry
->wLastSyncTime
);
1174 return ERROR_SUCCESS
;
1177 /***********************************************************************
1178 * URLCache_HashKey (Internal)
1180 * Returns the hash key for a given string
1183 * hash key for the string
1186 static DWORD
URLCache_HashKey(LPCSTR lpszKey
)
1188 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1189 * but the algorithm and result are not the same!
1191 static const unsigned char lookupTable
[256] =
1193 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1194 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1195 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1196 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1197 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1198 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1199 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1200 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1201 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1202 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1203 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1204 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1205 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1206 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1207 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1208 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1209 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1210 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1211 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1212 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1213 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1214 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1215 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1216 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1217 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1218 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1219 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1220 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1221 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1222 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1223 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1224 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1229 for (i
= 0; i
< sizeof(key
) / sizeof(key
[0]); i
++)
1230 key
[i
] = lookupTable
[i
];
1232 for (lpszKey
++; *lpszKey
&& ((lpszKey
[0] != '/') || (lpszKey
[1] != 0)); lpszKey
++)
1234 for (i
= 0; i
< sizeof(key
) / sizeof(key
[0]); i
++)
1235 key
[i
] = lookupTable
[*lpszKey
^ key
[i
]];
1238 return *(DWORD
*)key
;
1241 static inline HASH_CACHEFILE_ENTRY
* URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader
, DWORD dwOffset
)
1243 return (HASH_CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ dwOffset
);
1246 static inline BOOL
URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader
, const HASH_CACHEFILE_ENTRY
*pHashEntry
)
1248 /* check pHashEntry located within acceptable bounds in the URL cache mapping */
1249 return ((DWORD
)((const BYTE
*)pHashEntry
- (const BYTE
*)pHeader
) >= ENTRY_START_OFFSET
) &&
1250 ((DWORD
)((const BYTE
*)pHashEntry
- (const BYTE
*)pHeader
) < pHeader
->dwFileSize
);
1253 static BOOL
URLCache_FindHash(LPCURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, struct _HASH_ENTRY
** ppHashEntry
)
1255 /* structure of hash table:
1256 * 448 entries divided into 64 blocks
1257 * each block therefore contains a chain of 7 key/offset pairs
1258 * how position in table is calculated:
1259 * 1. the url is hashed in helper function
1260 * 2. the key % HASHTABLE_NUM_ENTRIES is the bucket number
1261 * 3. bucket number * HASHTABLE_BLOCKSIZE is offset of the bucket
1264 * there can be multiple hash tables in the file and the offset to
1265 * the next one is stored in the header of the hash table
1267 DWORD key
= URLCache_HashKey(lpszUrl
);
1268 DWORD offset
= (key
& (HASHTABLE_NUM_ENTRIES
-1)) * HASHTABLE_BLOCKSIZE
;
1269 HASH_CACHEFILE_ENTRY
* pHashEntry
;
1270 DWORD dwHashTableNumber
= 0;
1272 key
>>= HASHTABLE_FLAG_BITS
;
1274 for (pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1275 URLCache_IsHashEntryValid(pHeader
, pHashEntry
);
1276 pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHashEntry
->dwAddressNext
))
1279 if (pHashEntry
->dwHashTableNumber
!= dwHashTableNumber
++)
1281 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry
->dwHashTableNumber
, dwHashTableNumber
);
1284 /* make sure that it is in fact a hash entry */
1285 if (pHashEntry
->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1287 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&pHashEntry
->CacheFileEntry
.dwSignature
);
1291 for (i
= 0; i
< HASHTABLE_BLOCKSIZE
; i
++)
1293 struct _HASH_ENTRY
* pHashElement
= &pHashEntry
->HashTable
[offset
+ i
];
1294 if (key
== pHashElement
->dwHashKey
>>HASHTABLE_FLAG_BITS
)
1296 /* FIXME: we should make sure that this is the right element
1297 * before returning and claiming that it is. We can do this
1298 * by doing a simple compare between the URL we were given
1299 * and the URL stored in the entry. However, this assumes
1300 * we know the format of all the entries stored in the
1302 *ppHashEntry
= pHashElement
;
1310 static BOOL
URLCache_FindHashW(LPCURLCACHE_HEADER pHeader
, LPCWSTR lpszUrl
, struct _HASH_ENTRY
** ppHashEntry
)
1315 urlA
= heap_strdupWtoA(lpszUrl
);
1318 SetLastError(ERROR_OUTOFMEMORY
);
1322 ret
= URLCache_FindHash(pHeader
, urlA
, ppHashEntry
);
1327 /***********************************************************************
1328 * URLCache_HashEntrySetFlags (Internal)
1330 * Sets special bits in hash key
1336 static void URLCache_HashEntrySetFlags(struct _HASH_ENTRY
* pHashEntry
, DWORD dwFlag
)
1338 pHashEntry
->dwHashKey
= (pHashEntry
->dwHashKey
>> HASHTABLE_FLAG_BITS
<< HASHTABLE_FLAG_BITS
) | dwFlag
;
1341 /***********************************************************************
1342 * URLCache_DeleteEntryFromHash (Internal)
1344 * Searches all the hash tables in the index for the given URL and
1345 * then if found deletes the entry.
1348 * TRUE if the entry was found
1349 * FALSE if the entry could not be found
1352 static BOOL
URLCache_DeleteEntryFromHash(struct _HASH_ENTRY
* pHashEntry
)
1354 pHashEntry
->dwHashKey
= HASHTABLE_DEL
;
1358 /***********************************************************************
1359 * URLCache_AddEntryToHash (Internal)
1361 * Searches all the hash tables for a free slot based on the offset
1362 * generated from the hash key. If a free slot is found, the offset and
1363 * key are entered into the hash table.
1366 * ERROR_SUCCESS if the entry was added
1367 * Any other Win32 error code if the entry could not be added
1370 static DWORD
URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, DWORD dwOffsetEntry
, DWORD dwFieldType
)
1372 /* see URLCache_FindEntryInHash for structure of hash tables */
1374 DWORD key
= URLCache_HashKey(lpszUrl
);
1375 DWORD offset
= (key
& (HASHTABLE_NUM_ENTRIES
-1)) * HASHTABLE_BLOCKSIZE
;
1376 HASH_CACHEFILE_ENTRY
* pHashEntry
, *pHashPrev
= NULL
;
1377 DWORD dwHashTableNumber
= 0;
1380 key
= ((key
>> HASHTABLE_FLAG_BITS
) << HASHTABLE_FLAG_BITS
) + dwFieldType
;
1382 for (pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1383 URLCache_IsHashEntryValid(pHeader
, pHashEntry
);
1384 pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHashEntry
->dwAddressNext
))
1387 pHashPrev
= pHashEntry
;
1389 if (pHashEntry
->dwHashTableNumber
!= dwHashTableNumber
++)
1391 ERR("not right hash table number (%d) expected %d\n", pHashEntry
->dwHashTableNumber
, dwHashTableNumber
);
1394 /* make sure that it is in fact a hash entry */
1395 if (pHashEntry
->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1397 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&pHashEntry
->CacheFileEntry
.dwSignature
);
1401 for (i
= 0; i
< HASHTABLE_BLOCKSIZE
; i
++)
1403 struct _HASH_ENTRY
* pHashElement
= &pHashEntry
->HashTable
[offset
+ i
];
1404 if (pHashElement
->dwHashKey
==HASHTABLE_FREE
|| pHashElement
->dwHashKey
==HASHTABLE_DEL
) /* if the slot is free */
1406 pHashElement
->dwHashKey
= key
;
1407 pHashElement
->dwOffsetEntry
= dwOffsetEntry
;
1408 return ERROR_SUCCESS
;
1412 error
= URLCache_CreateHashTable(pHeader
, pHashPrev
, &pHashEntry
);
1413 if (error
!= ERROR_SUCCESS
)
1416 pHashEntry
->HashTable
[offset
].dwHashKey
= key
;
1417 pHashEntry
->HashTable
[offset
].dwOffsetEntry
= dwOffsetEntry
;
1418 return ERROR_SUCCESS
;
1421 /***********************************************************************
1422 * URLCache_CreateHashTable (Internal)
1424 * Creates a new hash table in free space and adds it to the chain of existing
1428 * ERROR_SUCCESS if the hash table was created
1429 * ERROR_DISK_FULL if the hash table could not be created
1432 static DWORD
URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader
, HASH_CACHEFILE_ENTRY
*pPrevHash
, HASH_CACHEFILE_ENTRY
**ppHash
)
1434 DWORD dwOffset
, error
;
1437 if ((error
= URLCache_FindFirstFreeEntry(pHeader
, 0x20, (CACHEFILE_ENTRY
**)ppHash
)) != ERROR_SUCCESS
)
1440 dwOffset
= (BYTE
*)*ppHash
- (BYTE
*)pHeader
;
1443 pPrevHash
->dwAddressNext
= dwOffset
;
1445 pHeader
->dwOffsetFirstHashTable
= dwOffset
;
1446 (*ppHash
)->CacheFileEntry
.dwSignature
= HASH_SIGNATURE
;
1447 (*ppHash
)->CacheFileEntry
.dwBlocksUsed
= 0x20;
1448 (*ppHash
)->dwAddressNext
= 0;
1449 (*ppHash
)->dwHashTableNumber
= pPrevHash
? pPrevHash
->dwHashTableNumber
+ 1 : 0;
1450 for (i
= 0; i
< HASHTABLE_SIZE
; i
++)
1452 (*ppHash
)->HashTable
[i
].dwOffsetEntry
= HASHTABLE_FREE
;
1453 (*ppHash
)->HashTable
[i
].dwHashKey
= HASHTABLE_FREE
;
1455 return ERROR_SUCCESS
;
1458 /***********************************************************************
1459 * URLCache_EnumHashTables (Internal)
1461 * Enumerates the hash tables in a container.
1464 * TRUE if an entry was found
1465 * FALSE if there are no more tables to enumerate.
1468 static BOOL
URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader
, DWORD
*pdwHashTableNumber
, HASH_CACHEFILE_ENTRY
** ppHashEntry
)
1470 for (*ppHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1471 URLCache_IsHashEntryValid(pHeader
, *ppHashEntry
);
1472 *ppHashEntry
= URLCache_HashEntryFromOffset(pHeader
, (*ppHashEntry
)->dwAddressNext
))
1474 TRACE("looking at hash table number %d\n", (*ppHashEntry
)->dwHashTableNumber
);
1475 if ((*ppHashEntry
)->dwHashTableNumber
!= *pdwHashTableNumber
)
1477 /* make sure that it is in fact a hash entry */
1478 if ((*ppHashEntry
)->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1480 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&(*ppHashEntry
)->CacheFileEntry
.dwSignature
);
1481 (*pdwHashTableNumber
)++;
1485 TRACE("hash table number %d found\n", *pdwHashTableNumber
);
1491 /***********************************************************************
1492 * URLCache_EnumHashTableEntries (Internal)
1494 * Enumerates entries in a hash table and returns the next non-free entry.
1497 * TRUE if an entry was found
1498 * FALSE if the hash table is empty or there are no more entries to
1502 static BOOL
URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader
, const HASH_CACHEFILE_ENTRY
* pHashEntry
,
1503 DWORD
* index
, const struct _HASH_ENTRY
** ppHashEntry
)
1505 for (; *index
< HASHTABLE_SIZE
; (*index
)++)
1507 if (pHashEntry
->HashTable
[*index
].dwHashKey
==HASHTABLE_FREE
|| pHashEntry
->HashTable
[*index
].dwHashKey
==HASHTABLE_DEL
)
1510 *ppHashEntry
= &pHashEntry
->HashTable
[*index
];
1511 TRACE("entry found %d\n", *index
);
1514 TRACE("no more entries (%d)\n", *index
);
1518 /***********************************************************************
1519 * URLCache_DeleteCacheDirectory (Internal)
1521 * Erase a directory containing an URL cache.
1524 * TRUE success, FALSE failure/aborted.
1527 static BOOL
URLCache_DeleteCacheDirectory(LPCWSTR lpszPath
)
1530 WCHAR path
[MAX_PATH
+ 1];
1531 SHFILEOPSTRUCTW shfos
;
1534 path_len
= strlenW(lpszPath
);
1535 if (path_len
>= MAX_PATH
)
1537 strcpyW(path
, lpszPath
);
1538 path
[path_len
+ 1] = 0; /* double-NUL-terminate path */
1541 shfos
.wFunc
= FO_DELETE
;
1545 shfos
.fAnyOperationsAborted
= FALSE
;
1546 ret
= SHFileOperationW(&shfos
);
1548 ERR("SHFileOperationW on %s returned %i\n", debugstr_w(path
), ret
);
1549 return !(ret
|| shfos
.fAnyOperationsAborted
);
1552 /***********************************************************************
1553 * FreeUrlCacheSpaceW (WININET.@)
1555 * Frees up some cache.
1558 * lpszCachePath [I] Which volume to free up from, or NULL if you don't care.
1559 * dwSize [I] How much space to free up.
1560 * dwSizeType [I] How to interpret dwSize.
1563 * TRUE success. FALSE failure.
1566 * This implementation just retrieves the path of the cache directory, and
1567 * deletes its contents from the filesystem. The correct approach would
1568 * probably be to implement and use {FindFirst,FindNext,Delete}UrlCacheGroup().
1570 BOOL WINAPI
FreeUrlCacheSpaceW(LPCWSTR lpszCachePath
, DWORD dwSize
, DWORD dwSizeType
)
1572 URLCACHECONTAINER
* pContainer
;
1574 if (lpszCachePath
!= NULL
|| dwSize
!= 100 || dwSizeType
!= FCS_PERCENT_CACHE_SPACE
)
1576 FIXME("(%s, %x, %x): partial stub!\n", debugstr_w(lpszCachePath
), dwSize
, dwSizeType
);
1577 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1581 LIST_FOR_EACH_ENTRY(pContainer
, &UrlContainers
, URLCACHECONTAINER
, entry
)
1583 /* The URL cache has prefix L"" (unlike Cookies and History) */
1584 if (pContainer
->cache_prefix
[0] == 0)
1588 WaitForSingleObject(pContainer
->hMutex
, INFINITE
);
1590 /* unlock, delete, recreate and lock cache */
1591 URLCacheContainer_CloseIndex(pContainer
);
1592 ret_del
= URLCache_DeleteCacheDirectory(pContainer
->path
);
1593 ret_open
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
1595 ReleaseMutex(pContainer
->hMutex
);
1596 return ret_del
&& (ret_open
== ERROR_SUCCESS
);
1602 /***********************************************************************
1603 * FreeUrlCacheSpaceA (WININET.@)
1605 * See FreeUrlCacheSpaceW.
1607 BOOL WINAPI
FreeUrlCacheSpaceA(LPCSTR lpszCachePath
, DWORD dwSize
, DWORD dwSizeType
)
1610 LPWSTR path
= heap_strdupAtoW(lpszCachePath
);
1611 if (lpszCachePath
== NULL
|| path
!= NULL
)
1612 ret
= FreeUrlCacheSpaceW(path
, dwSize
, dwSizeType
);
1617 /***********************************************************************
1618 * GetUrlCacheEntryInfoExA (WININET.@)
1621 BOOL WINAPI
GetUrlCacheEntryInfoExA(
1623 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1624 LPDWORD lpdwCacheEntryInfoBufSize
,
1626 LPDWORD lpdwReserved
,
1630 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1631 debugstr_a(lpszUrl
),
1633 lpdwCacheEntryInfoBufSize
,
1639 if ((lpszReserved
!= NULL
) ||
1640 (lpdwReserved
!= NULL
) ||
1641 (lpReserved
!= NULL
))
1643 ERR("Reserved value was not 0\n");
1644 SetLastError(ERROR_INVALID_PARAMETER
);
1649 FIXME("Undocumented flag(s): %x\n", dwFlags
);
1650 SetLastError(ERROR_FILE_NOT_FOUND
);
1653 return GetUrlCacheEntryInfoA(lpszUrl
, lpCacheEntryInfo
, lpdwCacheEntryInfoBufSize
);
1656 /***********************************************************************
1657 * GetUrlCacheEntryInfoA (WININET.@)
1660 BOOL WINAPI
GetUrlCacheEntryInfoA(
1661 IN LPCSTR lpszUrlName
,
1662 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1663 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1666 LPURLCACHE_HEADER pHeader
;
1667 struct _HASH_ENTRY
* pHashEntry
;
1668 const CACHEFILE_ENTRY
* pEntry
;
1669 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
1670 URLCACHECONTAINER
* pContainer
;
1673 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
, lpdwCacheEntryInfoBufferSize
);
1675 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
1676 if (error
!= ERROR_SUCCESS
)
1678 SetLastError(error
);
1682 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
1683 if (error
!= ERROR_SUCCESS
)
1685 SetLastError(error
);
1689 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1692 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
1694 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1695 WARN("entry %s not found!\n", debugstr_a(lpszUrlName
));
1696 SetLastError(ERROR_FILE_NOT_FOUND
);
1700 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1701 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1703 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1704 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1705 SetLastError(ERROR_FILE_NOT_FOUND
);
1709 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
1710 TRACE("Found URL: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
));
1711 if (pUrlEntry
->dwOffsetHeaderInfo
)
1712 TRACE("Header info: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
1714 if (lpdwCacheEntryInfoBufferSize
)
1716 if (!lpCacheEntryInfo
)
1717 *lpdwCacheEntryInfoBufferSize
= 0;
1719 error
= URLCache_CopyEntry(
1723 lpdwCacheEntryInfoBufferSize
,
1726 if (error
!= ERROR_SUCCESS
)
1728 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1729 SetLastError(error
);
1732 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
1735 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1740 /***********************************************************************
1741 * GetUrlCacheEntryInfoW (WININET.@)
1744 BOOL WINAPI
GetUrlCacheEntryInfoW(LPCWSTR lpszUrl
,
1745 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1746 LPDWORD lpdwCacheEntryInfoBufferSize
)
1748 LPURLCACHE_HEADER pHeader
;
1749 struct _HASH_ENTRY
* pHashEntry
;
1750 const CACHEFILE_ENTRY
* pEntry
;
1751 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
1752 URLCACHECONTAINER
* pContainer
;
1755 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl
), lpCacheEntryInfo
, lpdwCacheEntryInfoBufferSize
);
1757 error
= URLCacheContainers_FindContainerW(lpszUrl
, &pContainer
);
1758 if (error
!= ERROR_SUCCESS
)
1760 SetLastError(error
);
1764 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
1765 if (error
!= ERROR_SUCCESS
)
1767 SetLastError(error
);
1771 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1774 if (!URLCache_FindHashW(pHeader
, lpszUrl
, &pHashEntry
))
1776 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1777 WARN("entry %s not found!\n", debugstr_w(lpszUrl
));
1778 SetLastError(ERROR_FILE_NOT_FOUND
);
1782 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1783 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1785 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1786 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1787 SetLastError(ERROR_FILE_NOT_FOUND
);
1791 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
1792 TRACE("Found URL: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
));
1793 TRACE("Header info: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
1795 if (lpdwCacheEntryInfoBufferSize
)
1797 if (!lpCacheEntryInfo
)
1798 *lpdwCacheEntryInfoBufferSize
= 0;
1800 error
= URLCache_CopyEntry(
1803 (LPINTERNET_CACHE_ENTRY_INFOA
)lpCacheEntryInfo
,
1804 lpdwCacheEntryInfoBufferSize
,
1806 TRUE
/* UNICODE */);
1807 if (error
!= ERROR_SUCCESS
)
1809 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1810 SetLastError(error
);
1813 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
1816 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1821 /***********************************************************************
1822 * GetUrlCacheEntryInfoExW (WININET.@)
1825 BOOL WINAPI
GetUrlCacheEntryInfoExW(
1827 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1828 LPDWORD lpdwCacheEntryInfoBufSize
,
1829 LPWSTR lpszReserved
,
1830 LPDWORD lpdwReserved
,
1834 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1835 debugstr_w(lpszUrl
),
1837 lpdwCacheEntryInfoBufSize
,
1843 if ((lpszReserved
!= NULL
) ||
1844 (lpdwReserved
!= NULL
) ||
1845 (lpReserved
!= NULL
))
1847 ERR("Reserved value was not 0\n");
1848 SetLastError(ERROR_INVALID_PARAMETER
);
1853 FIXME("Undocumented flag(s): %x\n", dwFlags
);
1854 SetLastError(ERROR_FILE_NOT_FOUND
);
1857 return GetUrlCacheEntryInfoW(lpszUrl
, lpCacheEntryInfo
, lpdwCacheEntryInfoBufSize
);
1860 /***********************************************************************
1861 * SetUrlCacheEntryInfoA (WININET.@)
1863 BOOL WINAPI
SetUrlCacheEntryInfoA(
1865 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1866 DWORD dwFieldControl
)
1868 LPURLCACHE_HEADER pHeader
;
1869 struct _HASH_ENTRY
* pHashEntry
;
1870 CACHEFILE_ENTRY
* pEntry
;
1871 URLCACHECONTAINER
* pContainer
;
1874 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
, dwFieldControl
);
1876 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
1877 if (error
!= ERROR_SUCCESS
)
1879 SetLastError(error
);
1883 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
1884 if (error
!= ERROR_SUCCESS
)
1886 SetLastError(error
);
1890 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1893 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
1895 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1896 WARN("entry %s not found!\n", debugstr_a(lpszUrlName
));
1897 SetLastError(ERROR_FILE_NOT_FOUND
);
1901 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1902 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1904 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1905 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1906 SetLastError(ERROR_FILE_NOT_FOUND
);
1910 URLCache_SetEntryInfo(
1911 (URL_CACHEFILE_ENTRY
*)pEntry
,
1912 (const INTERNET_CACHE_ENTRY_INFOW
*)lpCacheEntryInfo
,
1915 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1920 /***********************************************************************
1921 * SetUrlCacheEntryInfoW (WININET.@)
1923 BOOL WINAPI
SetUrlCacheEntryInfoW(LPCWSTR lpszUrl
, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
, DWORD dwFieldControl
)
1925 LPURLCACHE_HEADER pHeader
;
1926 struct _HASH_ENTRY
* pHashEntry
;
1927 CACHEFILE_ENTRY
* pEntry
;
1928 URLCACHECONTAINER
* pContainer
;
1931 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl
), lpCacheEntryInfo
, dwFieldControl
);
1933 error
= URLCacheContainers_FindContainerW(lpszUrl
, &pContainer
);
1934 if (error
!= ERROR_SUCCESS
)
1936 SetLastError(error
);
1940 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
1941 if (error
!= ERROR_SUCCESS
)
1943 SetLastError(error
);
1947 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1950 if (!URLCache_FindHashW(pHeader
, lpszUrl
, &pHashEntry
))
1952 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1953 WARN("entry %s not found!\n", debugstr_w(lpszUrl
));
1954 SetLastError(ERROR_FILE_NOT_FOUND
);
1958 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1959 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1961 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1962 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1963 SetLastError(ERROR_FILE_NOT_FOUND
);
1967 URLCache_SetEntryInfo(
1968 (URL_CACHEFILE_ENTRY
*)pEntry
,
1972 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1977 /***********************************************************************
1978 * RetrieveUrlCacheEntryFileA (WININET.@)
1981 BOOL WINAPI
RetrieveUrlCacheEntryFileA(
1982 IN LPCSTR lpszUrlName
,
1983 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1984 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
1988 LPURLCACHE_HEADER pHeader
;
1989 struct _HASH_ENTRY
* pHashEntry
;
1990 CACHEFILE_ENTRY
* pEntry
;
1991 URL_CACHEFILE_ENTRY
* pUrlEntry
;
1992 URLCACHECONTAINER
* pContainer
;
1995 TRACE("(%s, %p, %p, 0x%08x)\n",
1996 debugstr_a(lpszUrlName
),
1998 lpdwCacheEntryInfoBufferSize
,
2001 if (!lpszUrlName
|| !lpdwCacheEntryInfoBufferSize
||
2002 (!lpCacheEntryInfo
&& *lpdwCacheEntryInfoBufferSize
))
2004 SetLastError(ERROR_INVALID_PARAMETER
);
2008 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
2009 if (error
!= ERROR_SUCCESS
)
2011 SetLastError(error
);
2015 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2016 if (error
!= ERROR_SUCCESS
)
2018 SetLastError(error
);
2022 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2025 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
2027 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2028 TRACE("entry %s not found!\n", lpszUrlName
);
2029 SetLastError(ERROR_FILE_NOT_FOUND
);
2033 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2034 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2036 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2037 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2038 SetLastError(ERROR_FILE_NOT_FOUND
);
2042 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2043 if (!pUrlEntry
->dwOffsetLocalName
)
2045 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2046 SetLastError(ERROR_INVALID_DATA
);
2050 TRACE("Found URL: %s\n", (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
2051 TRACE("Header info: %s\n", (LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
);
2053 error
= URLCache_CopyEntry(pContainer
, pHeader
, lpCacheEntryInfo
,
2054 lpdwCacheEntryInfoBufferSize
, pUrlEntry
,
2056 if (error
!= ERROR_SUCCESS
)
2058 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2059 SetLastError(error
);
2062 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
2064 pUrlEntry
->dwHitRate
++;
2065 pUrlEntry
->dwUseCount
++;
2066 URLCache_HashEntrySetFlags(pHashEntry
, HASHTABLE_LOCK
);
2067 GetSystemTimeAsFileTime(&pUrlEntry
->LastAccessTime
);
2069 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2074 /***********************************************************************
2075 * RetrieveUrlCacheEntryFileW (WININET.@)
2078 BOOL WINAPI
RetrieveUrlCacheEntryFileW(
2079 IN LPCWSTR lpszUrlName
,
2080 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
2081 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
2085 LPURLCACHE_HEADER pHeader
;
2086 struct _HASH_ENTRY
* pHashEntry
;
2087 CACHEFILE_ENTRY
* pEntry
;
2088 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2089 URLCACHECONTAINER
* pContainer
;
2092 TRACE("(%s, %p, %p, 0x%08x)\n",
2093 debugstr_w(lpszUrlName
),
2095 lpdwCacheEntryInfoBufferSize
,
2098 if (!lpszUrlName
|| !lpdwCacheEntryInfoBufferSize
||
2099 (!lpCacheEntryInfo
&& *lpdwCacheEntryInfoBufferSize
))
2101 SetLastError(ERROR_INVALID_PARAMETER
);
2105 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2106 if (error
!= ERROR_SUCCESS
)
2108 SetLastError(error
);
2112 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2113 if (error
!= ERROR_SUCCESS
)
2115 SetLastError(error
);
2119 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2122 if (!URLCache_FindHashW(pHeader
, lpszUrlName
, &pHashEntry
))
2124 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2125 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName
));
2126 SetLastError(ERROR_FILE_NOT_FOUND
);
2130 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2131 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2133 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2134 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2135 SetLastError(ERROR_FILE_NOT_FOUND
);
2139 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2140 if (!pUrlEntry
->dwOffsetLocalName
)
2142 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2143 SetLastError(ERROR_INVALID_DATA
);
2147 TRACE("Found URL: %s\n", (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
2148 TRACE("Header info: %s\n", (LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
);
2150 error
= URLCache_CopyEntry(
2153 (LPINTERNET_CACHE_ENTRY_INFOA
)lpCacheEntryInfo
,
2154 lpdwCacheEntryInfoBufferSize
,
2156 TRUE
/* UNICODE */);
2157 if (error
!= ERROR_SUCCESS
)
2159 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2160 SetLastError(error
);
2163 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
2165 pUrlEntry
->dwHitRate
++;
2166 pUrlEntry
->dwUseCount
++;
2167 URLCache_HashEntrySetFlags(pHashEntry
, HASHTABLE_LOCK
);
2168 GetSystemTimeAsFileTime(&pUrlEntry
->LastAccessTime
);
2170 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2175 static BOOL
DeleteUrlCacheEntryInternal(LPURLCACHE_HEADER pHeader
,
2176 struct _HASH_ENTRY
*pHashEntry
)
2178 CACHEFILE_ENTRY
* pEntry
;
2179 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2181 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2182 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2184 FIXME("Trying to delete entry of unknown format %s\n",
2185 debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2186 SetLastError(ERROR_FILE_NOT_FOUND
);
2190 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2191 if ((pHashEntry
->dwHashKey
& ((1<<HASHTABLE_FLAG_BITS
)-1)) == HASHTABLE_LOCK
)
2193 /* FIXME: implement timeout object unlocking */
2194 TRACE("Trying to delete locked entry\n");
2195 pUrlEntry
->CacheEntryType
|= DELETED_CACHE_ENTRY
;
2196 SetLastError(ERROR_SHARING_VIOLATION
);
2200 if (pUrlEntry
->CacheDir
< pHeader
->DirectoryCount
)
2202 if (pHeader
->directory_data
[pUrlEntry
->CacheDir
].dwNumFiles
)
2203 pHeader
->directory_data
[pUrlEntry
->CacheDir
].dwNumFiles
--;
2205 if (pUrlEntry
->CacheEntryType
& STICKY_CACHE_ENTRY
)
2207 if (pUrlEntry
->size
.QuadPart
< pHeader
->ExemptUsage
.QuadPart
)
2208 pHeader
->ExemptUsage
.QuadPart
-= pUrlEntry
->size
.QuadPart
;
2210 pHeader
->ExemptUsage
.QuadPart
= 0;
2214 if (pUrlEntry
->size
.QuadPart
< pHeader
->CacheUsage
.QuadPart
)
2215 pHeader
->CacheUsage
.QuadPart
-= pUrlEntry
->size
.QuadPart
;
2217 pHeader
->CacheUsage
.QuadPart
= 0;
2220 URLCache_DeleteEntry(pHeader
, pEntry
);
2222 URLCache_DeleteEntryFromHash(pHashEntry
);
2226 /***********************************************************************
2227 * UnlockUrlCacheEntryFileA (WININET.@)
2230 BOOL WINAPI
UnlockUrlCacheEntryFileA(
2231 IN LPCSTR lpszUrlName
,
2235 LPURLCACHE_HEADER pHeader
;
2236 struct _HASH_ENTRY
* pHashEntry
;
2237 CACHEFILE_ENTRY
* pEntry
;
2238 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2239 URLCACHECONTAINER
* pContainer
;
2242 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName
), dwReserved
);
2246 ERR("dwReserved != 0\n");
2247 SetLastError(ERROR_INVALID_PARAMETER
);
2251 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
2252 if (error
!= ERROR_SUCCESS
)
2254 SetLastError(error
);
2258 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2259 if (error
!= ERROR_SUCCESS
)
2261 SetLastError(error
);
2265 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2268 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
2270 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2271 TRACE("entry %s not found!\n", lpszUrlName
);
2272 SetLastError(ERROR_FILE_NOT_FOUND
);
2276 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2277 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2279 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2280 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2281 SetLastError(ERROR_FILE_NOT_FOUND
);
2285 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2287 if (pUrlEntry
->dwUseCount
== 0)
2289 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2292 pUrlEntry
->dwUseCount
--;
2293 if (!pUrlEntry
->dwUseCount
)
2295 URLCache_HashEntrySetFlags(pHashEntry
, HASHTABLE_URL
);
2296 if (pUrlEntry
->CacheEntryType
& DELETED_CACHE_ENTRY
)
2297 DeleteUrlCacheEntryInternal(pHeader
, pHashEntry
);
2300 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2305 /***********************************************************************
2306 * UnlockUrlCacheEntryFileW (WININET.@)
2309 BOOL WINAPI
UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName
, DWORD dwReserved
)
2311 LPURLCACHE_HEADER pHeader
;
2312 struct _HASH_ENTRY
* pHashEntry
;
2313 CACHEFILE_ENTRY
* pEntry
;
2314 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2315 URLCACHECONTAINER
* pContainer
;
2318 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName
), dwReserved
);
2322 ERR("dwReserved != 0\n");
2323 SetLastError(ERROR_INVALID_PARAMETER
);
2327 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2328 if (error
!= ERROR_SUCCESS
)
2330 SetLastError(error
);
2334 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2335 if (error
!= ERROR_SUCCESS
)
2337 SetLastError(error
);
2341 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2344 if (!URLCache_FindHashW(pHeader
, lpszUrlName
, &pHashEntry
))
2346 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2347 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName
));
2348 SetLastError(ERROR_FILE_NOT_FOUND
);
2352 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2353 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2355 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2356 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2357 SetLastError(ERROR_FILE_NOT_FOUND
);
2361 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2363 if (pUrlEntry
->dwUseCount
== 0)
2365 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2368 pUrlEntry
->dwUseCount
--;
2369 if (!pUrlEntry
->dwUseCount
)
2370 URLCache_HashEntrySetFlags(pHashEntry
, HASHTABLE_URL
);
2372 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2377 /***********************************************************************
2378 * CreateUrlCacheEntryA (WININET.@)
2381 BOOL WINAPI
CreateUrlCacheEntryA(
2382 IN LPCSTR lpszUrlName
,
2383 IN DWORD dwExpectedFileSize
,
2384 IN LPCSTR lpszFileExtension
,
2385 OUT LPSTR lpszFileName
,
2390 WCHAR
*file_extension
= NULL
;
2391 WCHAR file_name
[MAX_PATH
];
2392 BOOL bSuccess
= FALSE
;
2395 TRACE("(%s %d %s %p %d)\n", debugstr_a(lpszUrlName
), dwExpectedFileSize
,
2396 debugstr_a(lpszFileExtension
), lpszFileName
, dwReserved
);
2398 if (lpszUrlName
&& (url_name
= heap_strdupAtoW(lpszUrlName
)))
2400 if (!lpszFileExtension
|| (file_extension
= heap_strdupAtoW(lpszFileExtension
)))
2402 if (CreateUrlCacheEntryW(url_name
, dwExpectedFileSize
, file_extension
, file_name
, dwReserved
))
2404 if (WideCharToMultiByte(CP_ACP
, 0, file_name
, -1, lpszFileName
, MAX_PATH
, NULL
, NULL
) < MAX_PATH
)
2410 dwError
= GetLastError();
2415 dwError
= GetLastError();
2417 heap_free(file_extension
);
2421 dwError
= GetLastError();
2423 heap_free(url_name
);
2424 if (!bSuccess
) SetLastError(dwError
);
2428 /***********************************************************************
2429 * CreateUrlCacheEntryW (WININET.@)
2432 BOOL WINAPI
CreateUrlCacheEntryW(
2433 IN LPCWSTR lpszUrlName
,
2434 IN DWORD dwExpectedFileSize
,
2435 IN LPCWSTR lpszFileExtension
,
2436 OUT LPWSTR lpszFileName
,
2440 URLCACHECONTAINER
* pContainer
;
2441 LPURLCACHE_HEADER pHeader
;
2442 CHAR szFile
[MAX_PATH
];
2443 WCHAR szExtension
[MAX_PATH
];
2444 LPCWSTR lpszUrlPart
;
2446 LPCWSTR lpszFileNameExtension
;
2447 LPWSTR lpszFileNameNoPath
;
2449 int countnoextension
;
2452 BOOL bFound
= FALSE
;
2458 static const WCHAR szWWW
[] = {'w','w','w',0};
2459 static const WCHAR fmt
[] = {'%','0','8','X','%','s',0};
2461 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2462 debugstr_w(lpszUrlName
),
2464 debugstr_w(lpszFileExtension
),
2469 FIXME("dwReserved 0x%08x\n", dwReserved
);
2471 lpszUrlEnd
= lpszUrlName
+ strlenW(lpszUrlName
);
2473 if (((lpszUrlEnd
- lpszUrlName
) > 1) && (*(lpszUrlEnd
- 1) == '/' || *(lpszUrlEnd
- 1) == '\\'))
2476 lpszUrlPart
= memchrW(lpszUrlName
, '?', lpszUrlEnd
- lpszUrlName
);
2478 lpszUrlPart
= memchrW(lpszUrlName
, '#', lpszUrlEnd
- lpszUrlName
);
2480 lpszUrlEnd
= lpszUrlPart
;
2482 for (lpszUrlPart
= lpszUrlEnd
;
2483 (lpszUrlPart
>= lpszUrlName
);
2486 if ((*lpszUrlPart
== '/' || *lpszUrlPart
== '\\') && ((lpszUrlEnd
- lpszUrlPart
) > 1))
2493 if (!lstrcmpW(lpszUrlPart
, szWWW
))
2495 lpszUrlPart
+= lstrlenW(szWWW
);
2498 count
= lpszUrlEnd
- lpszUrlPart
;
2500 if (bFound
&& (count
< MAX_PATH
))
2502 int len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlPart
, count
, szFile
, sizeof(szFile
) - 1, NULL
, NULL
);
2506 while(len
&& szFile
[--len
] == '/') szFile
[len
] = '\0';
2508 /* FIXME: get rid of illegal characters like \, / and : */
2512 FIXME("need to generate a random filename\n");
2515 TRACE("File name: %s\n", debugstr_a(szFile
));
2517 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2518 if (error
!= ERROR_SUCCESS
)
2520 SetLastError(error
);
2524 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2525 if (error
!= ERROR_SUCCESS
)
2527 SetLastError(error
);
2531 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2534 CacheDir
= (BYTE
)(rand() % pHeader
->DirectoryCount
);
2536 lBufferSize
= MAX_PATH
* sizeof(WCHAR
);
2537 if (!URLCache_LocalFileNameToPathW(pContainer
, pHeader
, szFile
, CacheDir
, lpszFileName
, &lBufferSize
))
2539 WARN("Failed to get full path for filename %s, needed %u bytes.\n",
2540 debugstr_a(szFile
), lBufferSize
);
2541 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2545 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2547 for (lpszFileNameNoPath
= lpszFileName
+ lBufferSize
/ sizeof(WCHAR
) - 2;
2548 lpszFileNameNoPath
>= lpszFileName
;
2549 --lpszFileNameNoPath
)
2551 if (*lpszFileNameNoPath
== '/' || *lpszFileNameNoPath
== '\\')
2555 countnoextension
= lstrlenW(lpszFileNameNoPath
);
2556 lpszFileNameExtension
= PathFindExtensionW(lpszFileNameNoPath
);
2557 if (lpszFileNameExtension
)
2558 countnoextension
-= lstrlenW(lpszFileNameExtension
);
2559 *szExtension
= '\0';
2561 if (lpszFileExtension
)
2563 szExtension
[0] = '.';
2564 lstrcpyW(szExtension
+1, lpszFileExtension
);
2567 for (i
= 0; i
< 255; i
++)
2569 static const WCHAR szFormat
[] = {'[','%','u',']','%','s',0};
2572 wsprintfW(lpszFileNameNoPath
+ countnoextension
, szFormat
, i
, szExtension
);
2573 for (p
= lpszFileNameNoPath
+ 1; *p
; p
++)
2579 case '/': case '\\':
2586 if (p
[-1] == ' ' || p
[-1] == '.') p
[-1] = '_';
2588 TRACE("Trying: %s\n", debugstr_w(lpszFileName
));
2589 hFile
= CreateFileW(lpszFileName
, GENERIC_READ
, 0, NULL
, CREATE_NEW
, 0, NULL
);
2590 if (hFile
!= INVALID_HANDLE_VALUE
)
2597 GetSystemTimeAsFileTime(&ft
);
2598 wsprintfW(lpszFileNameNoPath
+ countnoextension
, fmt
, ft
.dwLowDateTime
, szExtension
);
2600 TRACE("Trying: %s\n", debugstr_w(lpszFileName
));
2601 hFile
= CreateFileW(lpszFileName
, GENERIC_READ
, 0, NULL
, CREATE_NEW
, 0, NULL
);
2602 if (hFile
!= INVALID_HANDLE_VALUE
)
2608 WARN("Could not find a unique filename\n");
2613 /***********************************************************************
2614 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2616 * The bug we are compensating for is that some drongo at Microsoft
2617 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2618 * As a consequence, CommitUrlCacheEntryA has been effectively
2619 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2620 * is still defined as LPCWSTR. The result (other than madness) is
2621 * that we always need to store lpHeaderInfo in CP_ACP rather than
2622 * in UTF16, and we need to avoid converting lpHeaderInfo in
2623 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2624 * result will lose data for arbitrary binary data.
2627 static BOOL
CommitUrlCacheEntryInternal(
2628 IN LPCWSTR lpszUrlName
,
2629 IN LPCWSTR lpszLocalFileName
,
2630 IN FILETIME ExpireTime
,
2631 IN FILETIME LastModifiedTime
,
2632 IN DWORD CacheEntryType
,
2633 IN LPBYTE lpHeaderInfo
,
2634 IN DWORD dwHeaderSize
,
2635 IN LPCWSTR lpszFileExtension
,
2636 IN LPCWSTR lpszOriginalUrl
2639 URLCACHECONTAINER
* pContainer
;
2640 LPURLCACHE_HEADER pHeader
;
2641 struct _HASH_ENTRY
* pHashEntry
;
2642 CACHEFILE_ENTRY
* pEntry
;
2643 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2644 DWORD url_entry_offset
;
2645 DWORD dwBytesNeeded
= DWORD_ALIGN(sizeof(*pUrlEntry
));
2646 DWORD dwOffsetLocalFileName
= 0;
2647 DWORD dwOffsetHeader
= 0;
2648 DWORD dwOffsetFileExtension
= 0;
2649 LARGE_INTEGER file_size
;
2650 BYTE cDirectory
= 0;
2651 char achFile
[MAX_PATH
];
2652 LPSTR lpszUrlNameA
= NULL
;
2653 LPSTR lpszFileExtensionA
= NULL
;
2654 char *pchLocalFileName
= 0;
2657 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2658 debugstr_w(lpszUrlName
),
2659 debugstr_w(lpszLocalFileName
),
2663 debugstr_w(lpszFileExtension
),
2664 debugstr_w(lpszOriginalUrl
));
2666 if (CacheEntryType
& STICKY_CACHE_ENTRY
&& !lpszLocalFileName
)
2668 SetLastError(ERROR_INVALID_PARAMETER
);
2671 if (lpszOriginalUrl
)
2672 WARN(": lpszOriginalUrl ignored\n");
2674 file_size
.QuadPart
= 0;
2675 if (lpszLocalFileName
)
2679 hFile
= CreateFileW(lpszLocalFileName
, FILE_READ_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2680 if (hFile
== INVALID_HANDLE_VALUE
)
2682 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName
), GetLastError());
2687 if (!GetFileSizeEx(hFile
, &file_size
))
2689 ERR("couldn't get file size (error is %d)\n", GetLastError());
2697 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
2698 if (error
!= ERROR_SUCCESS
)
2700 SetLastError(error
);
2704 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
2705 if (error
!= ERROR_SUCCESS
)
2707 SetLastError(error
);
2711 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2714 lpszUrlNameA
= heap_strdupWtoA(lpszUrlName
);
2717 error
= GetLastError();
2721 if (lpszFileExtension
&& !(lpszFileExtensionA
= heap_strdupWtoA(lpszFileExtension
)))
2723 error
= GetLastError();
2727 if (URLCache_FindHash(pHeader
, lpszUrlNameA
, &pHashEntry
))
2729 if ((pHashEntry
->dwHashKey
& ((1<<HASHTABLE_FLAG_BITS
)-1)) == HASHTABLE_LOCK
)
2731 /* FIXME: implement timeout object unlocking */
2732 FIXME("Trying to overwrite locked entry\n");
2733 SetLastError(ERROR_SHARING_VIOLATION
);
2737 FIXME("entry already in cache - don't know what to do!\n");
2739 * SetLastError(ERROR_FILE_NOT_FOUND);
2745 if (lpszLocalFileName
)
2747 BOOL bFound
= FALSE
;
2749 if (strncmpW(lpszLocalFileName
, pContainer
->path
, lstrlenW(pContainer
->path
)))
2751 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName
), debugstr_w(pContainer
->path
));
2752 error
= ERROR_INVALID_PARAMETER
;
2756 /* skip container path prefix */
2757 lpszLocalFileName
+= lstrlenW(pContainer
->path
);
2759 WideCharToMultiByte(CP_ACP
, 0, lpszLocalFileName
, -1, achFile
, MAX_PATH
, NULL
, NULL
);
2760 pchLocalFileName
= achFile
;
2762 for (cDirectory
= 0; cDirectory
< pHeader
->DirectoryCount
; cDirectory
++)
2764 if (!strncmp(pHeader
->directory_data
[cDirectory
].filename
, pchLocalFileName
, DIR_LENGTH
))
2773 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName
));
2774 error
= ERROR_INVALID_PARAMETER
;
2778 lpszLocalFileName
+= DIR_LENGTH
+ 1;
2779 pchLocalFileName
+= DIR_LENGTH
+ 1;
2782 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(lpszUrlNameA
) + 1);
2783 if (lpszLocalFileName
)
2785 dwOffsetLocalFileName
= dwBytesNeeded
;
2786 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(pchLocalFileName
) + 1);
2790 dwOffsetHeader
= dwBytesNeeded
;
2791 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ dwHeaderSize
);
2793 if (lpszFileExtensionA
)
2795 dwOffsetFileExtension
= dwBytesNeeded
;
2796 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(lpszFileExtensionA
) + 1);
2799 /* round up to next block */
2800 if (dwBytesNeeded
% BLOCKSIZE
)
2802 dwBytesNeeded
-= dwBytesNeeded
% BLOCKSIZE
;
2803 dwBytesNeeded
+= BLOCKSIZE
;
2806 error
= URLCache_FindFirstFreeEntry(pHeader
, dwBytesNeeded
/ BLOCKSIZE
, &pEntry
);
2807 while (error
== ERROR_HANDLE_DISK_FULL
)
2809 error
= URLCacheContainer_CleanIndex(pContainer
, &pHeader
);
2810 if (error
== ERROR_SUCCESS
)
2811 error
= URLCache_FindFirstFreeEntry(pHeader
, dwBytesNeeded
/ BLOCKSIZE
, &pEntry
);
2813 if (error
!= ERROR_SUCCESS
)
2816 /* FindFirstFreeEntry fills in blocks used */
2817 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2818 url_entry_offset
= (LPBYTE
)pUrlEntry
- (LPBYTE
)pHeader
;
2819 pUrlEntry
->CacheFileEntry
.dwSignature
= URL_SIGNATURE
;
2820 pUrlEntry
->CacheDir
= cDirectory
;
2821 pUrlEntry
->CacheEntryType
= CacheEntryType
;
2822 pUrlEntry
->dwHeaderInfoSize
= dwHeaderSize
;
2823 if (CacheEntryType
& STICKY_CACHE_ENTRY
)
2825 /* Sticky entries have a default exempt time of one day */
2826 pUrlEntry
->dwExemptDelta
= 86400;
2829 pUrlEntry
->dwExemptDelta
= 0;
2830 pUrlEntry
->dwHitRate
= 0;
2831 pUrlEntry
->dwOffsetFileExtension
= dwOffsetFileExtension
;
2832 pUrlEntry
->dwOffsetHeaderInfo
= dwOffsetHeader
;
2833 pUrlEntry
->dwOffsetLocalName
= dwOffsetLocalFileName
;
2834 pUrlEntry
->dwOffsetUrl
= DWORD_ALIGN(sizeof(*pUrlEntry
));
2835 pUrlEntry
->size
.QuadPart
= file_size
.QuadPart
;
2836 pUrlEntry
->dwUseCount
= 0;
2837 GetSystemTimeAsFileTime(&pUrlEntry
->LastAccessTime
);
2838 pUrlEntry
->LastModifiedTime
= LastModifiedTime
;
2839 URLCache_FileTimeToDosDateTime(&pUrlEntry
->LastAccessTime
, &pUrlEntry
->wLastSyncDate
, &pUrlEntry
->wLastSyncTime
);
2840 URLCache_FileTimeToDosDateTime(&ExpireTime
, &pUrlEntry
->wExpiredDate
, &pUrlEntry
->wExpiredTime
);
2841 pUrlEntry
->wUnknownDate
= pUrlEntry
->wLastSyncDate
;
2842 pUrlEntry
->wUnknownTime
= pUrlEntry
->wLastSyncTime
;
2845 pUrlEntry
->dwUnknown1
= 0;
2846 pUrlEntry
->dwUnknown2
= 0;
2847 pUrlEntry
->dwUnknown3
= 0x60;
2848 pUrlEntry
->Unknown4
= 0;
2849 pUrlEntry
->wUnknown5
= 0x1010;
2850 pUrlEntry
->dwUnknown7
= 0;
2851 pUrlEntry
->dwUnknown8
= 0;
2854 strcpy((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, lpszUrlNameA
);
2855 if (dwOffsetLocalFileName
)
2856 strcpy((LPSTR
)((LPBYTE
)pUrlEntry
+ dwOffsetLocalFileName
), pchLocalFileName
);
2858 memcpy((LPBYTE
)pUrlEntry
+ dwOffsetHeader
, lpHeaderInfo
, dwHeaderSize
);
2859 if (dwOffsetFileExtension
)
2860 strcpy((LPSTR
)((LPBYTE
)pUrlEntry
+ dwOffsetFileExtension
), lpszFileExtensionA
);
2862 error
= URLCache_AddEntryToHash(pHeader
, lpszUrlNameA
, url_entry_offset
, HASHTABLE_URL
);
2863 while (error
== ERROR_HANDLE_DISK_FULL
)
2865 error
= URLCacheContainer_CleanIndex(pContainer
, &pHeader
);
2866 if (error
== ERROR_SUCCESS
)
2868 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ url_entry_offset
);
2869 error
= URLCache_AddEntryToHash(pHeader
, lpszUrlNameA
,
2870 url_entry_offset
, HASHTABLE_URL
);
2873 if (error
!= ERROR_SUCCESS
)
2874 URLCache_DeleteEntry(pHeader
, &pUrlEntry
->CacheFileEntry
);
2877 if (pUrlEntry
->CacheDir
< pHeader
->DirectoryCount
)
2878 pHeader
->directory_data
[pUrlEntry
->CacheDir
].dwNumFiles
++;
2879 if (CacheEntryType
& STICKY_CACHE_ENTRY
)
2880 pHeader
->ExemptUsage
.QuadPart
+= file_size
.QuadPart
;
2882 pHeader
->CacheUsage
.QuadPart
+= file_size
.QuadPart
;
2883 if (pHeader
->CacheUsage
.QuadPart
+ pHeader
->ExemptUsage
.QuadPart
>
2884 pHeader
->CacheLimit
.QuadPart
)
2885 FIXME("file of size %s bytes fills cache\n", wine_dbgstr_longlong(file_size
.QuadPart
));
2889 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2890 heap_free(lpszUrlNameA
);
2891 heap_free(lpszFileExtensionA
);
2893 if (error
== ERROR_SUCCESS
)
2897 SetLastError(error
);
2902 /***********************************************************************
2903 * CommitUrlCacheEntryA (WININET.@)
2906 BOOL WINAPI
CommitUrlCacheEntryA(
2907 IN LPCSTR lpszUrlName
,
2908 IN LPCSTR lpszLocalFileName
,
2909 IN FILETIME ExpireTime
,
2910 IN FILETIME LastModifiedTime
,
2911 IN DWORD CacheEntryType
,
2912 IN LPBYTE lpHeaderInfo
,
2913 IN DWORD dwHeaderSize
,
2914 IN LPCSTR lpszFileExtension
,
2915 IN LPCSTR lpszOriginalUrl
2918 WCHAR
*url_name
= NULL
;
2919 WCHAR
*local_file_name
= NULL
;
2920 WCHAR
*original_url
= NULL
;
2921 WCHAR
*file_extension
= NULL
;
2922 BOOL bSuccess
= FALSE
;
2924 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2925 debugstr_a(lpszUrlName
),
2926 debugstr_a(lpszLocalFileName
),
2930 debugstr_a(lpszFileExtension
),
2931 debugstr_a(lpszOriginalUrl
));
2933 url_name
= heap_strdupAtoW(lpszUrlName
);
2937 if (lpszLocalFileName
)
2939 local_file_name
= heap_strdupAtoW(lpszLocalFileName
);
2940 if (!local_file_name
)
2943 if (lpszFileExtension
)
2945 file_extension
= heap_strdupAtoW(lpszFileExtension
);
2946 if (!file_extension
)
2949 if (lpszOriginalUrl
)
2951 original_url
= heap_strdupAtoW(lpszOriginalUrl
);
2956 bSuccess
= CommitUrlCacheEntryInternal(url_name
, local_file_name
, ExpireTime
, LastModifiedTime
,
2957 CacheEntryType
, lpHeaderInfo
, dwHeaderSize
,
2958 file_extension
, original_url
);
2961 heap_free(original_url
);
2962 heap_free(file_extension
);
2963 heap_free(local_file_name
);
2964 heap_free(url_name
);
2968 /***********************************************************************
2969 * CommitUrlCacheEntryW (WININET.@)
2972 BOOL WINAPI
CommitUrlCacheEntryW(
2973 IN LPCWSTR lpszUrlName
,
2974 IN LPCWSTR lpszLocalFileName
,
2975 IN FILETIME ExpireTime
,
2976 IN FILETIME LastModifiedTime
,
2977 IN DWORD CacheEntryType
,
2978 IN LPWSTR lpHeaderInfo
,
2979 IN DWORD dwHeaderSize
,
2980 IN LPCWSTR lpszFileExtension
,
2981 IN LPCWSTR lpszOriginalUrl
2985 BOOL bSuccess
= FALSE
;
2987 CHAR
*header_info
= NULL
;
2989 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2990 debugstr_w(lpszUrlName
),
2991 debugstr_w(lpszLocalFileName
),
2995 debugstr_w(lpszFileExtension
),
2996 debugstr_w(lpszOriginalUrl
));
2998 if (!lpHeaderInfo
|| (header_info
= heap_strdupWtoA(lpHeaderInfo
)))
3000 if (CommitUrlCacheEntryInternal(lpszUrlName
, lpszLocalFileName
, ExpireTime
, LastModifiedTime
,
3001 CacheEntryType
, (LPBYTE
)header_info
, len
, lpszFileExtension
, lpszOriginalUrl
))
3007 dwError
= GetLastError();
3011 heap_free(header_info
);
3013 SetLastError(dwError
);
3019 /***********************************************************************
3020 * ReadUrlCacheEntryStream (WININET.@)
3023 BOOL WINAPI
ReadUrlCacheEntryStream(
3024 IN HANDLE hUrlCacheStream
,
3025 IN DWORD dwLocation
,
3026 IN OUT LPVOID lpBuffer
,
3027 IN OUT LPDWORD lpdwLen
,
3031 /* Get handle to file from 'stream' */
3032 STREAM_HANDLE
* pStream
= (STREAM_HANDLE
*)hUrlCacheStream
;
3034 if (dwReserved
!= 0)
3036 ERR("dwReserved != 0\n");
3037 SetLastError(ERROR_INVALID_PARAMETER
);
3041 if (IsBadReadPtr(pStream
, sizeof(*pStream
)) || IsBadStringPtrA(pStream
->lpszUrl
, INTERNET_MAX_URL_LENGTH
))
3043 SetLastError(ERROR_INVALID_HANDLE
);
3047 if (SetFilePointer(pStream
->hFile
, dwLocation
, NULL
, FILE_CURRENT
) == INVALID_SET_FILE_POINTER
)
3049 return ReadFile(pStream
->hFile
, lpBuffer
, *lpdwLen
, lpdwLen
, NULL
);
3052 /***********************************************************************
3053 * RetrieveUrlCacheEntryStreamA (WININET.@)
3056 HANDLE WINAPI
RetrieveUrlCacheEntryStreamA(
3057 IN LPCSTR lpszUrlName
,
3058 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
3059 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
3060 IN BOOL fRandomRead
,
3064 /* NOTE: this is not the same as the way that the native
3065 * version allocates 'stream' handles. I did it this way
3066 * as it is much easier and no applications should depend
3067 * on this behaviour. (Native version appears to allocate
3068 * indices into a table)
3070 STREAM_HANDLE
* pStream
;
3073 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
,
3074 lpdwCacheEntryInfoBufferSize
, fRandomRead
, dwReserved
);
3076 if (!RetrieveUrlCacheEntryFileA(lpszUrlName
,
3078 lpdwCacheEntryInfoBufferSize
,
3084 hFile
= CreateFileA(lpCacheEntryInfo
->lpszLocalFileName
,
3089 fRandomRead
? FILE_FLAG_RANDOM_ACCESS
: 0,
3091 if (hFile
== INVALID_HANDLE_VALUE
)
3094 /* allocate handle storage space */
3095 pStream
= heap_alloc(sizeof(STREAM_HANDLE
) + strlen(lpszUrlName
) * sizeof(CHAR
));
3099 SetLastError(ERROR_OUTOFMEMORY
);
3103 pStream
->hFile
= hFile
;
3104 strcpy(pStream
->lpszUrl
, lpszUrlName
);
3108 /***********************************************************************
3109 * RetrieveUrlCacheEntryStreamW (WININET.@)
3112 HANDLE WINAPI
RetrieveUrlCacheEntryStreamW(
3113 IN LPCWSTR lpszUrlName
,
3114 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
3115 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
3116 IN BOOL fRandomRead
,
3122 /* NOTE: this is not the same as the way that the native
3123 * version allocates 'stream' handles. I did it this way
3124 * as it is much easier and no applications should depend
3125 * on this behaviour. (Native version appears to allocate
3126 * indices into a table)
3128 STREAM_HANDLE
* pStream
;
3131 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName
), lpCacheEntryInfo
,
3132 lpdwCacheEntryInfoBufferSize
, fRandomRead
, dwReserved
);
3134 if (!RetrieveUrlCacheEntryFileW(lpszUrlName
,
3136 lpdwCacheEntryInfoBufferSize
,
3142 hFile
= CreateFileW(lpCacheEntryInfo
->lpszLocalFileName
,
3147 fRandomRead
? FILE_FLAG_RANDOM_ACCESS
: 0,
3149 if (hFile
== INVALID_HANDLE_VALUE
)
3152 /* allocate handle storage space */
3153 size
= sizeof(STREAM_HANDLE
);
3154 url_len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, NULL
, 0, NULL
, NULL
);
3156 pStream
= heap_alloc(size
);
3160 SetLastError(ERROR_OUTOFMEMORY
);
3164 pStream
->hFile
= hFile
;
3165 WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, pStream
->lpszUrl
, url_len
, NULL
, NULL
);
3169 /***********************************************************************
3170 * UnlockUrlCacheEntryStream (WININET.@)
3173 BOOL WINAPI
UnlockUrlCacheEntryStream(
3174 IN HANDLE hUrlCacheStream
,
3178 STREAM_HANDLE
* pStream
= (STREAM_HANDLE
*)hUrlCacheStream
;
3180 if (dwReserved
!= 0)
3182 ERR("dwReserved != 0\n");
3183 SetLastError(ERROR_INVALID_PARAMETER
);
3187 if (IsBadReadPtr(pStream
, sizeof(*pStream
)) || IsBadStringPtrA(pStream
->lpszUrl
, INTERNET_MAX_URL_LENGTH
))
3189 SetLastError(ERROR_INVALID_HANDLE
);
3193 if (!UnlockUrlCacheEntryFileA(pStream
->lpszUrl
, 0))
3196 CloseHandle(pStream
->hFile
);
3202 /***********************************************************************
3203 * DeleteUrlCacheEntryA (WININET.@)
3206 BOOL WINAPI
DeleteUrlCacheEntryA(LPCSTR lpszUrlName
)
3208 URLCACHECONTAINER
* pContainer
;
3209 LPURLCACHE_HEADER pHeader
;
3210 struct _HASH_ENTRY
* pHashEntry
;
3214 TRACE("(%s)\n", debugstr_a(lpszUrlName
));
3216 error
= URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
);
3217 if (error
!= ERROR_SUCCESS
)
3219 SetLastError(error
);
3223 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
3224 if (error
!= ERROR_SUCCESS
)
3226 SetLastError(error
);
3230 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3233 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
3235 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3236 TRACE("entry %s not found!\n", lpszUrlName
);
3237 SetLastError(ERROR_FILE_NOT_FOUND
);
3241 ret
= DeleteUrlCacheEntryInternal(pHeader
, pHashEntry
);
3243 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3248 /***********************************************************************
3249 * DeleteUrlCacheEntryW (WININET.@)
3252 BOOL WINAPI
DeleteUrlCacheEntryW(LPCWSTR lpszUrlName
)
3254 URLCACHECONTAINER
* pContainer
;
3255 LPURLCACHE_HEADER pHeader
;
3256 struct _HASH_ENTRY
* pHashEntry
;
3261 TRACE("(%s)\n", debugstr_w(lpszUrlName
));
3263 urlA
= heap_strdupWtoA(lpszUrlName
);
3266 SetLastError(ERROR_OUTOFMEMORY
);
3270 error
= URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
);
3271 if (error
!= ERROR_SUCCESS
)
3274 SetLastError(error
);
3278 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
3279 if (error
!= ERROR_SUCCESS
)
3282 SetLastError(error
);
3286 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3292 if (!URLCache_FindHash(pHeader
, urlA
, &pHashEntry
))
3294 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3295 TRACE("entry %s not found!\n", debugstr_a(urlA
));
3297 SetLastError(ERROR_FILE_NOT_FOUND
);
3301 ret
= DeleteUrlCacheEntryInternal(pHeader
, pHashEntry
);
3303 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3308 BOOL WINAPI
DeleteUrlCacheContainerA(DWORD d1
, DWORD d2
)
3310 FIXME("(0x%08x, 0x%08x) stub\n", d1
, d2
);
3314 BOOL WINAPI
DeleteUrlCacheContainerW(DWORD d1
, DWORD d2
)
3316 FIXME("(0x%08x, 0x%08x) stub\n", d1
, d2
);
3320 /***********************************************************************
3321 * CreateCacheContainerA (WININET.@)
3323 BOOL WINAPI
CreateUrlCacheContainerA(DWORD d1
, DWORD d2
, DWORD d3
, DWORD d4
,
3324 DWORD d5
, DWORD d6
, DWORD d7
, DWORD d8
)
3326 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3327 d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
);
3331 /***********************************************************************
3332 * CreateCacheContainerW (WININET.@)
3334 BOOL WINAPI
CreateUrlCacheContainerW(DWORD d1
, DWORD d2
, DWORD d3
, DWORD d4
,
3335 DWORD d5
, DWORD d6
, DWORD d7
, DWORD d8
)
3337 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3338 d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
);
3342 /***********************************************************************
3343 * FindFirstUrlCacheContainerA (WININET.@)
3345 HANDLE WINAPI
FindFirstUrlCacheContainerA( LPVOID p1
, LPVOID p2
, LPVOID p3
, DWORD d1
)
3347 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1
, p2
, p3
, d1
);
3351 /***********************************************************************
3352 * FindFirstUrlCacheContainerW (WININET.@)
3354 HANDLE WINAPI
FindFirstUrlCacheContainerW( LPVOID p1
, LPVOID p2
, LPVOID p3
, DWORD d1
)
3356 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1
, p2
, p3
, d1
);
3360 /***********************************************************************
3361 * FindNextUrlCacheContainerA (WININET.@)
3363 BOOL WINAPI
FindNextUrlCacheContainerA( HANDLE handle
, LPVOID p1
, LPVOID p2
)
3365 FIXME("(%p, %p, %p) stub\n", handle
, p1
, p2
);
3369 /***********************************************************************
3370 * FindNextUrlCacheContainerW (WININET.@)
3372 BOOL WINAPI
FindNextUrlCacheContainerW( HANDLE handle
, LPVOID p1
, LPVOID p2
)
3374 FIXME("(%p, %p, %p) stub\n", handle
, p1
, p2
);
3378 HANDLE WINAPI
FindFirstUrlCacheEntryExA(
3379 LPCSTR lpszUrlSearchPattern
,
3383 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
,
3384 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3386 LPDWORD pcbReserved2
,
3390 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern
),
3391 dwFlags
, dwFilter
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, lpFirstCacheEntryInfo
,
3392 lpdwFirstCacheEntryInfoBufferSize
, lpReserved
, pcbReserved2
,lpReserved3
);
3393 SetLastError(ERROR_FILE_NOT_FOUND
);
3397 HANDLE WINAPI
FindFirstUrlCacheEntryExW(
3398 LPCWSTR lpszUrlSearchPattern
,
3402 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
,
3403 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3405 LPDWORD pcbReserved2
,
3409 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern
),
3410 dwFlags
, dwFilter
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, lpFirstCacheEntryInfo
,
3411 lpdwFirstCacheEntryInfoBufferSize
, lpReserved
, pcbReserved2
,lpReserved3
);
3412 SetLastError(ERROR_FILE_NOT_FOUND
);
3416 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
3418 typedef struct URLCacheFindEntryHandle
3421 LPWSTR lpszUrlSearchPattern
;
3422 DWORD dwContainerIndex
;
3423 DWORD dwHashTableIndex
;
3424 DWORD dwHashEntryIndex
;
3425 } URLCacheFindEntryHandle
;
3427 /***********************************************************************
3428 * FindFirstUrlCacheEntryA (WININET.@)
3431 INTERNETAPI HANDLE WINAPI
FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern
,
3432 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
, LPDWORD lpdwFirstCacheEntryInfoBufferSize
)
3434 URLCacheFindEntryHandle
*pEntryHandle
;
3436 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern
), lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
);
3438 pEntryHandle
= heap_alloc(sizeof(*pEntryHandle
));
3442 pEntryHandle
->dwMagic
= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
;
3443 if (lpszUrlSearchPattern
)
3445 pEntryHandle
->lpszUrlSearchPattern
= heap_strdupAtoW(lpszUrlSearchPattern
);
3446 if (!pEntryHandle
->lpszUrlSearchPattern
)
3448 heap_free(pEntryHandle
);
3453 pEntryHandle
->lpszUrlSearchPattern
= NULL
;
3454 pEntryHandle
->dwContainerIndex
= 0;
3455 pEntryHandle
->dwHashTableIndex
= 0;
3456 pEntryHandle
->dwHashEntryIndex
= 0;
3458 if (!FindNextUrlCacheEntryA(pEntryHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
))
3460 heap_free(pEntryHandle
);
3463 return pEntryHandle
;
3466 /***********************************************************************
3467 * FindFirstUrlCacheEntryW (WININET.@)
3470 INTERNETAPI HANDLE WINAPI
FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern
,
3471 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
, LPDWORD lpdwFirstCacheEntryInfoBufferSize
)
3473 URLCacheFindEntryHandle
*pEntryHandle
;
3475 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern
), lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
);
3477 pEntryHandle
= heap_alloc(sizeof(*pEntryHandle
));
3481 pEntryHandle
->dwMagic
= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
;
3482 if (lpszUrlSearchPattern
)
3484 pEntryHandle
->lpszUrlSearchPattern
= heap_strdupW(lpszUrlSearchPattern
);
3485 if (!pEntryHandle
->lpszUrlSearchPattern
)
3487 heap_free(pEntryHandle
);
3492 pEntryHandle
->lpszUrlSearchPattern
= NULL
;
3493 pEntryHandle
->dwContainerIndex
= 0;
3494 pEntryHandle
->dwHashTableIndex
= 0;
3495 pEntryHandle
->dwHashEntryIndex
= 0;
3497 if (!FindNextUrlCacheEntryW(pEntryHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
))
3499 heap_free(pEntryHandle
);
3502 return pEntryHandle
;
3505 static BOOL
FindNextUrlCacheEntryInternal(
3507 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo
,
3508 LPDWORD lpdwNextCacheEntryInfoBufferSize
,
3511 URLCacheFindEntryHandle
*pEntryHandle
= (URLCacheFindEntryHandle
*)hEnumHandle
;
3512 URLCACHECONTAINER
* pContainer
;
3514 if (pEntryHandle
->dwMagic
!= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
)
3516 SetLastError(ERROR_INVALID_HANDLE
);
3520 for (; URLCacheContainers_Enum(pEntryHandle
->lpszUrlSearchPattern
, pEntryHandle
->dwContainerIndex
, &pContainer
);
3521 pEntryHandle
->dwContainerIndex
++, pEntryHandle
->dwHashTableIndex
= 0)
3523 LPURLCACHE_HEADER pHeader
;
3524 HASH_CACHEFILE_ENTRY
*pHashTableEntry
;
3527 error
= URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
);
3528 if (error
!= ERROR_SUCCESS
)
3530 SetLastError(error
);
3534 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3537 for (; URLCache_EnumHashTables(pHeader
, &pEntryHandle
->dwHashTableIndex
, &pHashTableEntry
);
3538 pEntryHandle
->dwHashTableIndex
++, pEntryHandle
->dwHashEntryIndex
= 0)
3540 const struct _HASH_ENTRY
*pHashEntry
= NULL
;
3541 for (; URLCache_EnumHashTableEntries(pHeader
, pHashTableEntry
, &pEntryHandle
->dwHashEntryIndex
, &pHashEntry
);
3542 pEntryHandle
->dwHashEntryIndex
++)
3544 const URL_CACHEFILE_ENTRY
*pUrlEntry
;
3545 const CACHEFILE_ENTRY
*pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3547 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
3550 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
3551 TRACE("Found URL: %s\n",
3552 debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
));
3553 TRACE("Header info: %s\n",
3554 debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
3556 error
= URLCache_CopyEntry(
3559 lpNextCacheEntryInfo
,
3560 lpdwNextCacheEntryInfoBufferSize
,
3563 if (error
!= ERROR_SUCCESS
)
3565 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3566 SetLastError(error
);
3569 TRACE("Local File Name: %s\n",
3570 debugstr_a((LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
));
3572 /* increment the current index so that next time the function
3573 * is called the next entry is returned */
3574 pEntryHandle
->dwHashEntryIndex
++;
3575 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3580 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3583 SetLastError(ERROR_NO_MORE_ITEMS
);
3587 /***********************************************************************
3588 * FindNextUrlCacheEntryA (WININET.@)
3590 BOOL WINAPI
FindNextUrlCacheEntryA(
3592 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo
,
3593 LPDWORD lpdwNextCacheEntryInfoBufferSize
)
3595 TRACE("(%p, %p, %p)\n", hEnumHandle
, lpNextCacheEntryInfo
, lpdwNextCacheEntryInfoBufferSize
);
3597 return FindNextUrlCacheEntryInternal(hEnumHandle
, lpNextCacheEntryInfo
,
3598 lpdwNextCacheEntryInfoBufferSize
, FALSE
/* not UNICODE */);
3601 /***********************************************************************
3602 * FindNextUrlCacheEntryW (WININET.@)
3604 BOOL WINAPI
FindNextUrlCacheEntryW(
3606 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo
,
3607 LPDWORD lpdwNextCacheEntryInfoBufferSize
3610 TRACE("(%p, %p, %p)\n", hEnumHandle
, lpNextCacheEntryInfo
, lpdwNextCacheEntryInfoBufferSize
);
3612 return FindNextUrlCacheEntryInternal(hEnumHandle
,
3613 (LPINTERNET_CACHE_ENTRY_INFOA
)lpNextCacheEntryInfo
,
3614 lpdwNextCacheEntryInfoBufferSize
, TRUE
/* UNICODE */);
3617 /***********************************************************************
3618 * FindCloseUrlCache (WININET.@)
3620 BOOL WINAPI
FindCloseUrlCache(HANDLE hEnumHandle
)
3622 URLCacheFindEntryHandle
*pEntryHandle
= (URLCacheFindEntryHandle
*)hEnumHandle
;
3624 TRACE("(%p)\n", hEnumHandle
);
3626 if (!pEntryHandle
|| pEntryHandle
->dwMagic
!= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
)
3628 SetLastError(ERROR_INVALID_HANDLE
);
3632 pEntryHandle
->dwMagic
= 0;
3633 heap_free(pEntryHandle
->lpszUrlSearchPattern
);
3634 heap_free(pEntryHandle
);
3638 HANDLE WINAPI
FindFirstUrlCacheGroup( DWORD dwFlags
, DWORD dwFilter
, LPVOID lpSearchCondition
,
3639 DWORD dwSearchCondition
, GROUPID
* lpGroupId
, LPVOID lpReserved
)
3641 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags
, dwFilter
, lpSearchCondition
,
3642 dwSearchCondition
, lpGroupId
, lpReserved
);
3646 BOOL WINAPI
FindNextUrlCacheEntryExA(
3648 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
,
3649 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3651 LPDWORD pcbReserved2
,
3655 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
,
3656 lpReserved
, pcbReserved2
, lpReserved3
);
3660 BOOL WINAPI
FindNextUrlCacheEntryExW(
3662 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
,
3663 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3665 LPDWORD pcbReserved2
,
3669 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
,
3670 lpReserved
, pcbReserved2
, lpReserved3
);
3674 BOOL WINAPI
FindNextUrlCacheGroup( HANDLE hFind
, GROUPID
* lpGroupId
, LPVOID lpReserved
)
3676 FIXME("(%p, %p, %p) stub\n", hFind
, lpGroupId
, lpReserved
);
3680 /***********************************************************************
3681 * CreateUrlCacheGroup (WININET.@)
3684 INTERNETAPI GROUPID WINAPI
CreateUrlCacheGroup(DWORD dwFlags
, LPVOID lpReserved
)
3686 FIXME("(0x%08x, %p): stub\n", dwFlags
, lpReserved
);
3690 /***********************************************************************
3691 * DeleteUrlCacheGroup (WININET.@)
3694 BOOL WINAPI
DeleteUrlCacheGroup(GROUPID GroupId
, DWORD dwFlags
, LPVOID lpReserved
)
3696 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3697 (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, dwFlags
, lpReserved
);
3701 /***********************************************************************
3702 * SetUrlCacheEntryGroupA (WININET.@)
3705 BOOL WINAPI
SetUrlCacheEntryGroupA(LPCSTR lpszUrlName
, DWORD dwFlags
,
3706 GROUPID GroupId
, LPBYTE pbGroupAttributes
, DWORD cbGroupAttributes
,
3709 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3710 debugstr_a(lpszUrlName
), dwFlags
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
,
3711 pbGroupAttributes
, cbGroupAttributes
, lpReserved
);
3712 SetLastError(ERROR_FILE_NOT_FOUND
);
3716 /***********************************************************************
3717 * SetUrlCacheEntryGroupW (WININET.@)
3720 BOOL WINAPI
SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName
, DWORD dwFlags
,
3721 GROUPID GroupId
, LPBYTE pbGroupAttributes
, DWORD cbGroupAttributes
,
3724 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3725 debugstr_w(lpszUrlName
), dwFlags
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
,
3726 pbGroupAttributes
, cbGroupAttributes
, lpReserved
);
3727 SetLastError(ERROR_FILE_NOT_FOUND
);
3731 /***********************************************************************
3732 * GetUrlCacheConfigInfoW (WININET.@)
3734 BOOL WINAPI
GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo
, LPDWORD size
, DWORD bitmask
)
3736 FIXME("(%p, %p, %x)\n", CacheInfo
, size
, bitmask
);
3737 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
3741 /***********************************************************************
3742 * GetUrlCacheConfigInfoA (WININET.@)
3744 BOOL WINAPI
GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo
, LPDWORD size
, DWORD bitmask
)
3746 FIXME("(%p, %p, %x)\n", CacheInfo
, size
, bitmask
);
3747 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
3751 BOOL WINAPI
GetUrlCacheGroupAttributeA( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3752 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo
,
3753 LPDWORD lpdwGroupInfo
, LPVOID lpReserved
)
3755 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3756 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
,
3757 lpdwGroupInfo
, lpReserved
);
3761 BOOL WINAPI
GetUrlCacheGroupAttributeW( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3762 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo
,
3763 LPDWORD lpdwGroupInfo
, LPVOID lpReserved
)
3765 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3766 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
,
3767 lpdwGroupInfo
, lpReserved
);
3771 BOOL WINAPI
SetUrlCacheGroupAttributeA( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3772 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo
, LPVOID lpReserved
)
3774 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3775 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
, lpReserved
);
3779 BOOL WINAPI
SetUrlCacheGroupAttributeW( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3780 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo
, LPVOID lpReserved
)
3782 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3783 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
, lpReserved
);
3787 BOOL WINAPI
SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo
, DWORD dwFieldControl
)
3789 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo
, dwFieldControl
);
3793 BOOL WINAPI
SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo
, DWORD dwFieldControl
)
3795 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo
, dwFieldControl
);
3799 /***********************************************************************
3800 * DeleteIE3Cache (WININET.@)
3802 * Deletes the files used by the IE3 URL caching system.
3805 * hWnd [I] A dummy window.
3806 * hInst [I] Instance of process calling the function.
3807 * lpszCmdLine [I] Options used by function.
3808 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3810 DWORD WINAPI
DeleteIE3Cache(HWND hWnd
, HINSTANCE hInst
, LPSTR lpszCmdLine
, int nCmdShow
)
3812 FIXME("(%p, %p, %s, %d)\n", hWnd
, hInst
, debugstr_a(lpszCmdLine
), nCmdShow
);
3816 static BOOL
IsUrlCacheEntryExpiredInternal(const URL_CACHEFILE_ENTRY
*pUrlEntry
,
3817 FILETIME
*pftLastModified
)
3820 FILETIME now
, expired
;
3822 *pftLastModified
= pUrlEntry
->LastModifiedTime
;
3823 GetSystemTimeAsFileTime(&now
);
3824 URLCache_DosDateTimeToFileTime(pUrlEntry
->wExpiredDate
,
3825 pUrlEntry
->wExpiredTime
, &expired
);
3826 /* If the expired time is 0, it's interpreted as not expired */
3827 if (!expired
.dwLowDateTime
&& !expired
.dwHighDateTime
)
3830 ret
= CompareFileTime(&expired
, &now
) < 0;
3834 /***********************************************************************
3835 * IsUrlCacheEntryExpiredA (WININET.@)
3839 * dwFlags [I] Unknown
3840 * pftLastModified [O] Last modified time
3842 BOOL WINAPI
IsUrlCacheEntryExpiredA( LPCSTR url
, DWORD dwFlags
, FILETIME
* pftLastModified
)
3844 LPURLCACHE_HEADER pHeader
;
3845 struct _HASH_ENTRY
* pHashEntry
;
3846 const CACHEFILE_ENTRY
* pEntry
;
3847 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
3848 URLCACHECONTAINER
* pContainer
;
3851 TRACE("(%s, %08x, %p)\n", debugstr_a(url
), dwFlags
, pftLastModified
);
3853 if (!url
|| !pftLastModified
)
3856 FIXME("unknown flags 0x%08x\n", dwFlags
);
3858 /* Any error implies that the URL is expired, i.e. not in the cache */
3859 if (URLCacheContainers_FindContainerA(url
, &pContainer
))
3861 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3865 if (URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
))
3867 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3871 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3873 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3877 if (!URLCache_FindHash(pHeader
, url
, &pHashEntry
))
3879 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3880 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3881 TRACE("entry %s not found!\n", url
);
3885 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3886 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
3888 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3889 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3890 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
3894 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
3895 expired
= IsUrlCacheEntryExpiredInternal(pUrlEntry
, pftLastModified
);
3897 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3902 /***********************************************************************
3903 * IsUrlCacheEntryExpiredW (WININET.@)
3907 * dwFlags [I] Unknown
3908 * pftLastModified [O] Last modified time
3910 BOOL WINAPI
IsUrlCacheEntryExpiredW( LPCWSTR url
, DWORD dwFlags
, FILETIME
* pftLastModified
)
3912 LPURLCACHE_HEADER pHeader
;
3913 struct _HASH_ENTRY
* pHashEntry
;
3914 const CACHEFILE_ENTRY
* pEntry
;
3915 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
3916 URLCACHECONTAINER
* pContainer
;
3919 TRACE("(%s, %08x, %p)\n", debugstr_w(url
), dwFlags
, pftLastModified
);
3921 if (!url
|| !pftLastModified
)
3924 FIXME("unknown flags 0x%08x\n", dwFlags
);
3926 /* Any error implies that the URL is expired, i.e. not in the cache */
3927 if (URLCacheContainers_FindContainerW(url
, &pContainer
))
3929 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3933 if (URLCacheContainer_OpenIndex(pContainer
, MIN_BLOCK_NO
))
3935 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3939 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3941 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3945 if (!URLCache_FindHashW(pHeader
, url
, &pHashEntry
))
3947 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3948 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3949 TRACE("entry %s not found!\n", debugstr_w(url
));
3953 if (!URLCache_FindHashW(pHeader
, url
, &pHashEntry
))
3955 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3956 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3957 TRACE("entry %s not found!\n", debugstr_w(url
));
3961 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3962 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
3964 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3965 memset(pftLastModified
, 0, sizeof(*pftLastModified
));
3966 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
3970 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
3971 expired
= IsUrlCacheEntryExpiredInternal(pUrlEntry
, pftLastModified
);
3973 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3978 /***********************************************************************
3979 * GetDiskInfoA (WININET.@)
3981 BOOL WINAPI
GetDiskInfoA(PCSTR path
, PDWORD cluster_size
, PDWORDLONG free
, PDWORDLONG total
)
3984 ULARGE_INTEGER bytes_free
, bytes_total
;
3986 TRACE("(%s, %p, %p, %p)\n", debugstr_a(path
), cluster_size
, free
, total
);
3990 SetLastError(ERROR_INVALID_PARAMETER
);
3994 if ((ret
= GetDiskFreeSpaceExA(path
, NULL
, &bytes_total
, &bytes_free
)))
3996 if (cluster_size
) *cluster_size
= 1;
3997 if (free
) *free
= bytes_free
.QuadPart
;
3998 if (total
) *total
= bytes_total
.QuadPart
;
4003 /***********************************************************************
4004 * RegisterUrlCacheNotification (WININET.@)
4006 DWORD WINAPI
RegisterUrlCacheNotification(LPVOID a
, DWORD b
, DWORD c
, DWORD d
, DWORD e
, DWORD f
)
4008 FIXME("(%p %x %x %x %x %x)\n", a
, b
, c
, d
, e
, f
);
4012 /***********************************************************************
4013 * IncrementUrlCacheHeaderData (WININET.@)
4015 BOOL WINAPI
IncrementUrlCacheHeaderData(DWORD index
, LPDWORD data
)
4017 FIXME("(%u, %p)\n", index
, data
);
4021 /***********************************************************************
4022 * RunOnceUrlCache (WININET.@)
4025 DWORD WINAPI
RunOnceUrlCache(HWND hwnd
, HINSTANCE hinst
, LPSTR cmd
, int cmdshow
)
4027 FIXME("(%p, %p, %s, %d): stub\n", hwnd
, hinst
, debugstr_a(cmd
), cmdshow
);