2 * Wininet - Url Cache functions
4 * Copyright 2001,2002 CodeWeavers
5 * Copyright 2003 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"
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
48 #include "wine/unicode.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
53 #define ENTRY_START_OFFSET 0x4000
56 #define HASHTABLE_SIZE 448
57 #define HASHTABLE_BLOCKSIZE 7
58 #define HASHTABLE_FREE 3
59 #define ALLOCATION_TABLE_OFFSET 0x250
60 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
61 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
62 #define NEWFILE_NUM_BLOCKS 0xd80
63 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)
65 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
66 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
67 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
68 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
69 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
71 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
73 typedef struct _CACHEFILE_ENTRY
77 DWORD dwSignature
; /* e.g. "URL " */
78 /* CHAR szSignature[4];
80 DWORD dwBlocksUsed
; /* number of 128byte blocks used by this entry */
83 typedef struct _URL_CACHEFILE_ENTRY
85 CACHEFILE_ENTRY CacheFileEntry
;
86 FILETIME LastModifiedTime
;
87 FILETIME LastAccessTime
;
88 WORD wExpiredDate
; /* expire date in dos format */
89 WORD wExpiredTime
; /* expire time in dos format */
90 DWORD dwUnknown1
; /* usually zero */
91 DWORD dwSizeLow
; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
92 DWORD dwSizeHigh
; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
93 DWORD dwUnknown2
; /* usually zero */
94 DWORD dwExemptDelta
; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
95 DWORD dwUnknown3
; /* usually 0x60 */
96 DWORD dwOffsetUrl
; /* offset of start of url from start of entry */
97 BYTE CacheDir
; /* index of cache directory this url is stored in */
98 BYTE Unknown4
; /* usually zero */
99 WORD wUnknown5
; /* usually 0x1010 */
100 DWORD dwOffsetLocalName
; /* offset of start of local filename from start of entry */
101 DWORD CacheEntryType
; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
102 DWORD dwOffsetHeaderInfo
; /* offset of start of header info from start of entry */
103 DWORD dwHeaderInfoSize
;
104 DWORD dwOffsetFileExtension
; /* offset of start of file extension from start of entry */
105 WORD wLastSyncDate
; /* last sync date in dos format */
106 WORD wLastSyncTime
; /* last sync time in dos format */
107 DWORD dwHitRate
; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
108 DWORD dwUseCount
; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
109 WORD wUnknownDate
; /* usually same as wLastSyncDate */
110 WORD wUnknownTime
; /* usually same as wLastSyncTime */
111 DWORD dwUnknown7
; /* usually zero */
112 DWORD dwUnknown8
; /* usually zero */
113 /* packing to dword align start of next field */
114 /* CHAR szSourceUrlName[]; (url) */
115 /* packing to dword align start of next field */
116 /* CHAR szLocalFileName[]; (local file name excluding path) */
117 /* packing to dword align start of next field */
118 /* CHAR szHeaderInfo[]; (header info) */
119 } URL_CACHEFILE_ENTRY
;
127 typedef struct _HASH_CACHEFILE_ENTRY
129 CACHEFILE_ENTRY CacheFileEntry
;
131 DWORD dwHashTableNumber
;
132 struct _HASH_ENTRY HashTable
[HASHTABLE_SIZE
];
133 } HASH_CACHEFILE_ENTRY
;
135 typedef struct _DIRECTORY_DATA
138 char filename
[DIR_LENGTH
];
141 typedef struct _URLCACHE_HEADER
143 char szSignature
[28];
145 DWORD dwOffsetFirstHashTable
;
146 DWORD dwIndexCapacityInBlocks
;
149 DWORD dwCacheLimitLow
; /* disk space limit for cache */
150 DWORD dwCacheLimitHigh
; /* disk space limit for cache */
151 DWORD dwUnknown4
; /* current disk space usage for cache */
152 DWORD dwUnknown5
; /* current disk space usage for cache */
153 DWORD dwUnknown6
; /* possibly a flag? */
155 BYTE DirectoryCount
; /* number of directory_data's */
156 BYTE Unknown8
[3]; /* just padding? */
157 DIRECTORY_DATA directory_data
[1]; /* first directory entry */
158 } URLCACHE_HEADER
, *LPURLCACHE_HEADER
;
159 typedef const URLCACHE_HEADER
*LPCURLCACHE_HEADER
;
161 typedef struct _STREAM_HANDLE
167 typedef struct _URLCACHECONTAINER
169 struct list entry
; /* part of a list */
170 LPWSTR cache_prefix
; /* string that has to be prefixed for this container to be used */
171 LPWSTR path
; /* path to url container directory */
172 HANDLE hMapping
; /* handle of file mapping */
173 DWORD file_size
; /* size of file when mapping was opened */
174 HANDLE hMutex
; /* handle of mutex */
178 /* List of all containers available */
179 static struct list UrlContainers
= LIST_INIT(UrlContainers
);
181 static HASH_CACHEFILE_ENTRY
*URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader
, HASH_CACHEFILE_ENTRY
*pPrevHash
);
183 /***********************************************************************
184 * URLCache_PathToObjectName (Internal)
186 * Converts a path to a name suitable for use as a Win32 object name.
187 * Replaces '\\' characters in-place with the specified character
188 * (usually '_' or '!')
194 static void URLCache_PathToObjectName(LPWSTR lpszPath
, WCHAR replace
)
196 for (; *lpszPath
; lpszPath
++)
198 if (*lpszPath
== '\\')
203 /***********************************************************************
204 * URLCacheContainer_OpenIndex (Internal)
206 * Opens the index file and saves mapping handle in hCacheIndexMapping
213 static BOOL
URLCacheContainer_OpenIndex(URLCACHECONTAINER
* pContainer
)
216 WCHAR wszFilePath
[MAX_PATH
];
219 static const WCHAR wszIndex
[] = {'i','n','d','e','x','.','d','a','t',0};
220 static const WCHAR wszMappingFormat
[] = {'%','s','%','s','_','%','l','u',0};
222 if (pContainer
->hMapping
)
225 strcpyW(wszFilePath
, pContainer
->path
);
226 strcatW(wszFilePath
, wszIndex
);
228 hFile
= CreateFileW(wszFilePath
, GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, 0, NULL
);
229 if (hFile
== INVALID_HANDLE_VALUE
)
231 /* Maybe the directory wasn't there? Try to create it */
232 if (CreateDirectoryW(pContainer
->path
, 0))
233 hFile
= CreateFileW(wszFilePath
, GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_ALWAYS
, 0, NULL
);
235 if (hFile
== INVALID_HANDLE_VALUE
)
237 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath
));
241 /* At this stage we need the mutex because we may be about to create the
244 WaitForSingleObject(pContainer
->hMutex
, INFINITE
);
246 dwFileSize
= GetFileSize(hFile
, NULL
);
247 if (dwFileSize
== INVALID_FILE_SIZE
)
249 ReleaseMutex(pContainer
->hMutex
);
255 static const CHAR szCacheContent
[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content";
257 char achZeroes
[0x1000];
261 /* Write zeroes to the entire file so we can safely map it without
262 * fear of getting a SEGV because the disk is full.
264 memset(achZeroes
, 0, sizeof(achZeroes
));
265 for (dwOffset
= 0; dwOffset
< NEWFILE_SIZE
; dwOffset
+= sizeof(achZeroes
))
267 DWORD dwWrite
= sizeof(achZeroes
);
270 if (NEWFILE_SIZE
- dwOffset
< dwWrite
)
271 dwWrite
= NEWFILE_SIZE
- dwOffset
;
272 if (!WriteFile(hFile
, achZeroes
, dwWrite
, &dwWritten
, 0) ||
273 dwWritten
!= dwWrite
)
275 /* If we fail to write, we need to return the error that
276 * cause the problem and also make sure the file is no
277 * longer there, if possible.
279 dwError
= GetLastError();
287 HANDLE hMapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READWRITE
, 0, NEWFILE_SIZE
, NULL
);
291 URLCACHE_HEADER
*pHeader
= MapViewOfFile(hMapping
, FILE_MAP_WRITE
, 0, 0, NEWFILE_SIZE
);
296 WCHAR wszDirPath
[MAX_PATH
];
300 dwFileSize
= NEWFILE_SIZE
;
302 /* First set some constants and defaults in the header */
303 strcpy(pHeader
->szSignature
, "WINE URLCache Ver 0.2005001");
304 pHeader
->dwFileSize
= dwFileSize
;
305 pHeader
->dwIndexCapacityInBlocks
= NEWFILE_NUM_BLOCKS
;
306 /* 127MB - taken from default for Windows 2000 */
307 pHeader
->dwCacheLimitHigh
= 0;
308 pHeader
->dwCacheLimitLow
= 0x07ff5400;
309 /* Copied from a Windows 2000 cache index */
310 pHeader
->DirectoryCount
= 4;
312 /* If the registry has a cache size set, use the registry value */
313 if (RegOpenKeyA(HKEY_CURRENT_USER
, szCacheContent
, &key
) == ERROR_SUCCESS
)
316 DWORD len
= sizeof(dw
);
319 if (RegQueryValueExA(key
, "CacheLimit", NULL
, &keytype
,
320 (BYTE
*) &dw
, &len
) == ERROR_SUCCESS
&&
321 keytype
== REG_DWORD
)
323 pHeader
->dwCacheLimitHigh
= (dw
>> 22);
324 pHeader
->dwCacheLimitLow
= dw
<< 10;
329 URLCache_CreateHashTable(pHeader
, NULL
);
331 /* Last step - create the directories */
333 strcpyW(wszDirPath
, pContainer
->path
);
334 pwchDir
= wszDirPath
+ strlenW(wszDirPath
);
337 GetSystemTimeAsFileTime(&ft
);
339 for (i
= 0; !dwError
&& i
< pHeader
->DirectoryCount
; ++i
)
341 /* The following values were copied from a Windows index.
342 * I don't know what the values are supposed to mean but
343 * have made them the same in the hope that this will
344 * be better for compatibility
346 pHeader
->directory_data
[i
].dwUnknown
= (i
> 1) ? 0xfe : 0xff;
350 ULONGLONG n
= ft
.dwHighDateTime
;
352 /* Generate a file name to attempt to create.
353 * This algorithm will create what will appear
354 * to be random and unrelated directory names
355 * of up to 9 characters in length.
358 n
+= ft
.dwLowDateTime
;
359 n
^= ((ULONGLONG
) i
<< 56) | ((ULONGLONG
) j
<< 48);
361 for (k
= 0; k
< 8; ++k
)
365 /* Dividing by a prime greater than 36 helps
366 * with the appearance of randomness
371 pwchDir
[k
] = '0' + r
;
373 pwchDir
[k
] = 'A' + (r
- 10);
376 if (CreateDirectoryW(wszDirPath
, 0))
378 /* The following is OK because we generated an
379 * 8 character directory name made from characters
380 * [A-Z0-9], which are equivalent for all code
381 * pages and for UTF-16
383 for (k
= 0; k
< 8; ++k
)
384 pHeader
->directory_data
[i
].filename
[k
] = pwchDir
[k
];
389 /* Give up. The most likely cause of this
390 * is a full disk, but whatever the cause
391 * is, it should be more than apparent that
394 dwError
= GetLastError();
400 UnmapViewOfFile(pHeader
);
404 dwError
= GetLastError();
406 CloseHandle(hMapping
);
410 dwError
= GetLastError();
417 DeleteFileW(wszFilePath
);
418 ReleaseMutex(pContainer
->hMutex
);
419 SetLastError(dwError
);
425 ReleaseMutex(pContainer
->hMutex
);
427 wsprintfW(wszFilePath
, wszMappingFormat
, pContainer
->path
, wszIndex
, dwFileSize
);
428 URLCache_PathToObjectName(wszFilePath
, '_');
429 pContainer
->hMapping
= OpenFileMappingW(FILE_MAP_WRITE
, FALSE
, wszFilePath
);
430 if (!pContainer
->hMapping
)
431 pContainer
->hMapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READWRITE
, 0, 0, wszFilePath
);
433 if (!pContainer
->hMapping
)
435 ERR("Couldn't create file mapping (error is %d)\n", GetLastError());
442 /***********************************************************************
443 * URLCacheContainer_CloseIndex (Internal)
451 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER
* pContainer
)
453 CloseHandle(pContainer
->hMapping
);
454 pContainer
->hMapping
= NULL
;
457 static BOOL
URLCacheContainers_AddContainer(LPCWSTR cache_prefix
, LPCWSTR path
, LPWSTR mutex_name
)
459 URLCACHECONTAINER
* pContainer
= HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER
));
460 int path_len
= strlenW(path
);
461 int cache_prefix_len
= strlenW(cache_prefix
);
468 pContainer
->hMapping
= NULL
;
469 pContainer
->file_size
= 0;
471 pContainer
->path
= HeapAlloc(GetProcessHeap(), 0, (path_len
+ 1) * sizeof(WCHAR
));
472 if (!pContainer
->path
)
474 HeapFree(GetProcessHeap(), 0, pContainer
);
478 memcpy(pContainer
->path
, path
, (path_len
+ 1) * sizeof(WCHAR
));
480 pContainer
->cache_prefix
= HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len
+ 1) * sizeof(WCHAR
));
481 if (!pContainer
->cache_prefix
)
483 HeapFree(GetProcessHeap(), 0, pContainer
->path
);
484 HeapFree(GetProcessHeap(), 0, pContainer
);
488 memcpy(pContainer
->cache_prefix
, cache_prefix
, (cache_prefix_len
+ 1) * sizeof(WCHAR
));
490 CharLowerW(mutex_name
);
491 URLCache_PathToObjectName(mutex_name
, '!');
493 if ((pContainer
->hMutex
= CreateMutexW(NULL
, FALSE
, mutex_name
)) == NULL
)
495 ERR("couldn't create mutex (error is %d)\n", GetLastError());
496 HeapFree(GetProcessHeap(), 0, pContainer
->path
);
497 HeapFree(GetProcessHeap(), 0, pContainer
);
501 list_add_head(&UrlContainers
, &pContainer
->entry
);
506 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER
* pContainer
)
508 list_remove(&pContainer
->entry
);
510 URLCacheContainer_CloseIndex(pContainer
);
511 CloseHandle(pContainer
->hMutex
);
512 HeapFree(GetProcessHeap(), 0, pContainer
->path
);
513 HeapFree(GetProcessHeap(), 0, pContainer
->cache_prefix
);
514 HeapFree(GetProcessHeap(), 0, pContainer
);
517 void URLCacheContainers_CreateDefaults(void)
519 static const WCHAR UrlSuffix
[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
520 static const WCHAR UrlPrefix
[] = {0};
521 static const WCHAR HistorySuffix
[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
522 static const WCHAR HistoryPrefix
[] = {'V','i','s','i','t','e','d',':',0};
523 static const WCHAR CookieSuffix
[] = {0};
524 static const WCHAR CookiePrefix
[] = {'C','o','o','k','i','e',':',0};
527 int nFolder
; /* CSIDL_* constant */
528 const WCHAR
* shpath_suffix
; /* suffix on path returned by SHGetSpecialFolderPath */
529 const WCHAR
* cache_prefix
; /* prefix used to reference the container */
530 } DefaultContainerData
[] =
532 { CSIDL_INTERNET_CACHE
, UrlSuffix
, UrlPrefix
},
533 { CSIDL_HISTORY
, HistorySuffix
, HistoryPrefix
},
534 { CSIDL_COOKIES
, CookieSuffix
, CookiePrefix
},
538 for (i
= 0; i
< sizeof(DefaultContainerData
) / sizeof(DefaultContainerData
[0]); i
++)
540 WCHAR wszCachePath
[MAX_PATH
];
541 WCHAR wszMutexName
[MAX_PATH
];
542 int path_len
, suffix_len
;
544 if (!SHGetSpecialFolderPathW(NULL
, wszCachePath
, DefaultContainerData
[i
].nFolder
, TRUE
))
546 ERR("Couldn't get path for default container %u\n", i
);
549 path_len
= strlenW(wszCachePath
);
550 suffix_len
= strlenW(DefaultContainerData
[i
].shpath_suffix
);
552 if (path_len
+ suffix_len
+ 2 > MAX_PATH
)
554 ERR("Path too long\n");
558 wszCachePath
[path_len
] = '\\';
559 wszCachePath
[path_len
+1] = 0;
561 strcpyW(wszMutexName
, wszCachePath
);
565 memcpy(wszCachePath
+ path_len
+ 1, DefaultContainerData
[i
].shpath_suffix
, (suffix_len
+ 1) * sizeof(WCHAR
));
566 wszCachePath
[path_len
+ suffix_len
+ 1] = '\\';
567 wszCachePath
[path_len
+ suffix_len
+ 2] = '\0';
570 URLCacheContainers_AddContainer(DefaultContainerData
[i
].cache_prefix
, wszCachePath
, wszMutexName
);
574 void URLCacheContainers_DeleteAll(void)
576 while(!list_empty(&UrlContainers
))
577 URLCacheContainer_DeleteContainer(
578 LIST_ENTRY(list_head(&UrlContainers
), URLCACHECONTAINER
, entry
)
582 static BOOL
URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl
, URLCACHECONTAINER
** ppContainer
)
584 URLCACHECONTAINER
* pContainer
;
586 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl
));
588 LIST_FOR_EACH_ENTRY(pContainer
, &UrlContainers
, URLCACHECONTAINER
, entry
)
590 int prefix_len
= strlenW(pContainer
->cache_prefix
);
591 if (!strncmpW(pContainer
->cache_prefix
, lpwszUrl
, prefix_len
))
593 TRACE("found container with prefx %s for URL %s\n", debugstr_w(pContainer
->cache_prefix
), debugstr_w(lpwszUrl
));
594 *ppContainer
= pContainer
;
598 ERR("no container found\n");
599 SetLastError(ERROR_FILE_NOT_FOUND
);
603 static BOOL
URLCacheContainers_FindContainerA(LPCSTR lpszUrl
, URLCACHECONTAINER
** ppContainer
)
607 int url_len
= MultiByteToWideChar(CP_ACP
, 0, lpszUrl
, -1, NULL
, 0);
608 if (url_len
&& (lpwszUrl
= HeapAlloc(GetProcessHeap(), 0, url_len
* sizeof(WCHAR
))))
610 MultiByteToWideChar(CP_ACP
, 0, lpszUrl
, -1, lpwszUrl
, url_len
);
611 ret
= URLCacheContainers_FindContainerW(lpwszUrl
, ppContainer
);
612 HeapFree(GetProcessHeap(), 0, lpwszUrl
);
618 static BOOL
URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern
, DWORD dwIndex
, URLCACHECONTAINER
** ppContainer
)
621 URLCACHECONTAINER
* pContainer
;
623 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern
));
625 /* non-NULL search pattern only returns one container ever */
626 if (lpwszSearchPattern
&& dwIndex
> 0)
629 LIST_FOR_EACH_ENTRY(pContainer
, &UrlContainers
, URLCACHECONTAINER
, entry
)
631 if (lpwszSearchPattern
)
633 if (!strcmpW(pContainer
->cache_prefix
, lpwszSearchPattern
))
635 TRACE("found container with prefix %s\n", debugstr_w(pContainer
->cache_prefix
));
636 *ppContainer
= pContainer
;
644 TRACE("found container with prefix %s\n", debugstr_w(pContainer
->cache_prefix
));
645 *ppContainer
= pContainer
;
654 /***********************************************************************
655 * URLCacheContainer_LockIndex (Internal)
658 static LPURLCACHE_HEADER
URLCacheContainer_LockIndex(URLCACHECONTAINER
* pContainer
)
662 URLCACHE_HEADER
* pHeader
;
665 WaitForSingleObject(pContainer
->hMutex
, INFINITE
);
667 pIndexData
= MapViewOfFile(pContainer
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
671 ReleaseMutex(pContainer
->hMutex
);
672 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError());
675 pHeader
= (URLCACHE_HEADER
*)pIndexData
;
677 /* file has grown - we need to remap to prevent us getting
678 * access violations when we try and access beyond the end
679 * of the memory mapped file */
680 if (pHeader
->dwFileSize
!= pContainer
->file_size
)
682 URLCacheContainer_CloseIndex(pContainer
);
683 if (!URLCacheContainer_OpenIndex(pContainer
))
685 ReleaseMutex(pContainer
->hMutex
);
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
;
699 TRACE("Signature: %s, file size: %d bytes\n", pHeader
->szSignature
, pHeader
->dwFileSize
);
701 for (index
= 0; index
< pHeader
->DirectoryCount
; index
++)
703 TRACE("Directory[%d] = \"%.8s\"\n", index
, pHeader
->directory_data
[index
].filename
);
709 /***********************************************************************
710 * URLCacheContainer_UnlockIndex (Internal)
713 static BOOL
URLCacheContainer_UnlockIndex(URLCACHECONTAINER
* pContainer
, LPURLCACHE_HEADER pHeader
)
716 ReleaseMutex(pContainer
->hMutex
);
717 return UnmapViewOfFile(pHeader
);
722 #define CHAR_BIT (8 * sizeof(CHAR))
725 /***********************************************************************
726 * URLCache_Allocation_BlockIsFree (Internal)
728 * Is the specified block number free?
735 static inline BYTE
URLCache_Allocation_BlockIsFree(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
737 BYTE mask
= 1 << (dwBlockNumber
% CHAR_BIT
);
738 return (AllocationTable
[dwBlockNumber
/ CHAR_BIT
] & mask
) == 0;
741 /***********************************************************************
742 * URLCache_Allocation_BlockFree (Internal)
744 * Marks the specified block as free
750 static inline void URLCache_Allocation_BlockFree(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
752 BYTE mask
= ~(1 << (dwBlockNumber
% CHAR_BIT
));
753 AllocationTable
[dwBlockNumber
/ CHAR_BIT
] &= mask
;
756 /***********************************************************************
757 * URLCache_Allocation_BlockAllocate (Internal)
759 * Marks the specified block as allocated
765 static inline void URLCache_Allocation_BlockAllocate(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
767 BYTE mask
= 1 << (dwBlockNumber
% CHAR_BIT
);
768 AllocationTable
[dwBlockNumber
/ CHAR_BIT
] |= mask
;
771 /***********************************************************************
772 * URLCache_FindFirstFreeEntry (Internal)
774 * Finds and allocates the first block of free space big enough and
775 * sets ppEntry to point to it.
778 * TRUE if it had enough space
779 * FALSE if it couldn't find enough space
782 static BOOL
URLCache_FindFirstFreeEntry(URLCACHE_HEADER
* pHeader
, DWORD dwBlocksNeeded
, CACHEFILE_ENTRY
** ppEntry
)
784 LPBYTE AllocationTable
= (LPBYTE
)pHeader
+ ALLOCATION_TABLE_OFFSET
;
787 for (dwBlockNumber
= 0; dwBlockNumber
< pHeader
->dwIndexCapacityInBlocks
; dwBlockNumber
++)
789 for (dwFreeCounter
= 0;
790 dwFreeCounter
< dwBlocksNeeded
&&
791 dwFreeCounter
+ dwBlockNumber
< pHeader
->dwIndexCapacityInBlocks
&&
792 URLCache_Allocation_BlockIsFree(AllocationTable
, dwBlockNumber
+ dwFreeCounter
);
794 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber
, ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
796 if (dwFreeCounter
== dwBlocksNeeded
)
799 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber
, ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
800 for (index
= 0; index
< dwBlocksNeeded
; index
++)
801 URLCache_Allocation_BlockAllocate(AllocationTable
, dwBlockNumber
+ index
);
802 *ppEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
803 (*ppEntry
)->dwBlocksUsed
= dwBlocksNeeded
;
807 FIXME("Grow file\n");
811 /***********************************************************************
812 * URLCache_DeleteEntry (Internal)
814 * Deletes the specified entry and frees the space allocated to it
817 * TRUE if it succeeded
821 static BOOL
URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader
, CACHEFILE_ENTRY
* pEntry
)
825 BYTE
* AllocationTable
= (LPBYTE
)pHeader
+ ALLOCATION_TABLE_OFFSET
;
827 /* update allocation table */
828 dwStartBlock
= ((DWORD
)((BYTE
*)pEntry
- (BYTE
*)pHeader
)) / BLOCKSIZE
;
829 for (dwBlock
= dwStartBlock
; dwBlock
< dwStartBlock
+ pEntry
->dwBlocksUsed
; dwBlock
++)
830 URLCache_Allocation_BlockFree(AllocationTable
, dwBlock
);
832 ZeroMemory(pEntry
, pEntry
->dwBlocksUsed
* BLOCKSIZE
);
836 /***********************************************************************
837 * URLCache_LocalFileNameToPathW (Internal)
839 * Copies the full path to the specified buffer given the local file
840 * name and the index of the directory it is in. Always sets value in
841 * lpBufferSize to the required buffer size (in bytes).
844 * TRUE if the buffer was big enough
845 * FALSE if the buffer was too small
848 static BOOL
URLCache_LocalFileNameToPathW(
849 const URLCACHECONTAINER
* pContainer
,
850 LPCURLCACHE_HEADER pHeader
,
851 LPCSTR szLocalFileName
,
857 int path_len
= strlenW(pContainer
->path
);
858 int file_name_len
= MultiByteToWideChar(CP_ACP
, 0, szLocalFileName
, -1, NULL
, 0);
859 if (Directory
>= pHeader
->DirectoryCount
)
865 nRequired
= (path_len
+ DIR_LENGTH
+ file_name_len
+ 1) * sizeof(WCHAR
);
866 if (nRequired
< *lpBufferSize
)
870 memcpy(wszPath
, pContainer
->path
, path_len
* sizeof(WCHAR
));
871 dir_len
= MultiByteToWideChar(CP_ACP
, 0, pHeader
->directory_data
[Directory
].filename
, DIR_LENGTH
, wszPath
+ path_len
, DIR_LENGTH
);
872 wszPath
[dir_len
+ path_len
] = '\\';
873 MultiByteToWideChar(CP_ACP
, 0, szLocalFileName
, -1, wszPath
+ dir_len
+ path_len
+ 1, file_name_len
);
874 *lpBufferSize
= nRequired
;
877 *lpBufferSize
= nRequired
;
881 /***********************************************************************
882 * URLCache_LocalFileNameToPathA (Internal)
884 * Copies the full path to the specified buffer given the local file
885 * name and the index of the directory it is in. Always sets value in
886 * lpBufferSize to the required buffer size.
889 * TRUE if the buffer was big enough
890 * FALSE if the buffer was too small
893 static BOOL
URLCache_LocalFileNameToPathA(
894 const URLCACHECONTAINER
* pContainer
,
895 LPCURLCACHE_HEADER pHeader
,
896 LPCSTR szLocalFileName
,
902 int path_len
, file_name_len
, dir_len
;
904 if (Directory
>= pHeader
->DirectoryCount
)
910 path_len
= WideCharToMultiByte(CP_ACP
, 0, pContainer
->path
, -1, NULL
, 0, NULL
, NULL
) - 1;
911 file_name_len
= strlen(szLocalFileName
) + 1 /* for nul-terminator */;
912 dir_len
= DIR_LENGTH
;
914 nRequired
= (path_len
+ dir_len
+ 1 + file_name_len
) * sizeof(char);
915 if (nRequired
< *lpBufferSize
)
917 WideCharToMultiByte(CP_ACP
, 0, pContainer
->path
, -1, szPath
, path_len
, NULL
, NULL
);
918 memcpy(szPath
+path_len
, pHeader
->directory_data
[Directory
].filename
, dir_len
);
919 szPath
[path_len
+ dir_len
] = '\\';
920 memcpy(szPath
+ path_len
+ dir_len
+ 1, szLocalFileName
, file_name_len
);
921 *lpBufferSize
= nRequired
;
924 *lpBufferSize
= nRequired
;
928 /***********************************************************************
929 * URLCache_CopyEntry (Internal)
931 * Copies an entry from the cache index file to the Win32 structure
934 * TRUE if the buffer was big enough
935 * FALSE if the buffer was too small
938 static BOOL
URLCache_CopyEntry(
939 URLCACHECONTAINER
* pContainer
,
940 LPCURLCACHE_HEADER pHeader
,
941 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
942 LPDWORD lpdwBufferSize
,
943 const URL_CACHEFILE_ENTRY
* pUrlEntry
,
947 DWORD dwRequiredSize
= sizeof(*lpCacheEntryInfo
);
949 if (*lpdwBufferSize
>= dwRequiredSize
)
951 lpCacheEntryInfo
->lpHeaderInfo
= NULL
;
952 lpCacheEntryInfo
->lpszFileExtension
= NULL
;
953 lpCacheEntryInfo
->lpszLocalFileName
= NULL
;
954 lpCacheEntryInfo
->lpszSourceUrlName
= NULL
;
955 lpCacheEntryInfo
->CacheEntryType
= pUrlEntry
->CacheEntryType
;
956 lpCacheEntryInfo
->u
.dwExemptDelta
= pUrlEntry
->dwExemptDelta
;
957 lpCacheEntryInfo
->dwHeaderInfoSize
= pUrlEntry
->dwHeaderInfoSize
;
958 lpCacheEntryInfo
->dwHitRate
= pUrlEntry
->dwHitRate
;
959 lpCacheEntryInfo
->dwSizeHigh
= pUrlEntry
->dwSizeHigh
;
960 lpCacheEntryInfo
->dwSizeLow
= pUrlEntry
->dwSizeLow
;
961 lpCacheEntryInfo
->dwStructSize
= sizeof(*lpCacheEntryInfo
);
962 lpCacheEntryInfo
->dwUseCount
= pUrlEntry
->dwUseCount
;
963 DosDateTimeToFileTime(pUrlEntry
->wExpiredDate
, pUrlEntry
->wExpiredTime
, &lpCacheEntryInfo
->ExpireTime
);
964 lpCacheEntryInfo
->LastAccessTime
.dwHighDateTime
= pUrlEntry
->LastAccessTime
.dwHighDateTime
;
965 lpCacheEntryInfo
->LastAccessTime
.dwLowDateTime
= pUrlEntry
->LastAccessTime
.dwLowDateTime
;
966 lpCacheEntryInfo
->LastModifiedTime
.dwHighDateTime
= pUrlEntry
->LastModifiedTime
.dwHighDateTime
;
967 lpCacheEntryInfo
->LastModifiedTime
.dwLowDateTime
= pUrlEntry
->LastModifiedTime
.dwLowDateTime
;
968 DosDateTimeToFileTime(pUrlEntry
->wLastSyncDate
, pUrlEntry
->wLastSyncTime
, &lpCacheEntryInfo
->LastSyncTime
);
971 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
972 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
973 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
975 lenUrl
= MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, -1, NULL
, 0);
977 lenUrl
= strlen((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
978 dwRequiredSize
+= (lenUrl
+ 1) * (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
980 /* FIXME: is source url optional? */
981 if (*lpdwBufferSize
>= dwRequiredSize
)
983 lpCacheEntryInfo
->lpszSourceUrlName
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
- lenUrl
- 1;
985 MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, -1, (LPWSTR
)lpCacheEntryInfo
->lpszSourceUrlName
, lenUrl
+ 1);
987 memcpy(lpCacheEntryInfo
->lpszSourceUrlName
, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, (lenUrl
+ 1) * sizeof(CHAR
));
990 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
991 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
992 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
994 if (pUrlEntry
->dwOffsetLocalName
)
996 LONG nLocalFilePathSize
;
997 LPSTR lpszLocalFileName
;
998 lpszLocalFileName
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
;
999 nLocalFilePathSize
= *lpdwBufferSize
- dwRequiredSize
;
1000 if ((bUnicode
&& URLCache_LocalFileNameToPathW(pContainer
, pHeader
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
, pUrlEntry
->CacheDir
, (LPWSTR
)lpszLocalFileName
, &nLocalFilePathSize
)) ||
1001 URLCache_LocalFileNameToPathA(pContainer
, pHeader
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
, pUrlEntry
->CacheDir
, lpszLocalFileName
, &nLocalFilePathSize
))
1003 lpCacheEntryInfo
->lpszLocalFileName
= lpszLocalFileName
;
1005 dwRequiredSize
+= nLocalFilePathSize
* (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
)) ;
1007 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1008 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1009 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1011 dwRequiredSize
+= pUrlEntry
->dwHeaderInfoSize
+ 1;
1013 if (*lpdwBufferSize
>= dwRequiredSize
)
1015 lpCacheEntryInfo
->lpHeaderInfo
= (LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
- pUrlEntry
->dwHeaderInfoSize
- 1;
1016 memcpy(lpCacheEntryInfo
->lpHeaderInfo
, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
, pUrlEntry
->dwHeaderInfoSize
);
1017 ((LPBYTE
)lpCacheEntryInfo
)[dwRequiredSize
- 1] = '\0';
1019 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1020 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1021 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1023 if (pUrlEntry
->dwOffsetFileExtension
)
1028 lenExtension
= MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, -1, NULL
, 0);
1030 lenExtension
= strlen((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
) + 1;
1031 dwRequiredSize
+= lenExtension
* (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
1033 if (*lpdwBufferSize
>= dwRequiredSize
)
1035 lpCacheEntryInfo
->lpszFileExtension
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
- lenExtension
;
1037 MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, -1, (LPWSTR
)lpCacheEntryInfo
->lpszSourceUrlName
, lenExtension
);
1039 memcpy(lpCacheEntryInfo
->lpszFileExtension
, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetFileExtension
, lenExtension
* sizeof(CHAR
));
1042 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
1043 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
1044 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
1047 if (dwRequiredSize
> *lpdwBufferSize
)
1049 *lpdwBufferSize
= dwRequiredSize
;
1050 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1053 *lpdwBufferSize
= dwRequiredSize
;
1058 /***********************************************************************
1059 * URLCache_SetEntryInfo (Internal)
1061 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
1062 * according to the flags set by dwFieldControl.
1065 * TRUE if the buffer was big enough
1066 * FALSE if the buffer was too small
1069 static BOOL
URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY
* pUrlEntry
, const INTERNET_CACHE_ENTRY_INFOW
* lpCacheEntryInfo
, DWORD dwFieldControl
)
1071 if (dwFieldControl
& CACHE_ENTRY_ACCTIME_FC
)
1072 pUrlEntry
->LastAccessTime
= lpCacheEntryInfo
->LastAccessTime
;
1073 if (dwFieldControl
& CACHE_ENTRY_ATTRIBUTE_FC
)
1074 pUrlEntry
->CacheEntryType
= lpCacheEntryInfo
->CacheEntryType
;
1075 if (dwFieldControl
& CACHE_ENTRY_EXEMPT_DELTA_FC
)
1076 pUrlEntry
->dwExemptDelta
= lpCacheEntryInfo
->u
.dwExemptDelta
;
1077 if (dwFieldControl
& CACHE_ENTRY_EXPTIME_FC
)
1078 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
1079 if (dwFieldControl
& CACHE_ENTRY_HEADERINFO_FC
)
1080 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1081 if (dwFieldControl
& CACHE_ENTRY_HITRATE_FC
)
1082 pUrlEntry
->dwHitRate
= lpCacheEntryInfo
->dwHitRate
;
1083 if (dwFieldControl
& CACHE_ENTRY_MODTIME_FC
)
1084 pUrlEntry
->LastModifiedTime
= lpCacheEntryInfo
->LastModifiedTime
;
1085 if (dwFieldControl
& CACHE_ENTRY_SYNCTIME_FC
)
1086 FileTimeToDosDateTime(&lpCacheEntryInfo
->LastAccessTime
, &pUrlEntry
->wLastSyncDate
, &pUrlEntry
->wLastSyncTime
);
1091 /***********************************************************************
1092 * URLCache_HashKey (Internal)
1094 * Returns the hash key for a given string
1097 * hash key for the string
1100 static DWORD
URLCache_HashKey(LPCSTR lpszKey
)
1102 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
1103 * but the algorithm and result are not the same!
1105 static const unsigned char lookupTable
[256] =
1107 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1108 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1109 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1110 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1111 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1112 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1113 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1114 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1115 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1116 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1117 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1118 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1119 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1120 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1121 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1122 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1123 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1124 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1125 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1126 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1127 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1128 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1129 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1130 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1131 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1132 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1133 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1134 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1135 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1136 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1137 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1138 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1142 int subscript
[sizeof(key
) / sizeof(key
[0])];
1144 subscript
[0] = *lpszKey
;
1145 subscript
[1] = (char)(*lpszKey
+ 1);
1146 subscript
[2] = (char)(*lpszKey
+ 2);
1147 subscript
[3] = (char)(*lpszKey
+ 3);
1149 for (i
= 0; i
< sizeof(key
) / sizeof(key
[0]); i
++)
1150 key
[i
] = lookupTable
[i
];
1152 for (lpszKey
++; *lpszKey
&& ((lpszKey
[0] != '/') || (lpszKey
[1] != 0)); lpszKey
++)
1154 for (i
= 0; i
< sizeof(key
) / sizeof(key
[0]); i
++)
1155 key
[i
] = lookupTable
[*lpszKey
^ key
[i
]];
1158 return *(DWORD
*)key
;
1161 static inline HASH_CACHEFILE_ENTRY
* URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader
, DWORD dwOffset
)
1163 return (HASH_CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ dwOffset
);
1166 static inline BOOL
URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader
, const HASH_CACHEFILE_ENTRY
*pHashEntry
)
1168 /* check pHashEntry located within acceptable bounds in the URL cache mapping */
1169 return ((DWORD
)((LPBYTE
)pHashEntry
- (LPBYTE
)pHeader
) >= ENTRY_START_OFFSET
) &&
1170 ((DWORD
)((LPBYTE
)pHashEntry
- (LPBYTE
)pHeader
) < pHeader
->dwFileSize
);
1173 static BOOL
URLCache_FindHash(LPCURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, struct _HASH_ENTRY
** ppHashEntry
)
1175 /* structure of hash table:
1176 * 448 entries divided into 64 blocks
1177 * each block therefore contains a chain of 7 key/offset pairs
1178 * how position in table is calculated:
1179 * 1. the url is hashed in helper function
1180 * 2. the key % 64 * 8 is the offset
1181 * 3. the key in the hash table is the hash key aligned to 64
1184 * there can be multiple hash tables in the file and the offset to
1185 * the next one is stored in the header of the hash table
1187 DWORD key
= URLCache_HashKey(lpszUrl
);
1188 DWORD offset
= (key
% HASHTABLE_NUM_ENTRIES
) * sizeof(struct _HASH_ENTRY
);
1189 HASH_CACHEFILE_ENTRY
* pHashEntry
;
1190 DWORD dwHashTableNumber
= 0;
1192 key
= (key
/ HASHTABLE_NUM_ENTRIES
) * HASHTABLE_NUM_ENTRIES
;
1194 for (pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1195 URLCache_IsHashEntryValid(pHeader
, pHashEntry
);
1196 pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHashEntry
->dwAddressNext
))
1199 if (pHashEntry
->dwHashTableNumber
!= dwHashTableNumber
++)
1201 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry
->dwHashTableNumber
, dwHashTableNumber
);
1204 /* make sure that it is in fact a hash entry */
1205 if (pHashEntry
->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1207 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&pHashEntry
->CacheFileEntry
.dwSignature
);
1211 for (i
= 0; i
< HASHTABLE_BLOCKSIZE
; i
++)
1213 struct _HASH_ENTRY
* pHashElement
= &pHashEntry
->HashTable
[offset
+ i
];
1214 if (key
== (pHashElement
->dwHashKey
/ HASHTABLE_NUM_ENTRIES
) * HASHTABLE_NUM_ENTRIES
)
1216 /* FIXME: we should make sure that this is the right element
1217 * before returning and claiming that it is. We can do this
1218 * by doing a simple compare between the URL we were given
1219 * and the URL stored in the entry. However, this assumes
1220 * we know the format of all the entries stored in the
1222 *ppHashEntry
= pHashElement
;
1230 static BOOL
URLCache_FindHashW(LPCURLCACHE_HEADER pHeader
, LPCWSTR lpszUrl
, struct _HASH_ENTRY
** ppHashEntry
)
1236 url_len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrl
, -1, NULL
, 0, NULL
, NULL
);
1237 urlA
= HeapAlloc(GetProcessHeap(), 0, url_len
* sizeof(CHAR
));
1240 SetLastError(ERROR_OUTOFMEMORY
);
1243 WideCharToMultiByte(CP_ACP
, 0, lpszUrl
, -1, urlA
, url_len
, NULL
, NULL
);
1244 ret
= URLCache_FindHash(pHeader
, urlA
, ppHashEntry
);
1245 HeapFree(GetProcessHeap(), 0, urlA
);
1249 /***********************************************************************
1250 * URLCache_HashEntrySetUse (Internal)
1252 * Searches all the hash tables in the index for the given URL and
1253 * sets the use count (stored or'ed with key)
1256 * TRUE if the entry was found
1257 * FALSE if the entry could not be found
1260 static BOOL
URLCache_HashEntrySetUse(struct _HASH_ENTRY
* pHashEntry
, DWORD dwUseCount
)
1262 pHashEntry
->dwHashKey
= dwUseCount
| (pHashEntry
->dwHashKey
/ HASHTABLE_NUM_ENTRIES
) * HASHTABLE_NUM_ENTRIES
;
1266 /***********************************************************************
1267 * URLCache_DeleteEntryFromHash (Internal)
1269 * Searches all the hash tables in the index for the given URL and
1270 * then if found deletes the entry.
1273 * TRUE if the entry was found
1274 * FALSE if the entry could not be found
1277 static BOOL
URLCache_DeleteEntryFromHash(struct _HASH_ENTRY
* pHashEntry
)
1279 pHashEntry
->dwHashKey
= HASHTABLE_FREE
;
1280 pHashEntry
->dwOffsetEntry
= HASHTABLE_FREE
;
1284 /***********************************************************************
1285 * URLCache_AddEntryToHash (Internal)
1287 * Searches all the hash tables for a free slot based on the offset
1288 * generated from the hash key. If a free slot is found, the offset and
1289 * key are entered into the hash table.
1292 * TRUE if the entry was added
1293 * FALSE if the entry could not be added
1296 static BOOL
URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, DWORD dwOffsetEntry
)
1298 /* see URLCache_FindEntryInHash for structure of hash tables */
1300 DWORD key
= URLCache_HashKey(lpszUrl
);
1301 DWORD offset
= (key
% HASHTABLE_NUM_ENTRIES
) * sizeof(struct _HASH_ENTRY
);
1302 HASH_CACHEFILE_ENTRY
* pHashEntry
;
1303 DWORD dwHashTableNumber
= 0;
1305 key
= (key
/ HASHTABLE_NUM_ENTRIES
) * HASHTABLE_NUM_ENTRIES
;
1307 for (pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1308 URLCache_IsHashEntryValid(pHeader
, pHashEntry
);
1309 pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHashEntry
->dwAddressNext
))
1312 if (pHashEntry
->dwHashTableNumber
!= dwHashTableNumber
++)
1314 ERR("not right hash table number (%d) expected %d\n", pHashEntry
->dwHashTableNumber
, dwHashTableNumber
);
1317 /* make sure that it is in fact a hash entry */
1318 if (pHashEntry
->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1320 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&pHashEntry
->CacheFileEntry
.dwSignature
);
1324 for (i
= 0; i
< HASHTABLE_BLOCKSIZE
; i
++)
1326 struct _HASH_ENTRY
* pHashElement
= &pHashEntry
->HashTable
[offset
+ i
];
1327 if (pHashElement
->dwHashKey
== HASHTABLE_FREE
) /* if the slot is free */
1329 pHashElement
->dwHashKey
= key
;
1330 pHashElement
->dwOffsetEntry
= dwOffsetEntry
;
1335 pHashEntry
= URLCache_CreateHashTable(pHeader
, pHashEntry
);
1339 pHashEntry
->HashTable
[offset
].dwHashKey
= key
;
1340 pHashEntry
->HashTable
[offset
].dwOffsetEntry
= dwOffsetEntry
;
1344 /***********************************************************************
1345 * URLCache_CreateHashTable (Internal)
1347 * Creates a new hash table in free space and adds it to the chain of existing
1351 * TRUE if the hash table was created
1352 * FALSE if the hash table could not be created
1355 static HASH_CACHEFILE_ENTRY
*URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader
, HASH_CACHEFILE_ENTRY
*pPrevHash
)
1357 HASH_CACHEFILE_ENTRY
*pHash
;
1361 if (!URLCache_FindFirstFreeEntry(pHeader
, 0x20, (CACHEFILE_ENTRY
**)&pHash
))
1363 FIXME("no free space for hash table\n");
1364 SetLastError(ERROR_DISK_FULL
);
1368 dwOffset
= (BYTE
*)pHash
- (BYTE
*)pHeader
;
1371 pPrevHash
->dwAddressNext
= dwOffset
;
1373 pHeader
->dwOffsetFirstHashTable
= dwOffset
;
1374 pHash
->CacheFileEntry
.dwSignature
= HASH_SIGNATURE
;
1375 pHash
->CacheFileEntry
.dwBlocksUsed
= 0x20;
1376 pHash
->dwHashTableNumber
= pPrevHash
? pPrevHash
->dwHashTableNumber
+ 1 : 0;
1377 for (i
= 0; i
< HASHTABLE_SIZE
; i
++)
1379 pHash
->HashTable
[i
].dwOffsetEntry
= 0;
1380 pHash
->HashTable
[i
].dwHashKey
= HASHTABLE_FREE
;
1385 /***********************************************************************
1386 * URLCache_EnumHashTables (Internal)
1388 * Enumerates the hash tables in a container.
1391 * TRUE if an entry was found
1392 * FALSE if there are no more tables to enumerate.
1395 static BOOL
URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader
, DWORD
*pdwHashTableNumber
, HASH_CACHEFILE_ENTRY
** ppHashEntry
)
1397 for (*ppHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1398 URLCache_IsHashEntryValid(pHeader
, *ppHashEntry
);
1399 *ppHashEntry
= URLCache_HashEntryFromOffset(pHeader
, (*ppHashEntry
)->dwAddressNext
))
1401 TRACE("looking at hash table number %d\n", (*ppHashEntry
)->dwHashTableNumber
);
1402 if ((*ppHashEntry
)->dwHashTableNumber
!= *pdwHashTableNumber
)
1404 /* make sure that it is in fact a hash entry */
1405 if ((*ppHashEntry
)->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1407 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&(*ppHashEntry
)->CacheFileEntry
.dwSignature
);
1408 (*pdwHashTableNumber
)++;
1412 TRACE("hash table number %d found\n", *pdwHashTableNumber
);
1418 /***********************************************************************
1419 * URLCache_EnumHashTableEntries (Internal)
1421 * Enumerates entries in a hash table and returns the next non-free entry.
1424 * TRUE if an entry was found
1425 * FALSE if the hash table is empty or there are no more entries to
1429 static BOOL
URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader
, const HASH_CACHEFILE_ENTRY
* pHashEntry
,
1430 DWORD
* index
, const struct _HASH_ENTRY
** ppHashEntry
)
1432 for (; *index
< HASHTABLE_SIZE
; (*index
)++)
1434 if (pHashEntry
->HashTable
[*index
].dwHashKey
== HASHTABLE_FREE
)
1437 *ppHashEntry
= &pHashEntry
->HashTable
[*index
];
1438 TRACE("entry found %d\n", *index
);
1441 TRACE("no more entries (%d)\n", *index
);
1445 /***********************************************************************
1446 * GetUrlCacheEntryInfoExA (WININET.@)
1449 BOOL WINAPI
GetUrlCacheEntryInfoExA(
1451 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1452 LPDWORD lpdwCacheEntryInfoBufSize
,
1454 LPDWORD lpdwReserved
,
1458 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1459 debugstr_a(lpszUrl
),
1461 lpdwCacheEntryInfoBufSize
,
1467 if ((lpszReserved
!= NULL
) ||
1468 (lpdwReserved
!= NULL
) ||
1469 (lpReserved
!= NULL
))
1471 ERR("Reserved value was not 0\n");
1472 SetLastError(ERROR_INVALID_PARAMETER
);
1476 FIXME("Undocumented flag(s): %x\n", dwFlags
);
1477 return GetUrlCacheEntryInfoA(lpszUrl
, lpCacheEntryInfo
, lpdwCacheEntryInfoBufSize
);
1480 /***********************************************************************
1481 * GetUrlCacheEntryInfoA (WININET.@)
1484 BOOL WINAPI
GetUrlCacheEntryInfoA(
1485 IN LPCSTR lpszUrlName
,
1486 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1487 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1490 LPURLCACHE_HEADER pHeader
;
1491 struct _HASH_ENTRY
* pHashEntry
;
1492 const CACHEFILE_ENTRY
* pEntry
;
1493 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
1494 URLCACHECONTAINER
* pContainer
;
1496 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
, lpdwCacheEntryInfoBufferSize
);
1498 if (!URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
))
1501 if (!URLCacheContainer_OpenIndex(pContainer
))
1504 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1507 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
1509 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1510 WARN("entry %s not found!\n", debugstr_a(lpszUrlName
));
1511 SetLastError(ERROR_FILE_NOT_FOUND
);
1515 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1516 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1518 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1519 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1520 SetLastError(ERROR_FILE_NOT_FOUND
);
1524 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
1525 TRACE("Found URL: %s\n", debugstr_a((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
));
1526 if (pUrlEntry
->dwOffsetHeaderInfo
)
1527 TRACE("Header info: %s\n", debugstr_a((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
1529 if (lpdwCacheEntryInfoBufferSize
)
1531 if (!URLCache_CopyEntry(
1535 lpdwCacheEntryInfoBufferSize
,
1539 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1542 TRACE("Local File Name: %s\n", debugstr_a(lpCacheEntryInfo
->lpszLocalFileName
));
1545 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1550 /***********************************************************************
1551 * GetUrlCacheEntryInfoW (WININET.@)
1554 BOOL WINAPI
GetUrlCacheEntryInfoW(LPCWSTR lpszUrl
,
1555 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1556 LPDWORD lpdwCacheEntryInfoBufferSize
)
1558 LPURLCACHE_HEADER pHeader
;
1559 struct _HASH_ENTRY
* pHashEntry
;
1560 const CACHEFILE_ENTRY
* pEntry
;
1561 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
1562 URLCACHECONTAINER
* pContainer
;
1564 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl
), lpCacheEntryInfo
, lpdwCacheEntryInfoBufferSize
);
1566 if (!URLCacheContainers_FindContainerW(lpszUrl
, &pContainer
))
1569 if (!URLCacheContainer_OpenIndex(pContainer
))
1572 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1575 if (!URLCache_FindHashW(pHeader
, lpszUrl
, &pHashEntry
))
1577 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1578 WARN("entry %s not found!\n", debugstr_w(lpszUrl
));
1579 SetLastError(ERROR_FILE_NOT_FOUND
);
1583 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1584 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1586 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1587 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1588 SetLastError(ERROR_FILE_NOT_FOUND
);
1592 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
1593 TRACE("Found URL: %s\n", debugstr_a((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
));
1594 TRACE("Header info: %s\n", debugstr_a((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
1596 if (lpdwCacheEntryInfoBufferSize
)
1598 if (!URLCache_CopyEntry(
1601 (LPINTERNET_CACHE_ENTRY_INFOA
)lpCacheEntryInfo
,
1602 lpdwCacheEntryInfoBufferSize
,
1604 TRUE
/* UNICODE */))
1606 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1609 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo
->lpszLocalFileName
));
1612 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1617 /***********************************************************************
1618 * GetUrlCacheEntryInfoExW (WININET.@)
1621 BOOL WINAPI
GetUrlCacheEntryInfoExW(
1623 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1624 LPDWORD lpdwCacheEntryInfoBufSize
,
1625 LPWSTR lpszReserved
,
1626 LPDWORD lpdwReserved
,
1630 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n",
1631 debugstr_w(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
);
1648 FIXME("Undocumented flag(s): %x\n", dwFlags
);
1649 return GetUrlCacheEntryInfoW(lpszUrl
, lpCacheEntryInfo
, lpdwCacheEntryInfoBufSize
);
1652 /***********************************************************************
1653 * SetUrlCacheEntryInfoA (WININET.@)
1655 BOOL WINAPI
SetUrlCacheEntryInfoA(
1657 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1658 DWORD dwFieldControl
)
1660 LPURLCACHE_HEADER pHeader
;
1661 struct _HASH_ENTRY
* pHashEntry
;
1662 CACHEFILE_ENTRY
* pEntry
;
1663 URLCACHECONTAINER
* pContainer
;
1665 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
, dwFieldControl
);
1667 if (!URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
))
1670 if (!URLCacheContainer_OpenIndex(pContainer
))
1673 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1676 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
1678 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1679 WARN("entry %s not found!\n", debugstr_a(lpszUrlName
));
1680 SetLastError(ERROR_FILE_NOT_FOUND
);
1684 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1685 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1687 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1688 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1689 SetLastError(ERROR_FILE_NOT_FOUND
);
1693 URLCache_SetEntryInfo(
1694 (URL_CACHEFILE_ENTRY
*)pEntry
,
1695 (const INTERNET_CACHE_ENTRY_INFOW
*)lpCacheEntryInfo
,
1698 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1703 /***********************************************************************
1704 * SetUrlCacheEntryInfoW (WININET.@)
1706 BOOL WINAPI
SetUrlCacheEntryInfoW(LPCWSTR lpszUrl
, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
, DWORD dwFieldControl
)
1708 LPURLCACHE_HEADER pHeader
;
1709 struct _HASH_ENTRY
* pHashEntry
;
1710 CACHEFILE_ENTRY
* pEntry
;
1711 URLCACHECONTAINER
* pContainer
;
1713 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl
), lpCacheEntryInfo
, dwFieldControl
);
1715 if (!URLCacheContainers_FindContainerW(lpszUrl
, &pContainer
))
1718 if (!URLCacheContainer_OpenIndex(pContainer
))
1721 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1724 if (!URLCache_FindHashW(pHeader
, lpszUrl
, &pHashEntry
))
1726 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1727 WARN("entry %s not found!\n", debugstr_w(lpszUrl
));
1728 SetLastError(ERROR_FILE_NOT_FOUND
);
1732 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1733 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1735 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1736 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1737 SetLastError(ERROR_FILE_NOT_FOUND
);
1741 URLCache_SetEntryInfo(
1742 (URL_CACHEFILE_ENTRY
*)pEntry
,
1746 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1751 /***********************************************************************
1752 * RetrieveUrlCacheEntryFileA (WININET.@)
1755 BOOL WINAPI
RetrieveUrlCacheEntryFileA(
1756 IN LPCSTR lpszUrlName
,
1757 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1758 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
1762 LPURLCACHE_HEADER pHeader
;
1763 struct _HASH_ENTRY
* pHashEntry
;
1764 CACHEFILE_ENTRY
* pEntry
;
1765 URL_CACHEFILE_ENTRY
* pUrlEntry
;
1766 URLCACHECONTAINER
* pContainer
;
1768 TRACE("(%s, %p, %p, 0x%08x)\n",
1769 debugstr_a(lpszUrlName
),
1771 lpdwCacheEntryInfoBufferSize
,
1774 if (!URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
))
1777 if (!URLCacheContainer_OpenIndex(pContainer
))
1780 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1783 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
1785 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1786 TRACE("entry %s not found!\n", lpszUrlName
);
1787 SetLastError(ERROR_FILE_NOT_FOUND
);
1791 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1792 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1794 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1795 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1796 SetLastError(ERROR_FILE_NOT_FOUND
);
1800 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
1801 TRACE("Found URL: %s\n", (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
1802 TRACE("Header info: %s\n", (LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
);
1804 pUrlEntry
->dwHitRate
++;
1805 pUrlEntry
->dwUseCount
++;
1806 URLCache_HashEntrySetUse(pHashEntry
, pUrlEntry
->dwUseCount
);
1808 if (!URLCache_CopyEntry(pContainer
, pHeader
, lpCacheEntryInfo
, lpdwCacheEntryInfoBufferSize
, pUrlEntry
, FALSE
))
1810 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1813 TRACE("Local File Name: %s\n", lpCacheEntryInfo
->lpszLocalFileName
);
1815 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1820 /***********************************************************************
1821 * RetrieveUrlCacheEntryFileW (WININET.@)
1824 BOOL WINAPI
RetrieveUrlCacheEntryFileW(
1825 IN LPCWSTR lpszUrlName
,
1826 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1827 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
1831 LPURLCACHE_HEADER pHeader
;
1832 struct _HASH_ENTRY
* pHashEntry
;
1833 CACHEFILE_ENTRY
* pEntry
;
1834 URL_CACHEFILE_ENTRY
* pUrlEntry
;
1835 URLCACHECONTAINER
* pContainer
;
1837 TRACE("(%s, %p, %p, 0x%08x)\n",
1838 debugstr_w(lpszUrlName
),
1840 lpdwCacheEntryInfoBufferSize
,
1843 if (!URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
))
1846 if (!URLCacheContainer_OpenIndex(pContainer
))
1849 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1852 if (!URLCache_FindHashW(pHeader
, lpszUrlName
, &pHashEntry
))
1854 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1855 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName
));
1856 SetLastError(ERROR_FILE_NOT_FOUND
);
1860 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1861 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1863 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1864 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1865 SetLastError(ERROR_FILE_NOT_FOUND
);
1869 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
1870 TRACE("Found URL: %s\n", (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
1871 TRACE("Header info: %s\n", (LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
);
1873 pUrlEntry
->dwHitRate
++;
1874 pUrlEntry
->dwUseCount
++;
1875 URLCache_HashEntrySetUse(pHashEntry
, pUrlEntry
->dwUseCount
);
1877 if (!URLCache_CopyEntry(
1880 (LPINTERNET_CACHE_ENTRY_INFOA
)lpCacheEntryInfo
,
1881 lpdwCacheEntryInfoBufferSize
,
1883 TRUE
/* UNICODE */))
1885 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1888 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo
->lpszLocalFileName
));
1890 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1895 /***********************************************************************
1896 * UnlockUrlCacheEntryFileA (WININET.@)
1899 BOOL WINAPI
UnlockUrlCacheEntryFileA(
1900 IN LPCSTR lpszUrlName
,
1904 LPURLCACHE_HEADER pHeader
;
1905 struct _HASH_ENTRY
* pHashEntry
;
1906 CACHEFILE_ENTRY
* pEntry
;
1907 URL_CACHEFILE_ENTRY
* pUrlEntry
;
1908 URLCACHECONTAINER
* pContainer
;
1910 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName
), dwReserved
);
1914 ERR("dwReserved != 0\n");
1915 SetLastError(ERROR_INVALID_PARAMETER
);
1919 if (!URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
))
1922 if (!URLCacheContainer_OpenIndex(pContainer
))
1925 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1928 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
1930 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1931 TRACE("entry %s not found!\n", lpszUrlName
);
1932 SetLastError(ERROR_FILE_NOT_FOUND
);
1936 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1937 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1939 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1940 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1941 SetLastError(ERROR_FILE_NOT_FOUND
);
1945 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
1947 if (pUrlEntry
->dwUseCount
== 0)
1949 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1952 pUrlEntry
->dwUseCount
--;
1953 URLCache_HashEntrySetUse(pHashEntry
, pUrlEntry
->dwUseCount
);
1955 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1960 /***********************************************************************
1961 * UnlockUrlCacheEntryFileW (WININET.@)
1964 BOOL WINAPI
UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName
, DWORD dwReserved
)
1966 LPURLCACHE_HEADER pHeader
;
1967 struct _HASH_ENTRY
* pHashEntry
;
1968 CACHEFILE_ENTRY
* pEntry
;
1969 URL_CACHEFILE_ENTRY
* pUrlEntry
;
1970 URLCACHECONTAINER
* pContainer
;
1972 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName
), dwReserved
);
1976 ERR("dwReserved != 0\n");
1977 SetLastError(ERROR_INVALID_PARAMETER
);
1981 if (!URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
))
1984 if (!URLCacheContainer_OpenIndex(pContainer
))
1987 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1990 if (!URLCache_FindHashW(pHeader
, lpszUrlName
, &pHashEntry
))
1992 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1993 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName
));
1994 SetLastError(ERROR_FILE_NOT_FOUND
);
1998 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1999 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
2001 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2002 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
2003 SetLastError(ERROR_FILE_NOT_FOUND
);
2007 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2009 if (pUrlEntry
->dwUseCount
== 0)
2011 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2014 pUrlEntry
->dwUseCount
--;
2015 URLCache_HashEntrySetUse(pHashEntry
, pUrlEntry
->dwUseCount
);
2017 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2022 /***********************************************************************
2023 * CreateUrlCacheEntryA (WININET.@)
2026 BOOL WINAPI
CreateUrlCacheEntryA(
2027 IN LPCSTR lpszUrlName
,
2028 IN DWORD dwExpectedFileSize
,
2029 IN LPCSTR lpszFileExtension
,
2030 OUT LPSTR lpszFileName
,
2036 WCHAR
*file_extension
;
2037 WCHAR file_name
[MAX_PATH
];
2038 BOOL bSuccess
= FALSE
;
2041 if ((len
= MultiByteToWideChar(CP_ACP
, 0, lpszUrlName
, -1, NULL
, 0)) != 0 &&
2042 (url_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))) != 0)
2044 MultiByteToWideChar(CP_ACP
, 0, lpszUrlName
, -1, url_name
, len
);
2045 if ((len
= MultiByteToWideChar(CP_ACP
, 0, lpszFileExtension
, -1, NULL
, 0)) != 0 &&
2046 (file_extension
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))) != 0)
2048 MultiByteToWideChar(CP_ACP
, 0, lpszFileExtension
, -1, file_extension
, len
);
2049 if (CreateUrlCacheEntryW(url_name
, dwExpectedFileSize
, file_extension
, file_name
, dwReserved
))
2051 if (WideCharToMultiByte(CP_ACP
, 0, file_name
, -1, lpszFileName
, MAX_PATH
, NULL
, NULL
) < MAX_PATH
)
2057 dwError
= GetLastError();
2062 dwError
= GetLastError();
2064 HeapFree(GetProcessHeap(), 0, file_extension
);
2068 dwError
= GetLastError();
2070 HeapFree(GetProcessHeap(), 0, url_name
);
2072 SetLastError(dwError
);
2076 /***********************************************************************
2077 * CreateUrlCacheEntryW (WININET.@)
2080 BOOL WINAPI
CreateUrlCacheEntryW(
2081 IN LPCWSTR lpszUrlName
,
2082 IN DWORD dwExpectedFileSize
,
2083 IN LPCWSTR lpszFileExtension
,
2084 OUT LPWSTR lpszFileName
,
2088 URLCACHECONTAINER
* pContainer
;
2089 LPURLCACHE_HEADER pHeader
;
2090 CHAR szFile
[MAX_PATH
];
2091 WCHAR szExtension
[MAX_PATH
];
2092 LPCWSTR lpszUrlPart
;
2094 LPCWSTR lpszFileNameExtension
;
2095 LPWSTR lpszFileNameNoPath
;
2097 int countnoextension
;
2100 BOOL bFound
= FALSE
;
2102 static const WCHAR szWWW
[] = {'w','w','w',0};
2104 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n",
2105 debugstr_w(lpszUrlName
),
2107 debugstr_w(lpszFileExtension
),
2113 ERR("dwReserved != 0\n");
2114 SetLastError(ERROR_INVALID_PARAMETER
);
2118 lpszUrlEnd
= lpszUrlName
+ strlenW(lpszUrlName
);
2120 if (((lpszUrlEnd
- lpszUrlName
) > 1) && (*(lpszUrlEnd
- 1) == '/' || *(lpszUrlEnd
- 1) == '\\'))
2123 for (lpszUrlPart
= lpszUrlEnd
;
2124 (lpszUrlPart
>= lpszUrlName
);
2127 if ((*lpszUrlPart
== '/' || *lpszUrlPart
== '\\') && ((lpszUrlEnd
- lpszUrlPart
) > 1))
2133 else if(*lpszUrlPart
== '?' || *lpszUrlPart
== '#')
2135 lpszUrlEnd
= lpszUrlPart
;
2138 if (!lstrcmpW(lpszUrlPart
, szWWW
))
2140 lpszUrlPart
+= lstrlenW(szWWW
);
2143 count
= lpszUrlEnd
- lpszUrlPart
;
2145 if (bFound
&& (count
< MAX_PATH
))
2147 int len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlPart
, count
, szFile
, sizeof(szFile
) - 1, NULL
, NULL
);
2151 /* FIXME: get rid of illegal characters like \, / and : */
2155 FIXME("need to generate a random filename\n");
2158 TRACE("File name: %s\n", debugstr_a(szFile
));
2160 if (!URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
))
2163 if (!URLCacheContainer_OpenIndex(pContainer
))
2166 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2169 CacheDir
= (BYTE
)(rand() % pHeader
->DirectoryCount
);
2171 lBufferSize
= MAX_PATH
* sizeof(WCHAR
);
2172 URLCache_LocalFileNameToPathW(pContainer
, pHeader
, szFile
, CacheDir
, lpszFileName
, &lBufferSize
);
2174 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2176 for (lpszFileNameNoPath
= lpszFileName
+ lBufferSize
/ sizeof(WCHAR
) - 2;
2177 lpszFileNameNoPath
>= lpszFileName
;
2178 --lpszFileNameNoPath
)
2180 if (*lpszFileNameNoPath
== '/' || *lpszFileNameNoPath
== '\\')
2184 countnoextension
= lstrlenW(lpszFileNameNoPath
);
2185 lpszFileNameExtension
= PathFindExtensionW(lpszFileNameNoPath
);
2186 if (lpszFileNameExtension
)
2187 countnoextension
-= lstrlenW(lpszFileNameExtension
);
2188 *szExtension
= '\0';
2190 if (lpszFileExtension
)
2192 szExtension
[0] = '.';
2193 lstrcpyW(szExtension
+1, lpszFileExtension
);
2196 for (i
= 0; i
< 255; i
++)
2198 static const WCHAR szFormat
[] = {'[','%','u',']','%','s',0};
2200 wsprintfW(lpszFileNameNoPath
+ countnoextension
, szFormat
, i
, szExtension
);
2201 TRACE("Trying: %s\n", debugstr_w(lpszFileName
));
2202 hFile
= CreateFileW(lpszFileName
, GENERIC_READ
, 0, NULL
, CREATE_NEW
, 0, NULL
);
2203 if (hFile
!= INVALID_HANDLE_VALUE
)
2214 /***********************************************************************
2215 * CommitUrlCacheEntryInternal (Compensates for an MS bug)
2217 * The bug we are compensating for is that some drongo at Microsoft
2218 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA.
2219 * As a consequence, CommitUrlCacheEntryA has been effectively
2220 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW
2221 * is still defined as LPCWSTR. The result (other than madness) is
2222 * that we always need to store lpHeaderInfo in CP_ACP rather than
2223 * in UTF16, and we need to avoid converting lpHeaderInfo in
2224 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the
2225 * result will lose data for arbitrary binary data.
2228 static BOOL WINAPI
CommitUrlCacheEntryInternal(
2229 IN LPCWSTR lpszUrlName
,
2230 IN LPCWSTR lpszLocalFileName
,
2231 IN FILETIME ExpireTime
,
2232 IN FILETIME LastModifiedTime
,
2233 IN DWORD CacheEntryType
,
2234 IN LPBYTE lpHeaderInfo
,
2235 IN DWORD dwHeaderSize
,
2236 IN LPCWSTR lpszFileExtension
,
2237 IN LPCWSTR lpszOriginalUrl
2240 URLCACHECONTAINER
* pContainer
;
2241 LPURLCACHE_HEADER pHeader
;
2242 struct _HASH_ENTRY
* pHashEntry
;
2243 CACHEFILE_ENTRY
* pEntry
;
2244 URL_CACHEFILE_ENTRY
* pUrlEntry
;
2245 DWORD dwBytesNeeded
= DWORD_ALIGN(sizeof(*pUrlEntry
));
2246 DWORD dwOffsetLocalFileName
= 0;
2247 DWORD dwOffsetHeader
= 0;
2248 DWORD dwOffsetFileExtension
= 0;
2249 DWORD dwFileSizeLow
= 0;
2250 DWORD dwFileSizeHigh
= 0;
2251 BYTE cDirectory
= 0;
2253 char achFile
[MAX_PATH
];
2254 LPSTR lpszUrlNameA
= NULL
;
2255 LPSTR lpszFileExtensionA
= NULL
;
2256 char *pchLocalFileName
= 0;
2257 DWORD error
= ERROR_SUCCESS
;
2259 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2260 debugstr_w(lpszUrlName
),
2261 debugstr_w(lpszLocalFileName
),
2265 debugstr_w(lpszFileExtension
),
2266 debugstr_w(lpszOriginalUrl
));
2268 if (lpszOriginalUrl
)
2269 WARN(": lpszOriginalUrl ignored\n");
2271 if (lpszLocalFileName
)
2275 hFile
= CreateFileW(lpszLocalFileName
, FILE_READ_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, NULL
, OPEN_EXISTING
, 0, NULL
);
2276 if (hFile
== INVALID_HANDLE_VALUE
)
2278 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName
), GetLastError());
2283 dwFileSizeLow
= GetFileSize(hFile
, &dwFileSizeHigh
);
2284 if ((dwFileSizeLow
== INVALID_FILE_SIZE
) && (GetLastError() != NO_ERROR
))
2286 ERR("couldn't get file size (error is %d)\n", GetLastError());
2294 if (!URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
))
2297 if (!URLCacheContainer_OpenIndex(pContainer
))
2300 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2303 len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, NULL
, 0, NULL
, NULL
);
2304 lpszUrlNameA
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(char));
2307 error
= GetLastError();
2310 WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, lpszUrlNameA
, len
, NULL
, NULL
);
2312 if (lpszFileExtension
)
2314 len
= WideCharToMultiByte(CP_ACP
, 0, lpszFileExtension
, -1, NULL
, 0, NULL
, NULL
);
2315 lpszFileExtensionA
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(char));
2316 if (!lpszFileExtensionA
)
2318 error
= GetLastError();
2321 WideCharToMultiByte(CP_ACP
, 0, lpszFileExtension
, -1, lpszFileExtensionA
, len
, NULL
, NULL
);
2324 if (URLCache_FindHash(pHeader
, lpszUrlNameA
, &pHashEntry
))
2326 FIXME("entry already in cache - don't know what to do!\n");
2328 * SetLastError(ERROR_FILE_NOT_FOUND);
2334 if (lpszLocalFileName
)
2336 BOOL bFound
= FALSE
;
2338 if (strncmpW(lpszLocalFileName
, pContainer
->path
, lstrlenW(pContainer
->path
)))
2340 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName
), debugstr_w(pContainer
->path
));
2341 error
= ERROR_INVALID_PARAMETER
;
2345 /* skip container path prefix */
2346 lpszLocalFileName
+= lstrlenW(pContainer
->path
);
2348 WideCharToMultiByte(CP_ACP
, 0, lpszLocalFileName
, -1, achFile
, -1, NULL
, NULL
);
2349 pchLocalFileName
= achFile
;
2351 for (cDirectory
= 0; cDirectory
< pHeader
->DirectoryCount
; cDirectory
++)
2353 if (!strncmp(pHeader
->directory_data
[cDirectory
].filename
, pchLocalFileName
, DIR_LENGTH
))
2362 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName
));
2363 error
= ERROR_INVALID_PARAMETER
;
2367 lpszLocalFileName
+= (DIR_LENGTH
+ 1); /* "1234WXYZ\" */
2370 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(lpszUrlNameA
) + 1);
2371 if (lpszLocalFileName
)
2373 len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, NULL
, 0, NULL
, NULL
);
2374 dwOffsetLocalFileName
= dwBytesNeeded
;
2375 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(pchLocalFileName
) + 1);
2379 dwOffsetHeader
= dwBytesNeeded
;
2380 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ dwHeaderSize
);
2382 if (lpszFileExtensionA
)
2384 dwOffsetFileExtension
= dwBytesNeeded
;
2385 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(lpszFileExtensionA
) + 1);
2388 /* round up to next block */
2389 if (dwBytesNeeded
% BLOCKSIZE
)
2391 dwBytesNeeded
-= dwBytesNeeded
% BLOCKSIZE
;
2392 dwBytesNeeded
+= BLOCKSIZE
;
2395 if (!URLCache_FindFirstFreeEntry(pHeader
, dwBytesNeeded
/ BLOCKSIZE
, &pEntry
))
2397 ERR("no free entries\n");
2398 error
= ERROR_DISK_FULL
;
2402 /* FindFirstFreeEntry fills in blocks used */
2403 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
2404 pUrlEntry
->CacheFileEntry
.dwSignature
= URL_SIGNATURE
;
2405 pUrlEntry
->CacheDir
= cDirectory
;
2406 pUrlEntry
->CacheEntryType
= CacheEntryType
;
2407 pUrlEntry
->dwHeaderInfoSize
= dwHeaderSize
;
2408 pUrlEntry
->dwExemptDelta
= 0;
2409 pUrlEntry
->dwHitRate
= 0;
2410 pUrlEntry
->dwOffsetFileExtension
= dwOffsetFileExtension
;
2411 pUrlEntry
->dwOffsetHeaderInfo
= dwOffsetHeader
;
2412 pUrlEntry
->dwOffsetLocalName
= dwOffsetLocalFileName
;
2413 pUrlEntry
->dwOffsetUrl
= DWORD_ALIGN(sizeof(*pUrlEntry
));
2414 pUrlEntry
->dwSizeHigh
= 0;
2415 pUrlEntry
->dwSizeLow
= dwFileSizeLow
;
2416 pUrlEntry
->dwSizeHigh
= dwFileSizeHigh
;
2417 pUrlEntry
->dwUseCount
= 0;
2418 GetSystemTimeAsFileTime(&pUrlEntry
->LastAccessTime
);
2419 pUrlEntry
->LastModifiedTime
= LastModifiedTime
;
2420 FileTimeToDosDateTime(&pUrlEntry
->LastAccessTime
, &pUrlEntry
->wLastSyncDate
, &pUrlEntry
->wLastSyncTime
);
2421 FileTimeToDosDateTime(&ExpireTime
, &pUrlEntry
->wExpiredDate
, &pUrlEntry
->wExpiredTime
);
2422 pUrlEntry
->wUnknownDate
= pUrlEntry
->wLastSyncDate
;
2423 pUrlEntry
->wUnknownTime
= pUrlEntry
->wLastSyncTime
;
2426 pUrlEntry
->dwUnknown1
= 0;
2427 pUrlEntry
->dwUnknown2
= 0;
2428 pUrlEntry
->dwUnknown3
= 0x60;
2429 pUrlEntry
->Unknown4
= 0;
2430 pUrlEntry
->wUnknown5
= 0x1010;
2431 pUrlEntry
->dwUnknown7
= 0;
2432 pUrlEntry
->dwUnknown8
= 0;
2435 strcpy((LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
, lpszUrlNameA
);
2436 if (dwOffsetLocalFileName
)
2437 strcpy((LPSTR
)((LPBYTE
)pUrlEntry
+ dwOffsetLocalFileName
), pchLocalFileName
+ DIR_LENGTH
+ 1);
2439 memcpy((LPBYTE
)pUrlEntry
+ dwOffsetHeader
, lpHeaderInfo
, dwHeaderSize
);
2440 if (dwOffsetFileExtension
)
2441 strcpy((LPSTR
)((LPBYTE
)pUrlEntry
+ dwOffsetFileExtension
), lpszFileExtensionA
);
2443 if (!URLCache_AddEntryToHash(pHeader
, lpszUrlNameA
, (DWORD
)((LPBYTE
)pUrlEntry
- (LPBYTE
)pHeader
)))
2445 URLCache_DeleteEntry(pHeader
, &pUrlEntry
->CacheFileEntry
);
2446 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2447 HeapFree(GetProcessHeap(), 0, lpszUrlNameA
);
2452 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2453 HeapFree(GetProcessHeap(), 0, lpszUrlNameA
);
2454 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA
);
2456 if (error
== ERROR_SUCCESS
)
2460 SetLastError(error
);
2465 /***********************************************************************
2466 * CommitUrlCacheEntryA (WININET.@)
2469 BOOL WINAPI
CommitUrlCacheEntryA(
2470 IN LPCSTR lpszUrlName
,
2471 IN LPCSTR lpszLocalFileName
,
2472 IN FILETIME ExpireTime
,
2473 IN FILETIME LastModifiedTime
,
2474 IN DWORD CacheEntryType
,
2475 IN LPBYTE lpHeaderInfo
,
2476 IN DWORD dwHeaderSize
,
2477 IN LPCSTR lpszFileExtension
,
2478 IN LPCSTR lpszOriginalUrl
2482 WCHAR
*url_name
= NULL
;
2483 WCHAR
*local_file_name
= NULL
;
2484 WCHAR
*original_url
= NULL
;
2485 WCHAR
*file_extension
= NULL
;
2486 BOOL bSuccess
= FALSE
;
2488 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2489 debugstr_a(lpszUrlName
),
2490 debugstr_a(lpszLocalFileName
),
2494 debugstr_a(lpszFileExtension
),
2495 debugstr_a(lpszOriginalUrl
));
2497 len
= MultiByteToWideChar(CP_ACP
, 0, lpszUrlName
, -1, NULL
, 0);
2498 url_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2501 MultiByteToWideChar(CP_ACP
, 0, lpszUrlName
, -1, url_name
, len
);
2503 if (lpszLocalFileName
)
2505 len
= MultiByteToWideChar(CP_ACP
, 0, lpszLocalFileName
, -1, NULL
, 0);
2506 local_file_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2507 if (!local_file_name
)
2509 MultiByteToWideChar(CP_ACP
, 0, lpszLocalFileName
, -1, local_file_name
, len
);
2511 if (lpszFileExtension
)
2513 len
= MultiByteToWideChar(CP_ACP
, 0, lpszFileExtension
, -1, NULL
, 0);
2514 file_extension
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2515 if (!file_extension
)
2517 MultiByteToWideChar(CP_ACP
, 0, lpszFileExtension
, -1, file_extension
, len
);
2519 if (lpszOriginalUrl
)
2521 len
= MultiByteToWideChar(CP_ACP
, 0, lpszOriginalUrl
, -1, NULL
, 0);
2522 original_url
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2525 MultiByteToWideChar(CP_ACP
, 0, lpszOriginalUrl
, -1, original_url
, len
);
2528 bSuccess
= CommitUrlCacheEntryInternal(url_name
, local_file_name
, ExpireTime
, LastModifiedTime
,
2529 CacheEntryType
, lpHeaderInfo
, dwHeaderSize
,
2530 file_extension
, original_url
);
2533 HeapFree(GetProcessHeap(), 0, original_url
);
2534 HeapFree(GetProcessHeap(), 0, file_extension
);
2535 HeapFree(GetProcessHeap(), 0, local_file_name
);
2536 HeapFree(GetProcessHeap(), 0, url_name
);
2541 /***********************************************************************
2542 * CommitUrlCacheEntryW (WININET.@)
2545 BOOL WINAPI
CommitUrlCacheEntryW(
2546 IN LPCWSTR lpszUrlName
,
2547 IN LPCWSTR lpszLocalFileName
,
2548 IN FILETIME ExpireTime
,
2549 IN FILETIME LastModifiedTime
,
2550 IN DWORD CacheEntryType
,
2551 IN LPWSTR lpHeaderInfo
,
2552 IN DWORD dwHeaderSize
,
2553 IN LPCWSTR lpszFileExtension
,
2554 IN LPCWSTR lpszOriginalUrl
2558 BOOL bSuccess
= FALSE
;
2560 CHAR
*header_info
= NULL
;
2562 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
2563 debugstr_w(lpszUrlName
),
2564 debugstr_w(lpszLocalFileName
),
2568 debugstr_w(lpszFileExtension
),
2569 debugstr_w(lpszOriginalUrl
));
2571 if (!lpHeaderInfo
||
2572 ((len
= WideCharToMultiByte(CP_ACP
, 0, lpHeaderInfo
, -1, NULL
, 0, NULL
, NULL
)) != 0 &&
2573 (header_info
= HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR
) * len
)) != 0))
2576 WideCharToMultiByte(CP_ACP
, 0, lpHeaderInfo
, -1, header_info
, len
, NULL
, NULL
);
2577 if (CommitUrlCacheEntryInternal(lpszUrlName
, lpszLocalFileName
, ExpireTime
, LastModifiedTime
,
2578 CacheEntryType
, (LPBYTE
)header_info
, len
, lpszFileExtension
, lpszOriginalUrl
))
2584 dwError
= GetLastError();
2588 HeapFree(GetProcessHeap(), 0, header_info
);
2590 SetLastError(dwError
);
2596 /***********************************************************************
2597 * ReadUrlCacheEntryStream (WININET.@)
2600 BOOL WINAPI
ReadUrlCacheEntryStream(
2601 IN HANDLE hUrlCacheStream
,
2602 IN DWORD dwLocation
,
2603 IN OUT LPVOID lpBuffer
,
2604 IN OUT LPDWORD lpdwLen
,
2608 /* Get handle to file from 'stream' */
2609 STREAM_HANDLE
* pStream
= (STREAM_HANDLE
*)hUrlCacheStream
;
2611 if (dwReserved
!= 0)
2613 ERR("dwReserved != 0\n");
2614 SetLastError(ERROR_INVALID_PARAMETER
);
2618 if (IsBadReadPtr(pStream
, sizeof(*pStream
)) || IsBadStringPtrA(pStream
->lpszUrl
, INTERNET_MAX_URL_LENGTH
))
2620 SetLastError(ERROR_INVALID_HANDLE
);
2624 if (SetFilePointer(pStream
->hFile
, dwLocation
, NULL
, FILE_CURRENT
) == INVALID_SET_FILE_POINTER
)
2626 return ReadFile(pStream
->hFile
, lpBuffer
, *lpdwLen
, lpdwLen
, NULL
);
2629 /***********************************************************************
2630 * RetrieveUrlCacheEntryStreamA (WININET.@)
2633 HANDLE WINAPI
RetrieveUrlCacheEntryStreamA(
2634 IN LPCSTR lpszUrlName
,
2635 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
2636 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
2637 IN BOOL fRandomRead
,
2641 /* NOTE: this is not the same as the way that the native
2642 * version allocates 'stream' handles. I did it this way
2643 * as it is much easier and no applications should depend
2644 * on this behaviour. (Native version appears to allocate
2645 * indices into a table)
2647 STREAM_HANDLE
* pStream
;
2650 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
,
2651 lpdwCacheEntryInfoBufferSize
, fRandomRead
, dwReserved
);
2653 if (!RetrieveUrlCacheEntryFileA(lpszUrlName
,
2655 lpdwCacheEntryInfoBufferSize
,
2661 hFile
= CreateFileA(lpCacheEntryInfo
->lpszLocalFileName
,
2666 fRandomRead
? FILE_FLAG_RANDOM_ACCESS
: 0,
2668 if (hFile
== INVALID_HANDLE_VALUE
)
2671 /* allocate handle storage space */
2672 pStream
= HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE
) + strlen(lpszUrlName
) * sizeof(CHAR
));
2676 SetLastError(ERROR_OUTOFMEMORY
);
2680 pStream
->hFile
= hFile
;
2681 strcpy(pStream
->lpszUrl
, lpszUrlName
);
2682 return (HANDLE
)pStream
;
2685 /***********************************************************************
2686 * RetrieveUrlCacheEntryStreamW (WININET.@)
2689 HANDLE WINAPI
RetrieveUrlCacheEntryStreamW(
2690 IN LPCWSTR lpszUrlName
,
2691 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
2692 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
2693 IN BOOL fRandomRead
,
2697 FIXME( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName
), lpCacheEntryInfo
,
2698 lpdwCacheEntryInfoBufferSize
, fRandomRead
, dwReserved
);
2702 /***********************************************************************
2703 * UnlockUrlCacheEntryStream (WININET.@)
2706 BOOL WINAPI
UnlockUrlCacheEntryStream(
2707 IN HANDLE hUrlCacheStream
,
2711 STREAM_HANDLE
* pStream
= (STREAM_HANDLE
*)hUrlCacheStream
;
2713 if (dwReserved
!= 0)
2715 ERR("dwReserved != 0\n");
2716 SetLastError(ERROR_INVALID_PARAMETER
);
2720 if (IsBadReadPtr(pStream
, sizeof(*pStream
)) || IsBadStringPtrA(pStream
->lpszUrl
, INTERNET_MAX_URL_LENGTH
))
2722 SetLastError(ERROR_INVALID_HANDLE
);
2726 if (!UnlockUrlCacheEntryFileA(pStream
->lpszUrl
, 0))
2729 /* close file handle */
2730 CloseHandle(pStream
->hFile
);
2732 /* free allocated space */
2733 HeapFree(GetProcessHeap(), 0, pStream
);
2739 /***********************************************************************
2740 * DeleteUrlCacheEntryA (WININET.@)
2743 BOOL WINAPI
DeleteUrlCacheEntryA(LPCSTR lpszUrlName
)
2745 URLCACHECONTAINER
* pContainer
;
2746 LPURLCACHE_HEADER pHeader
;
2747 struct _HASH_ENTRY
* pHashEntry
;
2748 CACHEFILE_ENTRY
* pEntry
;
2750 TRACE("(%s)\n", debugstr_a(lpszUrlName
));
2752 if (!URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
))
2755 if (!URLCacheContainer_OpenIndex(pContainer
))
2758 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2761 if (!URLCache_FindHash(pHeader
, lpszUrlName
, &pHashEntry
))
2763 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2764 TRACE("entry %s not found!\n", lpszUrlName
);
2765 SetLastError(ERROR_FILE_NOT_FOUND
);
2769 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2770 URLCache_DeleteEntry(pHeader
, pEntry
);
2772 URLCache_DeleteEntryFromHash(pHashEntry
);
2774 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2779 /***********************************************************************
2780 * DeleteUrlCacheEntryW (WININET.@)
2783 BOOL WINAPI
DeleteUrlCacheEntryW(LPCWSTR lpszUrlName
)
2785 URLCACHECONTAINER
* pContainer
;
2786 LPURLCACHE_HEADER pHeader
;
2787 struct _HASH_ENTRY
* pHashEntry
;
2788 CACHEFILE_ENTRY
* pEntry
;
2792 TRACE("(%s)\n", debugstr_w(lpszUrlName
));
2794 url_len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, NULL
, 0, NULL
, NULL
);
2795 urlA
= HeapAlloc(GetProcessHeap(), 0, url_len
* sizeof(CHAR
));
2798 SetLastError(ERROR_OUTOFMEMORY
);
2801 WideCharToMultiByte(CP_ACP
, 0, lpszUrlName
, -1, urlA
, url_len
, NULL
, NULL
);
2803 if (!URLCacheContainers_FindContainerW(lpszUrlName
, &pContainer
))
2805 HeapFree(GetProcessHeap(), 0, urlA
);
2808 if (!URLCacheContainer_OpenIndex(pContainer
))
2810 HeapFree(GetProcessHeap(), 0, urlA
);
2813 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2815 HeapFree(GetProcessHeap(), 0, urlA
);
2819 if (!URLCache_FindHash(pHeader
, urlA
, &pHashEntry
))
2821 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2822 TRACE("entry %s not found!\n", debugstr_a(urlA
));
2823 HeapFree(GetProcessHeap(), 0, urlA
);
2824 SetLastError(ERROR_FILE_NOT_FOUND
);
2828 pEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
2829 URLCache_DeleteEntry(pHeader
, pEntry
);
2831 URLCache_DeleteEntryFromHash(pHashEntry
);
2833 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2835 HeapFree(GetProcessHeap(), 0, urlA
);
2839 BOOL WINAPI
DeleteUrlCacheContainerA(DWORD d1
, DWORD d2
)
2841 FIXME("(0x%08x, 0x%08x) stub\n", d1
, d2
);
2845 BOOL WINAPI
DeleteUrlCacheContainerW(DWORD d1
, DWORD d2
)
2847 FIXME("(0x%08x, 0x%08x) stub\n", d1
, d2
);
2851 /***********************************************************************
2852 * CreateCacheContainerA (WININET.@)
2854 BOOL WINAPI
CreateUrlCacheContainerA(DWORD d1
, DWORD d2
, DWORD d3
, DWORD d4
,
2855 DWORD d5
, DWORD d6
, DWORD d7
, DWORD d8
)
2857 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2858 d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
);
2862 /***********************************************************************
2863 * CreateCacheContainerW (WININET.@)
2865 BOOL WINAPI
CreateUrlCacheContainerW(DWORD d1
, DWORD d2
, DWORD d3
, DWORD d4
,
2866 DWORD d5
, DWORD d6
, DWORD d7
, DWORD d8
)
2868 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
2869 d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
);
2873 /***********************************************************************
2874 * FindFirstUrlCacheContainerA (WININET.@)
2876 HANDLE WINAPI
FindFirstUrlCacheContainerA( LPVOID p1
, LPVOID p2
, LPVOID p3
, DWORD d1
)
2878 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1
, p2
, p3
, d1
);
2882 /***********************************************************************
2883 * FindFirstUrlCacheContainerW (WININET.@)
2885 HANDLE WINAPI
FindFirstUrlCacheContainerW( LPVOID p1
, LPVOID p2
, LPVOID p3
, DWORD d1
)
2887 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1
, p2
, p3
, d1
);
2891 /***********************************************************************
2892 * FindNextUrlCacheContainerA (WININET.@)
2894 BOOL WINAPI
FindNextUrlCacheContainerA( HANDLE handle
, LPVOID p1
, LPVOID p2
)
2896 FIXME("(%p, %p, %p) stub\n", handle
, p1
, p2
);
2900 /***********************************************************************
2901 * FindNextUrlCacheContainerW (WININET.@)
2903 BOOL WINAPI
FindNextUrlCacheContainerW( HANDLE handle
, LPVOID p1
, LPVOID p2
)
2905 FIXME("(%p, %p, %p) stub\n", handle
, p1
, p2
);
2909 HANDLE WINAPI
FindFirstUrlCacheEntryExA(
2910 LPCSTR lpszUrlSearchPattern
,
2914 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
,
2915 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
2917 LPDWORD pcbReserved2
,
2921 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern
),
2922 dwFlags
, dwFilter
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, lpFirstCacheEntryInfo
,
2923 lpdwFirstCacheEntryInfoBufferSize
, lpReserved
, pcbReserved2
,lpReserved3
);
2924 SetLastError(ERROR_FILE_NOT_FOUND
);
2928 HANDLE WINAPI
FindFirstUrlCacheEntryExW(
2929 LPCWSTR lpszUrlSearchPattern
,
2933 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
,
2934 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
2936 LPDWORD pcbReserved2
,
2940 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern
),
2941 dwFlags
, dwFilter
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, lpFirstCacheEntryInfo
,
2942 lpdwFirstCacheEntryInfoBufferSize
, lpReserved
, pcbReserved2
,lpReserved3
);
2943 SetLastError(ERROR_FILE_NOT_FOUND
);
2947 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
2949 typedef struct URLCacheFindEntryHandle
2952 LPWSTR lpszUrlSearchPattern
;
2953 DWORD dwContainerIndex
;
2954 DWORD dwHashTableIndex
;
2955 DWORD dwHashEntryIndex
;
2956 } URLCacheFindEntryHandle
;
2958 /***********************************************************************
2959 * FindFirstUrlCacheEntryA (WININET.@)
2962 INTERNETAPI HANDLE WINAPI
FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern
,
2963 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
, LPDWORD lpdwFirstCacheEntryInfoBufferSize
)
2965 URLCacheFindEntryHandle
*pEntryHandle
;
2967 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern
), lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
);
2969 pEntryHandle
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle
));
2973 pEntryHandle
->dwMagic
= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
;
2974 if (lpszUrlSearchPattern
)
2976 int len
= MultiByteToWideChar(CP_ACP
, 0, lpszUrlSearchPattern
, -1, NULL
, 0);
2977 pEntryHandle
->lpszUrlSearchPattern
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2978 if (!pEntryHandle
->lpszUrlSearchPattern
)
2980 HeapFree(GetProcessHeap(), 0, pEntryHandle
);
2983 MultiByteToWideChar(CP_ACP
, 0, lpszUrlSearchPattern
, -1, pEntryHandle
->lpszUrlSearchPattern
, len
);
2986 pEntryHandle
->lpszUrlSearchPattern
= NULL
;
2987 pEntryHandle
->dwContainerIndex
= 0;
2988 pEntryHandle
->dwHashTableIndex
= 0;
2989 pEntryHandle
->dwHashEntryIndex
= 0;
2991 if (!FindNextUrlCacheEntryA(pEntryHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
))
2993 HeapFree(GetProcessHeap(), 0, pEntryHandle
);
2996 return pEntryHandle
;
2999 /***********************************************************************
3000 * FindFirstUrlCacheEntryW (WININET.@)
3003 INTERNETAPI HANDLE WINAPI
FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern
,
3004 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
, LPDWORD lpdwFirstCacheEntryInfoBufferSize
)
3006 URLCacheFindEntryHandle
*pEntryHandle
;
3008 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern
), lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
);
3010 pEntryHandle
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pEntryHandle
));
3014 pEntryHandle
->dwMagic
= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
;
3015 if (lpszUrlSearchPattern
)
3017 int len
= strlenW(lpszUrlSearchPattern
);
3018 pEntryHandle
->lpszUrlSearchPattern
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
3019 if (!pEntryHandle
->lpszUrlSearchPattern
)
3021 HeapFree(GetProcessHeap(), 0, pEntryHandle
);
3024 memcpy(pEntryHandle
->lpszUrlSearchPattern
, lpszUrlSearchPattern
, (len
+ 1) * sizeof(WCHAR
));
3027 pEntryHandle
->lpszUrlSearchPattern
= NULL
;
3028 pEntryHandle
->dwContainerIndex
= 0;
3029 pEntryHandle
->dwHashTableIndex
= 0;
3030 pEntryHandle
->dwHashEntryIndex
= 0;
3032 if (!FindNextUrlCacheEntryW(pEntryHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
))
3034 HeapFree(GetProcessHeap(), 0, pEntryHandle
);
3037 return pEntryHandle
;
3040 /***********************************************************************
3041 * FindNextUrlCacheEntryA (WININET.@)
3043 BOOL WINAPI
FindNextUrlCacheEntryA(
3045 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo
,
3046 LPDWORD lpdwNextCacheEntryInfoBufferSize
)
3048 URLCacheFindEntryHandle
*pEntryHandle
= (URLCacheFindEntryHandle
*)hEnumHandle
;
3049 URLCACHECONTAINER
* pContainer
;
3051 TRACE("(%p, %p, %p)\n", hEnumHandle
, lpNextCacheEntryInfo
, lpdwNextCacheEntryInfoBufferSize
);
3053 if (pEntryHandle
->dwMagic
!= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
)
3055 SetLastError(ERROR_INVALID_HANDLE
);
3059 for (; URLCacheContainers_Enum(pEntryHandle
->lpszUrlSearchPattern
, pEntryHandle
->dwContainerIndex
, &pContainer
);
3060 pEntryHandle
->dwContainerIndex
++, pEntryHandle
->dwHashTableIndex
= 0)
3062 LPURLCACHE_HEADER pHeader
;
3063 HASH_CACHEFILE_ENTRY
*pHashTableEntry
;
3065 if (!URLCacheContainer_OpenIndex(pContainer
))
3068 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3071 for (; URLCache_EnumHashTables(pHeader
, &pEntryHandle
->dwHashTableIndex
, &pHashTableEntry
);
3072 pEntryHandle
->dwHashTableIndex
++, pEntryHandle
->dwHashEntryIndex
= 0)
3074 const struct _HASH_ENTRY
*pHashEntry
= NULL
;
3075 for (; URLCache_EnumHashTableEntries(pHeader
, pHashTableEntry
, &pEntryHandle
->dwHashEntryIndex
, &pHashEntry
);
3076 pEntryHandle
->dwHashEntryIndex
++)
3078 const URL_CACHEFILE_ENTRY
*pUrlEntry
;
3079 const CACHEFILE_ENTRY
*pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3081 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
3084 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
3085 TRACE("Found URL: %s\n", (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetUrl
);
3086 TRACE("Header info: %s\n", (LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
);
3088 if (!URLCache_CopyEntry(
3091 lpNextCacheEntryInfo
,
3092 lpdwNextCacheEntryInfoBufferSize
,
3094 FALSE
/* not UNICODE */))
3096 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3099 TRACE("Local File Name: %s\n", debugstr_a(lpNextCacheEntryInfo
->lpszLocalFileName
));
3101 /* increment the current index so that next time the function
3102 * is called the next entry is returned */
3103 pEntryHandle
->dwHashEntryIndex
++;
3104 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3109 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3112 SetLastError(ERROR_NO_MORE_ITEMS
);
3116 BOOL WINAPI
FindNextUrlCacheEntryW(
3118 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo
,
3119 LPDWORD lpdwNextCacheEntryInfoBufferSize
3122 FIXME("(%p, %p, %p) stub\n", hEnumHandle
, lpNextCacheEntryInfo
, lpdwNextCacheEntryInfoBufferSize
);
3123 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3127 /***********************************************************************
3128 * FindCloseUrlCache (WININET.@)
3130 BOOL WINAPI
FindCloseUrlCache(HANDLE hEnumHandle
)
3132 URLCacheFindEntryHandle
*pEntryHandle
= (URLCacheFindEntryHandle
*)hEnumHandle
;
3134 TRACE("(%p)\n", hEnumHandle
);
3136 if (pEntryHandle
->dwMagic
!= URLCACHE_FIND_ENTRY_HANDLE_MAGIC
)
3138 SetLastError(ERROR_INVALID_HANDLE
);
3142 pEntryHandle
->dwMagic
= 0;
3143 HeapFree(GetProcessHeap(), 0, pEntryHandle
->lpszUrlSearchPattern
);
3144 HeapFree(GetProcessHeap(), 0, pEntryHandle
);
3149 HANDLE WINAPI
FindFirstUrlCacheGroup( DWORD dwFlags
, DWORD dwFilter
, LPVOID lpSearchCondition
,
3150 DWORD dwSearchCondition
, GROUPID
* lpGroupId
, LPVOID lpReserved
)
3152 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags
, dwFilter
, lpSearchCondition
,
3153 dwSearchCondition
, lpGroupId
, lpReserved
);
3157 BOOL WINAPI
FindNextUrlCacheEntryExA(
3159 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
,
3160 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3162 LPDWORD pcbReserved2
,
3166 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
,
3167 lpReserved
, pcbReserved2
, lpReserved3
);
3171 BOOL WINAPI
FindNextUrlCacheEntryExW(
3173 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
,
3174 LPDWORD lpdwFirstCacheEntryInfoBufferSize
,
3176 LPDWORD pcbReserved2
,
3180 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle
, lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
,
3181 lpReserved
, pcbReserved2
, lpReserved3
);
3185 BOOL WINAPI
FindNextUrlCacheGroup( HANDLE hFind
, GROUPID
* lpGroupId
, LPVOID lpReserved
)
3187 FIXME("(%p, %p, %p) stub\n", hFind
, lpGroupId
, lpReserved
);
3191 /***********************************************************************
3192 * CreateUrlCacheGroup (WININET.@)
3195 INTERNETAPI GROUPID WINAPI
CreateUrlCacheGroup(DWORD dwFlags
, LPVOID lpReserved
)
3197 FIXME("(0x%08x, %p): stub\n", dwFlags
, lpReserved
);
3201 /***********************************************************************
3202 * DeleteUrlCacheGroup (WININET.@)
3205 BOOL WINAPI
DeleteUrlCacheGroup(GROUPID GroupId
, DWORD dwFlags
, LPVOID lpReserved
)
3207 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n",
3208 (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
, dwFlags
, lpReserved
);
3212 /***********************************************************************
3213 * SetUrlCacheEntryGroupA (WININET.@)
3216 BOOL WINAPI
SetUrlCacheEntryGroupA(LPCSTR lpszUrlName
, DWORD dwFlags
,
3217 GROUPID GroupId
, LPBYTE pbGroupAttributes
, DWORD cbGroupAttributes
,
3220 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3221 debugstr_a(lpszUrlName
), dwFlags
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
,
3222 pbGroupAttributes
, cbGroupAttributes
, lpReserved
);
3223 SetLastError(ERROR_FILE_NOT_FOUND
);
3227 /***********************************************************************
3228 * SetUrlCacheEntryGroupW (WININET.@)
3231 BOOL WINAPI
SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName
, DWORD dwFlags
,
3232 GROUPID GroupId
, LPBYTE pbGroupAttributes
, DWORD cbGroupAttributes
,
3235 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n",
3236 debugstr_w(lpszUrlName
), dwFlags
, (ULONG
)(GroupId
>> 32), (ULONG
)GroupId
,
3237 pbGroupAttributes
, cbGroupAttributes
, lpReserved
);
3238 SetLastError(ERROR_FILE_NOT_FOUND
);
3242 /***********************************************************************
3243 * GetUrlCacheConfigInfoW (WININET.@)
3245 BOOL WINAPI
GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo
, LPDWORD size
, DWORD bitmask
)
3247 FIXME("(%p, %p, %x)\n", CacheInfo
, size
, bitmask
);
3248 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
3252 /***********************************************************************
3253 * GetUrlCacheConfigInfoA (WININET.@)
3255 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
3257 BOOL WINAPI
GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo
, LPDWORD size
, DWORD bitmask
)
3259 FIXME("(%p, %p, %x)\n", CacheInfo
, size
, bitmask
);
3260 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
3264 BOOL WINAPI
GetUrlCacheGroupAttributeA( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3265 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo
,
3266 LPDWORD lpdwGroupInfo
, LPVOID lpReserved
)
3268 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3269 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
,
3270 lpdwGroupInfo
, lpReserved
);
3274 BOOL WINAPI
GetUrlCacheGroupAttributeW( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3275 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo
,
3276 LPDWORD lpdwGroupInfo
, LPVOID lpReserved
)
3278 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3279 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
,
3280 lpdwGroupInfo
, lpReserved
);
3284 BOOL WINAPI
SetUrlCacheGroupAttributeA( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3285 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo
, LPVOID lpReserved
)
3287 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3288 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
, lpReserved
);
3292 BOOL WINAPI
SetUrlCacheGroupAttributeW( GROUPID gid
, DWORD dwFlags
, DWORD dwAttributes
,
3293 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo
, LPVOID lpReserved
)
3295 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n",
3296 (ULONG
)(gid
>> 32), (ULONG
)gid
, dwFlags
, dwAttributes
, lpGroupInfo
, lpReserved
);
3300 BOOL WINAPI
SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo
, DWORD dwFieldControl
)
3302 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo
, dwFieldControl
);
3306 BOOL WINAPI
SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo
, DWORD dwFieldControl
)
3308 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo
, dwFieldControl
);
3312 /***********************************************************************
3313 * DeleteIE3Cache (WININET.@)
3315 * Deletes the files used by the IE3 URL caching system.
3318 * hWnd [I] A dummy window.
3319 * hInst [I] Instance of process calling the function.
3320 * lpszCmdLine [I] Options used by function.
3321 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any.
3323 DWORD WINAPI
DeleteIE3Cache(HWND hWnd
, HINSTANCE hInst
, LPSTR lpszCmdLine
, int nCmdShow
)
3325 FIXME("(%p, %p, %s, %d)\n", hWnd
, hInst
, debugstr_a(lpszCmdLine
), nCmdShow
);
3329 /***********************************************************************
3330 * IsUrlCacheEntryExpiredA (WININET.@)
3334 * dwFlags [I] Unknown
3335 * pftLastModified [O] Last modified time
3337 BOOL WINAPI
IsUrlCacheEntryExpiredA( LPCSTR url
, DWORD dwFlags
, FILETIME
* pftLastModified
)
3339 LPURLCACHE_HEADER pHeader
;
3340 struct _HASH_ENTRY
* pHashEntry
;
3341 const CACHEFILE_ENTRY
* pEntry
;
3342 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
3343 URLCACHECONTAINER
* pContainer
;
3345 TRACE("(%s, %08x, %p)\n", debugstr_a(url
), dwFlags
, pftLastModified
);
3347 if (!URLCacheContainers_FindContainerA(url
, &pContainer
))
3350 if (!URLCacheContainer_OpenIndex(pContainer
))
3353 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3356 if (!URLCache_FindHash(pHeader
, url
, &pHashEntry
))
3358 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3359 TRACE("entry %s not found!\n", url
);
3360 SetLastError(ERROR_FILE_NOT_FOUND
);
3364 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3365 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
3367 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3368 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
3369 SetLastError(ERROR_FILE_NOT_FOUND
);
3373 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
3375 DosDateTimeToFileTime(pUrlEntry
->wExpiredDate
, pUrlEntry
->wExpiredTime
, pftLastModified
);
3377 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3382 /***********************************************************************
3383 * IsUrlCacheEntryExpiredW (WININET.@)
3387 * dwFlags [I] Unknown
3388 * pftLastModified [O] Last modified time
3390 BOOL WINAPI
IsUrlCacheEntryExpiredW( LPCWSTR url
, DWORD dwFlags
, FILETIME
* pftLastModified
)
3392 LPURLCACHE_HEADER pHeader
;
3393 struct _HASH_ENTRY
* pHashEntry
;
3394 const CACHEFILE_ENTRY
* pEntry
;
3395 const URL_CACHEFILE_ENTRY
* pUrlEntry
;
3396 URLCACHECONTAINER
* pContainer
;
3398 TRACE("(%s, %08x, %p)\n", debugstr_w(url
), dwFlags
, pftLastModified
);
3400 if (!URLCacheContainers_FindContainerW(url
, &pContainer
))
3403 if (!URLCacheContainer_OpenIndex(pContainer
))
3406 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
3409 if (!URLCache_FindHashW(pHeader
, url
, &pHashEntry
))
3411 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3412 TRACE("entry %s not found!\n", debugstr_w(url
));
3413 SetLastError(ERROR_FILE_NOT_FOUND
);
3417 pEntry
= (const CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
3418 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
3420 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
3421 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
3422 SetLastError(ERROR_FILE_NOT_FOUND
);
3426 pUrlEntry
= (const URL_CACHEFILE_ENTRY
*)pEntry
;
3428 DosDateTimeToFileTime(pUrlEntry
->wExpiredDate
, pUrlEntry
->wExpiredTime
, pftLastModified
);
3430 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);