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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #define COM_NO_WINDOWS_H
45 #include "wine/unicode.h"
46 #include "wine/list.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
51 #define ENTRY_START_OFFSET 0x4000
54 #define HASHTABLE_SIZE 448
55 #define HASHTABLE_BLOCKSIZE 7
56 #define HASHTABLE_FREE 3
57 #define ALLOCATION_TABLE_OFFSET 0x250
58 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET)
59 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
61 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
62 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
63 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
64 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
65 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
67 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
69 typedef struct _CACHEFILE_ENTRY
73 DWORD dwSignature
; /* e.g. "URL " */
74 /* CHAR szSignature[4];
76 DWORD dwBlocksUsed
; /* number of 128byte blocks used by this entry */
79 typedef struct _URL_CACHEFILE_ENTRY
81 CACHEFILE_ENTRY CacheFileEntry
;
82 FILETIME LastModifiedTime
;
83 FILETIME LastAccessTime
;
84 WORD wExpiredDate
; /* expire date in dos format */
85 WORD wExpiredTime
; /* expire time in dos format */
86 DWORD dwUnknown1
; /* usually zero */
87 DWORD dwSizeLow
; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
88 DWORD dwSizeHigh
; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
89 DWORD dwUnknown2
; /* usually zero */
90 DWORD dwExemptDelta
; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
91 DWORD dwUnknown3
; /* usually 0x60 */
92 DWORD dwOffsetUrl
; /* usually 0x68 */
93 BYTE CacheDir
; /* index of cache directory this url is stored in */
94 BYTE Unknown4
; /* usually zero */
95 WORD wUnknown5
; /* usually 0x1010 */
96 DWORD dwOffsetLocalName
; /* offset of start of local filename from start of entry */
97 DWORD CacheEntryType
; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
98 DWORD dwOffsetHeaderInfo
; /* offset of start of header info from start of entry */
99 DWORD dwHeaderInfoSize
;
100 DWORD dwUnknown6
; /* usually zero */
101 WORD wLastSyncDate
; /* last sync date in dos format */
102 WORD wLastSyncTime
; /* last sync time in dos format */
103 DWORD dwHitRate
; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
104 DWORD dwUseCount
; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
105 WORD wUnknownDate
; /* usually same as wLastSyncDate */
106 WORD wUnknownTime
; /* usually same as wLastSyncTime */
107 DWORD dwUnknown7
; /* usually zero */
108 DWORD dwUnknown8
; /* usually zero */
109 CHAR szSourceUrlName
[1]; /* start of url */
110 /* packing to dword align start of next field */
111 /* CHAR szLocalFileName[]; (local file name exluding path) */
112 /* packing to dword align start of next field */
113 /* CHAR szHeaderInfo[]; (header info) */
114 } URL_CACHEFILE_ENTRY
;
122 typedef struct _HASH_CACHEFILE_ENTRY
124 CACHEFILE_ENTRY CacheFileEntry
;
126 DWORD dwHashTableNumber
;
127 struct _HASH_ENTRY HashTable
[HASHTABLE_SIZE
];
128 } HASH_CACHEFILE_ENTRY
;
130 typedef struct _DIRECTORY_DATA
133 char filename
[DIR_LENGTH
];
136 typedef struct _URLCACHE_HEADER
138 char szSignature
[28];
140 DWORD dwOffsetFirstHashTable
;
141 DWORD dwIndexCapacityInBlocks
;
142 DWORD dwBlocksInUse
; /* is this right? */
144 DWORD dwCacheLimitLow
; /* disk space limit for cache */
145 DWORD dwCacheLimitHigh
; /* disk space limit for cache */
146 DWORD dwUnknown4
; /* current disk space usage for cache? */
147 DWORD dwUnknown5
; /* current disk space usage for cache? */
148 DWORD dwUnknown6
; /* possibly a flag? */
150 BYTE DirectoryCount
; /* number of directory_data's */
151 BYTE Unknown8
[3]; /* just padding? */
152 DIRECTORY_DATA directory_data
[1]; /* first directory entry */
153 } URLCACHE_HEADER
, *LPURLCACHE_HEADER
;
154 typedef const URLCACHE_HEADER
*LPCURLCACHE_HEADER
;
156 typedef struct _STREAM_HANDLE
162 typedef struct _URLCACHECONTAINER
164 struct list entry
; /* part of a list */
165 LPWSTR cache_prefix
; /* string that has to be prefixed for this container to be used */
166 LPWSTR path
; /* path to url container directory */
167 HANDLE hMapping
; /* handle of file mapping */
168 DWORD file_size
; /* size of file when mapping was opened */
169 HANDLE hMutex
; /* hande of mutex */
173 /* List of all containers available */
174 static struct list UrlContainers
= LIST_INIT(UrlContainers
);
177 /***********************************************************************
178 * URLCache_PathToObjectName (Internal)
180 * Converts a path to a name suitable for use as a Win32 object name.
181 * Replaces '\\' characters in-place with the specified character
182 * (usually '_' or '!')
188 static void URLCache_PathToObjectName(LPWSTR lpszPath
, WCHAR replace
)
190 for (; *lpszPath
; lpszPath
++)
192 if (*lpszPath
== '\\')
197 /***********************************************************************
198 * URLCacheContainer_OpenIndex (Internal)
200 * Opens the index file and saves mapping handle in hCacheIndexMapping
207 static BOOL
URLCacheContainer_OpenIndex(URLCACHECONTAINER
* pContainer
)
210 WCHAR wszFilePath
[MAX_PATH
];
213 static const WCHAR wszIndex
[] = {'i','n','d','e','x','.','d','a','t',0};
214 static const WCHAR wszMappingFormat
[] = {'%','s','%','s','_','%','l','u',0};
216 if (pContainer
->hMapping
)
219 strcpyW(wszFilePath
, pContainer
->path
);
220 strcatW(wszFilePath
, wszIndex
);
222 hFile
= CreateFileW(wszFilePath
, GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
223 if (hFile
== INVALID_HANDLE_VALUE
)
225 FIXME("need to create cache index file\n");
229 dwFileSize
= GetFileSize(hFile
, NULL
);
230 if (dwFileSize
== INVALID_FILE_SIZE
)
235 FIXME("need to create cache index file\n");
239 wsprintfW(wszFilePath
, wszMappingFormat
, pContainer
->path
, wszIndex
, dwFileSize
);
240 URLCache_PathToObjectName(wszFilePath
, '_');
241 pContainer
->hMapping
= OpenFileMappingW(FILE_MAP_WRITE
, FALSE
, wszFilePath
);
242 if (!pContainer
->hMapping
)
243 pContainer
->hMapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READWRITE
, 0, 0, wszFilePath
);
245 if (!pContainer
->hMapping
)
247 ERR("Couldn't create file mapping (error is %ld)\n", GetLastError());
254 /***********************************************************************
255 * URLCacheContainer_CloseIndex (Internal)
263 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER
* pContainer
)
265 CloseHandle(pContainer
->hMapping
);
266 pContainer
->hMapping
= NULL
;
269 static BOOL
URLCacheContainers_AddContainer(LPCWSTR cache_prefix
, LPCWSTR path
, LPWSTR mutex_name
)
271 URLCACHECONTAINER
* pContainer
= HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER
));
272 int path_len
= strlenW(path
);
273 int cache_prefix_len
= strlenW(cache_prefix
);
280 pContainer
->hMapping
= NULL
;
281 pContainer
->file_size
= 0;
283 pContainer
->path
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, (path_len
+ 1) * sizeof(WCHAR
));
284 if (!pContainer
->path
)
286 HeapFree(GetProcessHeap(), 0, pContainer
);
290 memcpy(pContainer
->path
, path
, (path_len
+ 1) * sizeof(WCHAR
));
292 pContainer
->cache_prefix
= HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len
+ 1) * sizeof(WCHAR
));
293 if (!pContainer
->cache_prefix
)
295 HeapFree(GetProcessHeap(), 0, pContainer
->path
);
296 HeapFree(GetProcessHeap(), 0, pContainer
);
300 memcpy(pContainer
->cache_prefix
, cache_prefix
, (cache_prefix_len
+ 1) * sizeof(WCHAR
));
302 CharLowerW(mutex_name
);
303 URLCache_PathToObjectName(mutex_name
, '!');
305 if ((pContainer
->hMutex
= CreateMutexW(NULL
, FALSE
, mutex_name
)) == NULL
)
307 ERR("couldn't create mutex (error is %ld)\n", GetLastError());
308 HeapFree(GetProcessHeap(), 0, pContainer
->path
);
309 HeapFree(GetProcessHeap(), 0, pContainer
);
313 list_add_head(&UrlContainers
, &pContainer
->entry
);
318 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER
* pContainer
)
320 list_remove(&pContainer
->entry
);
322 URLCacheContainer_CloseIndex(pContainer
);
323 CloseHandle(pContainer
->hMutex
);
324 HeapFree(GetProcessHeap(), 0, pContainer
->path
);
325 HeapFree(GetProcessHeap(), 0, pContainer
->cache_prefix
);
326 HeapFree(GetProcessHeap(), 0, pContainer
);
329 void URLCacheContainers_CreateDefaults()
331 static const WCHAR UrlSuffix
[] = {'C','o','n','t','e','n','t','.','I','E','5',0};
332 static const WCHAR UrlPrefix
[] = {0};
333 static const WCHAR HistorySuffix
[] = {'H','i','s','t','o','r','y','.','I','E','5',0};
334 static const WCHAR HistoryPrefix
[] = {'V','i','s','i','t','e','d',':',0};
335 static const WCHAR CookieSuffix
[] = {0};
336 static const WCHAR CookiePrefix
[] = {'C','o','o','k','i','e',':',0};
339 int nFolder
; /* CSIDL_* constant */
340 const WCHAR
* shpath_suffix
; /* suffix on path returned by SHGetSpecialFolderPath */
341 const WCHAR
* cache_prefix
; /* prefix used to reference the container */
342 } DefaultContainerData
[] =
344 { CSIDL_INTERNET_CACHE
, UrlSuffix
, UrlPrefix
},
345 { CSIDL_HISTORY
, HistorySuffix
, HistoryPrefix
},
346 { CSIDL_COOKIES
, CookieSuffix
, CookiePrefix
},
350 for (i
= 0; i
< sizeof(DefaultContainerData
) / sizeof(DefaultContainerData
[0]); i
++)
352 WCHAR wszCachePath
[MAX_PATH
];
353 WCHAR wszMutexName
[MAX_PATH
];
354 int path_len
, suffix_len
;
356 if (FAILED(SHGetSpecialFolderPathW(NULL
, wszCachePath
, DefaultContainerData
[i
].nFolder
, TRUE
)))
358 ERR("Couldn't get path for default container %d\n", i
);
361 path_len
= strlenW(wszCachePath
);
362 suffix_len
= strlenW(DefaultContainerData
[i
].shpath_suffix
);
364 if (path_len
+ suffix_len
+ 2 > MAX_PATH
)
366 ERR("Path too long\n");
370 wszCachePath
[path_len
] = '\\';
372 strcpyW(wszMutexName
, wszCachePath
);
376 memcpy(wszCachePath
+ path_len
+ 1, DefaultContainerData
[i
].shpath_suffix
, (suffix_len
+ 1) * sizeof(WCHAR
));
377 wszCachePath
[path_len
+ suffix_len
+ 1] = '\\';
378 wszCachePath
[path_len
+ suffix_len
+ 2] = '\0';
381 URLCacheContainers_AddContainer(DefaultContainerData
[i
].cache_prefix
, wszCachePath
, wszMutexName
);
385 void URLCacheContainers_DeleteAll()
387 while(!list_empty(&UrlContainers
))
388 URLCacheContainer_DeleteContainer(
389 LIST_ENTRY(list_head(&UrlContainers
), URLCACHECONTAINER
, entry
)
393 static BOOL
URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl
, URLCACHECONTAINER
** ppContainer
)
395 struct list
* cursor
;
397 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl
));
399 LIST_FOR_EACH(cursor
, &UrlContainers
)
401 URLCACHECONTAINER
* pContainer
= LIST_ENTRY(cursor
, URLCACHECONTAINER
, entry
);
402 int prefix_len
= strlenW(pContainer
->cache_prefix
);
403 if (!strncmpW(pContainer
->cache_prefix
, lpwszUrl
, prefix_len
))
405 TRACE("found container with prefx %s for URL %s\n", debugstr_w(pContainer
->cache_prefix
), debugstr_w(lpwszUrl
));
406 *ppContainer
= pContainer
;
410 ERR("no container found\n");
411 SetLastError(ERROR_FILE_NOT_FOUND
);
415 static BOOL
URLCacheContainers_FindContainerA(LPCSTR lpszUrl
, URLCACHECONTAINER
** ppContainer
)
419 int url_len
= MultiByteToWideChar(CP_ACP
, 0, lpszUrl
, -1, NULL
, 0);
420 if (url_len
&& (lpwszUrl
= HeapAlloc(GetProcessHeap(), 0, url_len
* sizeof(WCHAR
))))
422 MultiByteToWideChar(CP_ACP
, 0, lpszUrl
, -1, lpwszUrl
, url_len
);
423 ret
= URLCacheContainers_FindContainerW(lpwszUrl
, ppContainer
);
424 HeapFree(GetProcessHeap(), 0, lpwszUrl
);
430 /***********************************************************************
431 * URLCacheContainer_LockIndex (Internal)
434 static LPURLCACHE_HEADER
URLCacheContainer_LockIndex(URLCACHECONTAINER
* pContainer
)
438 URLCACHE_HEADER
* pHeader
;
441 WaitForSingleObject(pContainer
->hMutex
, INFINITE
);
443 pIndexData
= MapViewOfFile(pContainer
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
447 ReleaseMutex(pContainer
->hMutex
);
448 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
451 pHeader
= (URLCACHE_HEADER
*)pIndexData
;
453 /* file has grown - we need to remap to prevent us getting
454 * access violations when we try and access beyond the end
455 * of the memory mapped file */
456 if (pHeader
->dwFileSize
!= pContainer
->file_size
)
458 URLCacheContainer_CloseIndex(pContainer
);
459 if (!URLCacheContainer_OpenIndex(pContainer
))
461 ReleaseMutex(pContainer
->hMutex
);
464 pIndexData
= MapViewOfFile(pContainer
->hMapping
, FILE_MAP_WRITE
, 0, 0, 0);
468 ReleaseMutex(pContainer
->hMutex
);
469 ERR("Couldn't MapViewOfFile. Error: %ld\n", GetLastError());
472 pHeader
= (URLCACHE_HEADER
*)pIndexData
;
475 TRACE("Signature: %s, file size: %ld bytes\n", pHeader
->szSignature
, pHeader
->dwFileSize
);
477 for (index
= 0; index
< pHeader
->DirectoryCount
; index
++)
479 TRACE("Directory[%d] = \"%.8s\"\n", index
, pHeader
->directory_data
[index
].filename
);
485 /***********************************************************************
486 * URLCacheContainer_UnlockIndex (Internal)
489 static BOOL
URLCacheContainer_UnlockIndex(URLCACHECONTAINER
* pContainer
, LPURLCACHE_HEADER pHeader
)
492 ReleaseMutex(pContainer
->hMutex
);
493 return UnmapViewOfFile(pHeader
);
498 #define CHAR_BIT (8 * sizeof(CHAR))
501 /***********************************************************************
502 * URLCache_Allocation_BlockIsFree (Internal)
504 * Is the specified block number free?
511 static inline BYTE
URLCache_Allocation_BlockIsFree(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
513 BYTE mask
= 1 << (dwBlockNumber
% CHAR_BIT
);
514 return (AllocationTable
[dwBlockNumber
/ CHAR_BIT
] & mask
) == 0;
517 /***********************************************************************
518 * URLCache_Allocation_BlockFree (Internal)
520 * Marks the specified block as free
526 static inline void URLCache_Allocation_BlockFree(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
528 BYTE mask
= ~(1 << (dwBlockNumber
% CHAR_BIT
));
529 AllocationTable
[dwBlockNumber
/ CHAR_BIT
] &= mask
;
532 /***********************************************************************
533 * URLCache_Allocation_BlockAllocate (Internal)
535 * Marks the specified block as allocated
541 static inline void URLCache_Allocation_BlockAllocate(BYTE
* AllocationTable
, DWORD dwBlockNumber
)
543 BYTE mask
= 1 << (dwBlockNumber
% CHAR_BIT
);
544 AllocationTable
[dwBlockNumber
/ CHAR_BIT
] |= mask
;
547 /***********************************************************************
548 * URLCache_FindEntry (Internal)
550 * Finds an entry without using the hash tables
553 * TRUE if it found the specified entry
557 static BOOL
URLCache_FindEntry(LPCURLCACHE_HEADER pHeader
, LPCSTR szUrl
, CACHEFILE_ENTRY
** ppEntry
)
559 CACHEFILE_ENTRY
* pCurrentEntry
;
562 BYTE
* AllocationTable
= (LPBYTE
)pHeader
+ ALLOCATION_TABLE_OFFSET
;
564 for (pCurrentEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ ENTRY_START_OFFSET
);
565 (DWORD
)((LPBYTE
)pCurrentEntry
- (LPBYTE
)pHeader
) < pHeader
->dwFileSize
;
566 pCurrentEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pCurrentEntry
+ pCurrentEntry
->dwBlocksUsed
* BLOCKSIZE
))
568 dwBlockNumber
= (DWORD
)((LPBYTE
)pCurrentEntry
- (LPBYTE
)pHeader
- ENTRY_START_OFFSET
) / BLOCKSIZE
;
569 while (URLCache_Allocation_BlockIsFree(AllocationTable
, dwBlockNumber
))
571 if (dwBlockNumber
>= pHeader
->dwIndexCapacityInBlocks
)
574 pCurrentEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pCurrentEntry
+ BLOCKSIZE
);
575 dwBlockNumber
= (DWORD
)((LPBYTE
)pCurrentEntry
- (LPBYTE
)pHeader
- ENTRY_START_OFFSET
) / BLOCKSIZE
;
578 switch (pCurrentEntry
->dwSignature
)
580 case URL_SIGNATURE
: /* "URL " */
581 case LEAK_SIGNATURE
: /* "LEAK" */
583 URL_CACHEFILE_ENTRY
* pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pCurrentEntry
;
584 if (!strcmp(szUrl
, pUrlEntry
->szSourceUrlName
))
586 *ppEntry
= pCurrentEntry
;
587 /* FIXME: should we update the LastAccessTime here? */
592 case HASH_SIGNATURE
: /* HASH entries parsed in FindEntryInHash */
593 case 0xDEADBEEF: /* this is always at offset 0x4000 in URL cache for some reason */
596 FIXME("Unknown entry %.4s ignored\n", (LPCSTR
)&pCurrentEntry
->dwSignature
);
603 /***********************************************************************
604 * URLCache_FindFirstFreeEntry (Internal)
606 * Finds and allocates the first block of free space big enough and
607 * sets ppEntry to point to it.
610 * TRUE if it had enough space
611 * FALSE if it couldn't find enough space
614 static BOOL
URLCache_FindFirstFreeEntry(URLCACHE_HEADER
* pHeader
, DWORD dwBlocksNeeded
, CACHEFILE_ENTRY
** ppEntry
)
616 LPBYTE AllocationTable
= (LPBYTE
)pHeader
+ ALLOCATION_TABLE_OFFSET
;
619 for (dwBlockNumber
= 0; dwBlockNumber
< pHeader
->dwIndexCapacityInBlocks
; dwBlockNumber
++)
621 for (dwFreeCounter
= 0;
622 dwFreeCounter
< dwBlocksNeeded
&&
623 dwFreeCounter
+ dwBlockNumber
< pHeader
->dwIndexCapacityInBlocks
&&
624 URLCache_Allocation_BlockIsFree(AllocationTable
, dwBlockNumber
+ dwFreeCounter
);
626 TRACE("Found free block at no. %ld (0x%lx)\n", dwBlockNumber
, ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
628 if (dwFreeCounter
== dwBlocksNeeded
)
631 TRACE("Found free blocks starting at no. %ld (0x%lx)\n", dwBlockNumber
, ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
632 for (index
= 0; index
< dwBlocksNeeded
; index
++)
633 URLCache_Allocation_BlockAllocate(AllocationTable
, dwBlockNumber
+ index
);
634 *ppEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ ENTRY_START_OFFSET
+ dwBlockNumber
* BLOCKSIZE
);
635 (*ppEntry
)->dwBlocksUsed
= dwBlocksNeeded
;
639 FIXME("Grow file\n");
643 /***********************************************************************
644 * URLCache_DeleteEntry (Internal)
646 * Deletes the specified entry and frees the space allocated to it
649 * TRUE if it succeeded
653 static BOOL
URLCache_DeleteEntry(CACHEFILE_ENTRY
* pEntry
)
655 ZeroMemory(pEntry
, pEntry
->dwBlocksUsed
* BLOCKSIZE
);
659 /***********************************************************************
660 * URLCache_LocalFileNameToPathW (Internal)
662 * Copies the full path to the specified buffer given the local file
663 * name and the index of the directory it is in. Always sets value in
664 * lpBufferSize to the required buffer size (in bytes).
667 * TRUE if the buffer was big enough
668 * FALSE if the buffer was too small
671 static BOOL
URLCache_LocalFileNameToPathW(
672 const URLCACHECONTAINER
* pContainer
,
673 LPCURLCACHE_HEADER pHeader
,
674 LPCSTR szLocalFileName
,
680 int path_len
= strlenW(pContainer
->path
);
681 int file_name_len
= MultiByteToWideChar(CP_ACP
, 0, szLocalFileName
, -1, NULL
, 0);
682 if (Directory
>= pHeader
->DirectoryCount
)
688 nRequired
= (path_len
+ DIR_LENGTH
+ file_name_len
+ 1) * sizeof(WCHAR
);
689 if (nRequired
< *lpBufferSize
)
693 memcpy(wszPath
, pContainer
->path
, path_len
* sizeof(WCHAR
));
694 dir_len
= MultiByteToWideChar(CP_ACP
, 0, pHeader
->directory_data
[Directory
].filename
, DIR_LENGTH
, wszPath
+ path_len
, DIR_LENGTH
);
695 wszPath
[dir_len
+ path_len
] = '\\';
696 MultiByteToWideChar(CP_ACP
, 0, szLocalFileName
, -1, wszPath
+ dir_len
+ path_len
+ 1, file_name_len
);
697 *lpBufferSize
= nRequired
;
700 *lpBufferSize
= nRequired
;
704 /***********************************************************************
705 * URLCache_LocalFileNameToPathA (Internal)
707 * Copies the full path to the specified buffer given the local file
708 * name and the index of the directory it is in. Always sets value in
709 * lpBufferSize to the required buffer size.
712 * TRUE if the buffer was big enough
713 * FALSE if the buffer was too small
716 static BOOL
URLCache_LocalFileNameToPathA(
717 const URLCACHECONTAINER
* pContainer
,
718 LPCURLCACHE_HEADER pHeader
,
719 LPCSTR szLocalFileName
,
725 int path_len
= WideCharToMultiByte(CP_ACP
, 0, pContainer
->path
, -1, NULL
, 0, NULL
, NULL
);
726 int file_name_len
= strlen(szLocalFileName
);
727 int dir_len
= DIR_LENGTH
;
728 if (Directory
>= pHeader
->DirectoryCount
)
734 nRequired
= (path_len
+ dir_len
+ file_name_len
+ 1) * sizeof(WCHAR
);
735 if (nRequired
< *lpBufferSize
)
737 WideCharToMultiByte(CP_ACP
, 0, pContainer
->path
, -1, szPath
, -1, NULL
, NULL
);
738 strncpy(szPath
, pHeader
->directory_data
[Directory
].filename
, DIR_LENGTH
);
739 szPath
[dir_len
+ path_len
] = '\\';
740 strcpy(szPath
+ dir_len
+ path_len
+ 1, szLocalFileName
);
741 *lpBufferSize
= nRequired
;
744 *lpBufferSize
= nRequired
;
748 /***********************************************************************
749 * URLCache_CopyEntry (Internal)
751 * Copies an entry from the cache index file to the Win32 structure
754 * TRUE if the buffer was big enough
755 * FALSE if the buffer was too small
758 static BOOL
URLCache_CopyEntry(
759 URLCACHECONTAINER
* pContainer
,
760 LPCURLCACHE_HEADER pHeader
,
761 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
762 LPDWORD lpdwBufferSize
,
763 URL_CACHEFILE_ENTRY
* pUrlEntry
,
767 DWORD dwRequiredSize
= sizeof(*lpCacheEntryInfo
);
769 if (*lpdwBufferSize
>= dwRequiredSize
)
771 lpCacheEntryInfo
->lpHeaderInfo
= NULL
;
772 lpCacheEntryInfo
->lpszFileExtension
= NULL
;
773 lpCacheEntryInfo
->lpszLocalFileName
= NULL
;
774 lpCacheEntryInfo
->lpszSourceUrlName
= NULL
;
775 lpCacheEntryInfo
->CacheEntryType
= pUrlEntry
->CacheEntryType
;
776 lpCacheEntryInfo
->u
.dwExemptDelta
= pUrlEntry
->dwExemptDelta
;
777 lpCacheEntryInfo
->dwHeaderInfoSize
= pUrlEntry
->dwHeaderInfoSize
;
778 lpCacheEntryInfo
->dwHitRate
= pUrlEntry
->dwHitRate
;
779 lpCacheEntryInfo
->dwSizeHigh
= pUrlEntry
->dwSizeHigh
;
780 lpCacheEntryInfo
->dwSizeLow
= pUrlEntry
->dwSizeLow
;
781 lpCacheEntryInfo
->dwStructSize
= sizeof(*lpCacheEntryInfo
);
782 lpCacheEntryInfo
->dwUseCount
= pUrlEntry
->dwUseCount
;
783 DosDateTimeToFileTime(pUrlEntry
->wExpiredDate
, pUrlEntry
->wExpiredTime
, &lpCacheEntryInfo
->ExpireTime
);
784 lpCacheEntryInfo
->LastAccessTime
.dwHighDateTime
= pUrlEntry
->LastAccessTime
.dwHighDateTime
;
785 lpCacheEntryInfo
->LastAccessTime
.dwLowDateTime
= pUrlEntry
->LastAccessTime
.dwLowDateTime
;
786 lpCacheEntryInfo
->LastModifiedTime
.dwHighDateTime
= pUrlEntry
->LastModifiedTime
.dwHighDateTime
;
787 lpCacheEntryInfo
->LastModifiedTime
.dwLowDateTime
= pUrlEntry
->LastModifiedTime
.dwLowDateTime
;
788 DosDateTimeToFileTime(pUrlEntry
->wLastSyncDate
, pUrlEntry
->wLastSyncTime
, &lpCacheEntryInfo
->LastSyncTime
);
791 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
792 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
793 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
795 lenUrl
= MultiByteToWideChar(CP_ACP
, 0, pUrlEntry
->szSourceUrlName
, -1, NULL
, 0);
797 lenUrl
= strlen(pUrlEntry
->szSourceUrlName
);
798 dwRequiredSize
+= lenUrl
+ 1;
800 /* FIXME: is source url optional? */
801 if (*lpdwBufferSize
>= dwRequiredSize
)
803 lpCacheEntryInfo
->lpszSourceUrlName
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
- lenUrl
- 1;
805 MultiByteToWideChar(CP_ACP
, 0, pUrlEntry
->szSourceUrlName
, -1, (LPWSTR
)lpCacheEntryInfo
->lpszSourceUrlName
, lenUrl
+ 1);
807 memcpy(lpCacheEntryInfo
->lpszSourceUrlName
, pUrlEntry
->szSourceUrlName
, (lenUrl
+ 1) * sizeof(CHAR
));
810 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
811 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
812 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
814 if (pUrlEntry
->dwOffsetLocalName
)
816 LONG nLocalFilePathSize
;
817 LPSTR lpszLocalFileName
;
818 lpszLocalFileName
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
;
819 nLocalFilePathSize
= *lpdwBufferSize
- dwRequiredSize
;
820 if ((bUnicode
&& URLCache_LocalFileNameToPathW(pContainer
, pHeader
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
, pUrlEntry
->CacheDir
, (LPWSTR
)lpszLocalFileName
, &nLocalFilePathSize
)) ||
821 URLCache_LocalFileNameToPathA(pContainer
, pHeader
, (LPCSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetLocalName
, pUrlEntry
->CacheDir
, lpszLocalFileName
, &nLocalFilePathSize
))
823 lpCacheEntryInfo
->lpszLocalFileName
= lpszLocalFileName
;
825 dwRequiredSize
+= nLocalFilePathSize
;
827 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
828 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
829 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
831 dwRequiredSize
+= pUrlEntry
->dwHeaderInfoSize
+ 1;
833 if (*lpdwBufferSize
>= dwRequiredSize
)
835 lpCacheEntryInfo
->lpHeaderInfo
= (LPSTR
)lpCacheEntryInfo
+ dwRequiredSize
- pUrlEntry
->dwHeaderInfoSize
- 1;
836 memcpy(lpCacheEntryInfo
->lpHeaderInfo
, (LPSTR
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
, pUrlEntry
->dwHeaderInfoSize
);
837 ((LPBYTE
)lpCacheEntryInfo
)[dwRequiredSize
- 1] = '\0';
839 if ((dwRequiredSize
% 4) && (dwRequiredSize
< *lpdwBufferSize
))
840 ZeroMemory((LPBYTE
)lpCacheEntryInfo
+ dwRequiredSize
, 4 - (dwRequiredSize
% 4));
841 dwRequiredSize
= DWORD_ALIGN(dwRequiredSize
);
843 if (dwRequiredSize
> *lpdwBufferSize
)
845 *lpdwBufferSize
= dwRequiredSize
;
846 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
849 *lpdwBufferSize
= dwRequiredSize
;
854 /***********************************************************************
855 * URLCache_SetEntryInfo (Internal)
857 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry
858 * according the the flags set by dwFieldControl.
861 * TRUE if the buffer was big enough
862 * FALSE if the buffer was too small
865 static BOOL
URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY
* pUrlEntry
, const INTERNET_CACHE_ENTRY_INFOW
* lpCacheEntryInfo
, DWORD dwFieldControl
)
867 if (dwFieldControl
& CACHE_ENTRY_ACCTIME_FC
)
868 pUrlEntry
->LastAccessTime
= lpCacheEntryInfo
->LastAccessTime
;
869 if (dwFieldControl
& CACHE_ENTRY_ATTRIBUTE_FC
)
870 pUrlEntry
->CacheEntryType
= lpCacheEntryInfo
->CacheEntryType
;
871 if (dwFieldControl
& CACHE_ENTRY_EXEMPT_DELTA_FC
)
872 pUrlEntry
->dwExemptDelta
= lpCacheEntryInfo
->u
.dwExemptDelta
;
873 if (dwFieldControl
& CACHE_ENTRY_EXPTIME_FC
)
874 FIXME("CACHE_ENTRY_EXPTIME_FC unimplemented\n");
875 if (dwFieldControl
& CACHE_ENTRY_HEADERINFO_FC
)
876 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
877 if (dwFieldControl
& CACHE_ENTRY_HITRATE_FC
)
878 pUrlEntry
->dwHitRate
= lpCacheEntryInfo
->dwHitRate
;
879 if (dwFieldControl
& CACHE_ENTRY_MODTIME_FC
)
880 pUrlEntry
->LastModifiedTime
= lpCacheEntryInfo
->LastModifiedTime
;
881 if (dwFieldControl
& CACHE_ENTRY_SYNCTIME_FC
)
882 FileTimeToDosDateTime(&lpCacheEntryInfo
->LastAccessTime
, &pUrlEntry
->wLastSyncDate
, &pUrlEntry
->wLastSyncTime
);
887 /***********************************************************************
888 * URLCache_HashKey (Internal)
890 * Returns the hash key for a given string
893 * hash key for the string
896 static DWORD
URLCache_HashKey(LPCSTR lpszKey
)
898 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W}
899 * but the algorithm and result are not the same!
901 static const unsigned char lookupTable
[256] =
903 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
904 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
905 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
906 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
907 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
908 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
909 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
910 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
911 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
912 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
913 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
914 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
915 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
916 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
917 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
918 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
919 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
920 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
921 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
922 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
923 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
924 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
925 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
926 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
927 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
928 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
929 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
930 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
931 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
932 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
933 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
934 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
938 int subscript
[sizeof(key
) / sizeof(key
[0])];
940 subscript
[0] = *lpszKey
;
941 subscript
[1] = (char)(*lpszKey
+ 1);
942 subscript
[2] = (char)(*lpszKey
+ 2);
943 subscript
[3] = (char)(*lpszKey
+ 3);
945 for (i
= 0; i
< sizeof(key
) / sizeof(key
[0]); i
++)
946 key
[i
] = lookupTable
[i
];
948 for (lpszKey
++; *lpszKey
&& ((lpszKey
[0] != '/') || (lpszKey
[1] != 0)); lpszKey
++)
950 for (i
= 0; i
< sizeof(key
) / sizeof(key
[0]); i
++)
951 key
[i
] = lookupTable
[*lpszKey
^ key
[i
]];
954 return *(DWORD
*)key
;
957 static inline HASH_CACHEFILE_ENTRY
* URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader
, DWORD dwOffset
)
959 return (HASH_CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ dwOffset
);
962 static BOOL
URLCache_FindHash(LPCURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, struct _HASH_ENTRY
** ppHashEntry
)
964 /* structure of hash table:
965 * 448 entries divided into 64 blocks
966 * each block therefore contains a chain of 7 key/offset pairs
967 * how position in table is calculated:
968 * 1. the url is hashed in helper function
969 * 2. the key % 64 * 8 is the offset
970 * 3. the key in the hash table is the hash key aligned to 64
973 * there can be multiple hash tables in the file and the offset to
974 * the next one is stored in the header of the hash table
976 DWORD key
= URLCache_HashKey(lpszUrl
);
977 DWORD offset
= (key
% HASHTABLE_NUM_ENTRIES
) * sizeof(struct _HASH_ENTRY
);
978 HASH_CACHEFILE_ENTRY
* pHashEntry
;
979 DWORD dwHashTableNumber
= 0;
981 key
= (DWORD
)(key
/ HASHTABLE_NUM_ENTRIES
) * HASHTABLE_NUM_ENTRIES
;
983 for (pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
984 ((DWORD
)((LPBYTE
)pHashEntry
- (LPBYTE
)pHeader
) >= ENTRY_START_OFFSET
) && ((DWORD
)((LPBYTE
)pHashEntry
- (LPBYTE
)pHeader
) < pHeader
->dwFileSize
);
985 pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHashEntry
->dwAddressNext
))
988 if (pHashEntry
->dwHashTableNumber
!= dwHashTableNumber
++)
990 ERR("Error: not right hash table number (%ld) expected %ld\n", pHashEntry
->dwHashTableNumber
, dwHashTableNumber
);
993 /* make sure that it is in fact a hash entry */
994 if (pHashEntry
->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
996 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&pHashEntry
->CacheFileEntry
.dwSignature
);
1000 for (i
= 0; i
< HASHTABLE_BLOCKSIZE
; i
++)
1002 struct _HASH_ENTRY
* pHashElement
= &pHashEntry
->HashTable
[offset
+ i
];
1003 if (key
== (DWORD
)(pHashElement
->dwHashKey
/ HASHTABLE_NUM_ENTRIES
) * HASHTABLE_NUM_ENTRIES
)
1005 /* FIXME: we should make sure that this is the right element
1006 * before returning and claiming that it is. We can do this
1007 * by doing a simple compare between the URL we were given
1008 * and the URL stored in the entry. However, this assumes
1009 * we know the format of all the entries stored in the
1011 *ppHashEntry
= pHashElement
;
1019 /***********************************************************************
1020 * URLCache_FindEntryInHash (Internal)
1022 * Searches all the hash tables in the index for the given URL and
1023 * returns the entry, if it was found, in ppEntry
1026 * TRUE if the entry was found
1027 * FALSE if the entry could not be found
1030 static BOOL
URLCache_FindEntryInHash(LPCURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, CACHEFILE_ENTRY
** ppEntry
)
1032 struct _HASH_ENTRY
* pHashEntry
;
1033 if (URLCache_FindHash(pHeader
, lpszUrl
, &pHashEntry
))
1035 *ppEntry
= (CACHEFILE_ENTRY
*)((LPBYTE
)pHeader
+ pHashEntry
->dwOffsetEntry
);
1041 /***********************************************************************
1042 * URLCache_HashEntrySetUse (Internal)
1044 * Searches all the hash tables in the index for the given URL and
1045 * sets the use count (stored or'ed with key)
1048 * TRUE if the entry was found
1049 * FALSE if the entry could not be found
1052 static BOOL
URLCache_HashEntrySetUse(LPCURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, DWORD dwUseCount
)
1054 struct _HASH_ENTRY
* pHashEntry
;
1055 if (URLCache_FindHash(pHeader
, lpszUrl
, &pHashEntry
))
1057 pHashEntry
->dwHashKey
= dwUseCount
| (DWORD
)(pHashEntry
->dwHashKey
/ HASHTABLE_NUM_ENTRIES
) * HASHTABLE_NUM_ENTRIES
;
1063 /***********************************************************************
1064 * URLCache_DeleteEntryFromHash (Internal)
1066 * Searches all the hash tables in the index for the given URL and
1067 * then if found deletes the entry.
1070 * TRUE if the entry was found
1071 * FALSE if the entry could not be found
1074 static BOOL
URLCache_DeleteEntryFromHash(LPCURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
)
1076 struct _HASH_ENTRY
* pHashEntry
;
1077 if (URLCache_FindHash(pHeader
, lpszUrl
, &pHashEntry
))
1079 pHashEntry
->dwHashKey
= HASHTABLE_FREE
;
1080 pHashEntry
->dwOffsetEntry
= HASHTABLE_FREE
;
1086 /***********************************************************************
1087 * URLCache_AddEntryToHash (Internal)
1089 * Searches all the hash tables for a free slot based on the offset
1090 * generated from the hash key. If a free slot is found, the offset and
1091 * key are entered into the hash table.
1094 * TRUE if the entry was added
1095 * FALSE if the entry could not be added
1098 static BOOL
URLCache_AddEntryToHash(LPCURLCACHE_HEADER pHeader
, LPCSTR lpszUrl
, DWORD dwOffsetEntry
)
1100 /* see URLCache_FindEntryInHash for structure of hash tables */
1102 DWORD key
= URLCache_HashKey(lpszUrl
);
1103 DWORD offset
= (key
% HASHTABLE_NUM_ENTRIES
) * sizeof(struct _HASH_ENTRY
);
1104 HASH_CACHEFILE_ENTRY
* pHashEntry
;
1105 DWORD dwHashTableNumber
= 0;
1107 key
= (DWORD
)(key
/ HASHTABLE_NUM_ENTRIES
) * HASHTABLE_NUM_ENTRIES
;
1109 for (pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHeader
->dwOffsetFirstHashTable
);
1110 ((DWORD
)((LPBYTE
)pHashEntry
- (LPBYTE
)pHeader
) >= ENTRY_START_OFFSET
) && ((DWORD
)((LPBYTE
)pHashEntry
- (LPBYTE
)pHeader
) < pHeader
->dwFileSize
);
1111 pHashEntry
= URLCache_HashEntryFromOffset(pHeader
, pHashEntry
->dwAddressNext
))
1114 if (pHashEntry
->dwHashTableNumber
!= dwHashTableNumber
++)
1116 ERR("not right hash table number (%ld) expected %ld\n", pHashEntry
->dwHashTableNumber
, dwHashTableNumber
);
1119 /* make sure that it is in fact a hash entry */
1120 if (pHashEntry
->CacheFileEntry
.dwSignature
!= HASH_SIGNATURE
)
1122 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR
)&pHashEntry
->CacheFileEntry
.dwSignature
);
1126 for (i
= 0; i
< HASHTABLE_BLOCKSIZE
; i
++)
1128 struct _HASH_ENTRY
* pHashElement
= &pHashEntry
->HashTable
[offset
+ i
];
1129 if (pHashElement
->dwHashKey
== HASHTABLE_FREE
) /* if the slot is free */
1131 pHashElement
->dwHashKey
= key
;
1132 pHashElement
->dwOffsetEntry
= dwOffsetEntry
;
1137 FIXME("need to create another hash table\n");
1141 /***********************************************************************
1142 * GetUrlCacheEntryInfoExA (WININET.@)
1145 BOOL WINAPI
GetUrlCacheEntryInfoExA(
1147 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1148 LPDWORD lpdwCacheEntryInfoBufSize
,
1150 LPDWORD lpdwReserved
,
1154 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1155 debugstr_a(lpszUrl
),
1157 lpdwCacheEntryInfoBufSize
,
1163 if ((lpszReserved
!= NULL
) ||
1164 (lpdwReserved
!= NULL
) ||
1165 (lpReserved
!= NULL
))
1167 ERR("Reserved value was not 0\n");
1168 SetLastError(ERROR_INVALID_PARAMETER
);
1172 FIXME("Undocumented flag(s): %lx\n", dwFlags
);
1173 return GetUrlCacheEntryInfoA(lpszUrl
, lpCacheEntryInfo
, lpdwCacheEntryInfoBufSize
);
1176 /***********************************************************************
1177 * GetUrlCacheEntryInfoA (WININET.@)
1180 BOOL WINAPI
GetUrlCacheEntryInfoA(
1181 IN LPCSTR lpszUrlName
,
1182 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1183 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
1186 LPURLCACHE_HEADER pHeader
;
1187 CACHEFILE_ENTRY
* pEntry
;
1188 URL_CACHEFILE_ENTRY
* pUrlEntry
;
1189 URLCACHECONTAINER
* pContainer
;
1191 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
, lpdwCacheEntryInfoBufferSize
);
1193 if (!URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
))
1196 if (!URLCacheContainer_OpenIndex(pContainer
))
1199 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1202 if (!URLCache_FindEntryInHash(pHeader
, lpszUrlName
, &pEntry
))
1204 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1205 WARN("entry %s not found!\n", debugstr_a(lpszUrlName
));
1206 SetLastError(ERROR_FILE_NOT_FOUND
);
1210 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1212 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1213 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1214 SetLastError(ERROR_FILE_NOT_FOUND
);
1218 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
1219 TRACE("Found URL: %s\n", debugstr_a(pUrlEntry
->szSourceUrlName
));
1220 if (pUrlEntry
->dwOffsetHeaderInfo
)
1221 TRACE("Header info: %s\n", debugstr_a((LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
1223 if (!URLCache_CopyEntry(
1227 lpdwCacheEntryInfoBufferSize
,
1231 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1234 TRACE("Local File Name: %s\n", debugstr_a(lpCacheEntryInfo
->lpszLocalFileName
));
1236 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1241 /***********************************************************************
1242 * GetUrlCacheEntryInfoW (WININET.@)
1245 BOOL WINAPI
GetUrlCacheEntryInfoW(LPCWSTR lpszUrl
,
1246 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1247 LPDWORD lpdwCacheEntryInfoBufferSize
)
1249 LPURLCACHE_HEADER pHeader
;
1250 CACHEFILE_ENTRY
* pEntry
;
1251 URL_CACHEFILE_ENTRY
* pUrlEntry
;
1252 URLCACHECONTAINER
* pContainer
;
1256 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl
), lpCacheEntryInfo
, lpdwCacheEntryInfoBufferSize
);
1258 url_len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrl
, -1, NULL
, 0, NULL
, NULL
);
1259 lpszUrlA
= HeapAlloc(GetProcessHeap(), 0, url_len
* sizeof(CHAR
));
1262 SetLastError(ERROR_OUTOFMEMORY
);
1265 WideCharToMultiByte(CP_ACP
, 0, lpszUrl
, -1, lpszUrlA
, url_len
, NULL
, NULL
);
1267 if (!URLCacheContainers_FindContainerW(lpszUrl
, &pContainer
))
1269 HeapFree(GetProcessHeap(), 0, lpszUrlA
);
1273 if (!URLCacheContainer_OpenIndex(pContainer
))
1275 HeapFree(GetProcessHeap(), 0, lpszUrlA
);
1279 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1281 HeapFree(GetProcessHeap(), 0, lpszUrlA
);
1285 if (!URLCache_FindEntryInHash(pHeader
, lpszUrlA
, &pEntry
))
1287 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1288 HeapFree(GetProcessHeap(), 0, lpszUrlA
);
1289 WARN("entry %s not found!\n", debugstr_a(lpszUrlA
));
1290 SetLastError(ERROR_FILE_NOT_FOUND
);
1293 HeapFree(GetProcessHeap(), 0, lpszUrlA
);
1295 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1297 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1298 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1299 SetLastError(ERROR_FILE_NOT_FOUND
);
1303 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
1304 TRACE("Found URL: %s\n", debugstr_a(pUrlEntry
->szSourceUrlName
));
1305 TRACE("Header info: %s\n", debugstr_a((LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
));
1307 if (!URLCache_CopyEntry(
1310 (LPINTERNET_CACHE_ENTRY_INFOA
)lpCacheEntryInfo
,
1311 lpdwCacheEntryInfoBufferSize
,
1313 TRUE
/* UNICODE */))
1315 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1318 TRACE("Local File Name: %s\n", debugstr_w(lpCacheEntryInfo
->lpszLocalFileName
));
1320 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1325 /***********************************************************************
1326 * GetUrlCacheEntryInfoExW (WININET.@)
1329 BOOL WINAPI
GetUrlCacheEntryInfoExW(
1331 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
,
1332 LPDWORD lpdwCacheEntryInfoBufSize
,
1333 LPWSTR lpszReserved
,
1334 LPDWORD lpdwReserved
,
1338 TRACE("(%s, %p, %p, %p, %p, %p, %lx)\n",
1339 debugstr_w(lpszUrl
),
1341 lpdwCacheEntryInfoBufSize
,
1347 if ((lpszReserved
!= NULL
) ||
1348 (lpdwReserved
!= NULL
) ||
1349 (lpReserved
!= NULL
))
1351 ERR("Reserved value was not 0\n");
1352 SetLastError(ERROR_INVALID_PARAMETER
);
1356 FIXME("Undocumented flag(s): %lx\n", dwFlags
);
1357 return GetUrlCacheEntryInfoW(lpszUrl
, lpCacheEntryInfo
, lpdwCacheEntryInfoBufSize
);
1360 /***********************************************************************
1361 * SetUrlCacheEntryInfoA (WININET.@)
1363 BOOL WINAPI
SetUrlCacheEntryInfoA(
1365 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1366 DWORD dwFieldControl
)
1368 LPURLCACHE_HEADER pHeader
;
1369 CACHEFILE_ENTRY
* pEntry
;
1370 URLCACHECONTAINER
* pContainer
;
1372 TRACE("(%s, %p, 0x%08lx)\n", debugstr_a(lpszUrlName
), lpCacheEntryInfo
, dwFieldControl
);
1374 if (!URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
))
1377 if (!URLCacheContainer_OpenIndex(pContainer
))
1380 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1383 if (!URLCache_FindEntryInHash(pHeader
, lpszUrlName
, &pEntry
))
1385 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1386 WARN("entry %s not found!\n", debugstr_a(lpszUrlName
));
1387 SetLastError(ERROR_FILE_NOT_FOUND
);
1391 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1393 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1394 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1395 SetLastError(ERROR_FILE_NOT_FOUND
);
1399 URLCache_SetEntryInfo(
1400 (URL_CACHEFILE_ENTRY
*)pEntry
,
1401 (const INTERNET_CACHE_ENTRY_INFOW
*)lpCacheEntryInfo
,
1404 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1409 /***********************************************************************
1410 * SetUrlCacheEntryInfoW (WININET.@)
1412 BOOL WINAPI
SetUrlCacheEntryInfoW(LPCWSTR lpszUrl
, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo
, DWORD dwFieldControl
)
1414 LPURLCACHE_HEADER pHeader
;
1415 CACHEFILE_ENTRY
* pEntry
;
1416 URLCACHECONTAINER
* pContainer
;
1420 TRACE("(%s, %p, 0x%08lx)\n", debugstr_w(lpszUrl
), lpCacheEntryInfo
, dwFieldControl
);
1422 url_len
= WideCharToMultiByte(CP_ACP
, 0, lpszUrl
, -1, NULL
, 0, NULL
, NULL
);
1423 lpszUrlA
= HeapAlloc(GetProcessHeap(), 0, url_len
* sizeof(CHAR
));
1426 SetLastError(ERROR_OUTOFMEMORY
);
1429 WideCharToMultiByte(CP_ACP
, 0, lpszUrl
, -1, lpszUrlA
, url_len
, NULL
, NULL
);
1431 if (!URLCacheContainers_FindContainerW(lpszUrl
, &pContainer
))
1433 HeapFree(GetProcessHeap(), 0, lpszUrlA
);
1437 if (!URLCacheContainer_OpenIndex(pContainer
))
1439 HeapFree(GetProcessHeap(), 0, lpszUrlA
);
1443 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1445 HeapFree(GetProcessHeap(), 0, lpszUrlA
);
1449 if (!URLCache_FindEntryInHash(pHeader
, lpszUrlA
, &pEntry
))
1451 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1452 HeapFree(GetProcessHeap(), 0, lpszUrlA
);
1453 WARN("entry %s not found!\n", debugstr_a(lpszUrlA
));
1454 SetLastError(ERROR_FILE_NOT_FOUND
);
1457 HeapFree(GetProcessHeap(), 0, lpszUrlA
);
1459 if (pEntry
->dwSignature
!= URL_SIGNATURE
)
1461 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1462 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR
)&pEntry
->dwSignature
, sizeof(DWORD
)));
1463 SetLastError(ERROR_FILE_NOT_FOUND
);
1467 URLCache_SetEntryInfo(
1468 (URL_CACHEFILE_ENTRY
*)pEntry
,
1472 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1477 /***********************************************************************
1478 * RetrieveUrlCacheEntryFileA (WININET.@)
1481 BOOL WINAPI
RetrieveUrlCacheEntryFileA(
1482 IN LPCSTR lpszUrlName
,
1483 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1484 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
1488 LPURLCACHE_HEADER pHeader
;
1489 CACHEFILE_ENTRY
* pEntry
;
1490 URL_CACHEFILE_ENTRY
* pUrlEntry
;
1491 URLCACHECONTAINER
* pContainer
;
1493 TRACE("(%s, %p, %p, 0x%08lx)\n",
1494 debugstr_a(lpszUrlName
),
1496 lpdwCacheEntryInfoBufferSize
,
1499 if (!URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
))
1502 if (!URLCacheContainer_OpenIndex(pContainer
))
1505 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1508 if (!URLCache_FindEntryInHash(pHeader
, lpszUrlName
, &pEntry
))
1510 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1511 TRACE("entry %s not found!\n", lpszUrlName
);
1512 SetLastError(ERROR_FILE_NOT_FOUND
);
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
= (URL_CACHEFILE_ENTRY
*)pEntry
;
1525 TRACE("Found URL: %s\n", pUrlEntry
->szSourceUrlName
);
1526 TRACE("Header info: %s\n", (LPBYTE
)pUrlEntry
+ pUrlEntry
->dwOffsetHeaderInfo
);
1528 pUrlEntry
->dwHitRate
++;
1529 pUrlEntry
->dwUseCount
++;
1530 URLCache_HashEntrySetUse(pHeader
, lpszUrlName
, pUrlEntry
->dwUseCount
);
1532 if (!URLCache_CopyEntry(pContainer
, pHeader
, lpCacheEntryInfo
, lpdwCacheEntryInfoBufferSize
, pUrlEntry
, FALSE
))
1534 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1537 TRACE("Local File Name: %s\n", lpCacheEntryInfo
->lpszLocalFileName
);
1539 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1544 /***********************************************************************
1545 * UnlockUrlCacheEntryFileA (WININET.@)
1548 BOOL WINAPI
UnlockUrlCacheEntryFileA(
1549 IN LPCSTR lpszUrlName
,
1553 LPURLCACHE_HEADER pHeader
;
1554 CACHEFILE_ENTRY
* pEntry
;
1555 URL_CACHEFILE_ENTRY
* pUrlEntry
;
1556 URLCACHECONTAINER
* pContainer
;
1558 TRACE("(%s, 0x%08lx)\n", debugstr_a(lpszUrlName
), dwReserved
);
1562 ERR("dwReserved != 0\n");
1563 SetLastError(ERROR_INVALID_PARAMETER
);
1567 if (!URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
))
1570 if (!URLCacheContainer_OpenIndex(pContainer
))
1573 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1576 if (!URLCache_FindEntryInHash(pHeader
, lpszUrlName
, &pEntry
))
1578 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1579 TRACE("entry %s not found!\n", lpszUrlName
);
1580 SetLastError(ERROR_FILE_NOT_FOUND
);
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
= (URL_CACHEFILE_ENTRY
*)pEntry
;
1594 if (pUrlEntry
->dwUseCount
== 0)
1596 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1599 pUrlEntry
->dwUseCount
--;
1600 URLCache_HashEntrySetUse(pHeader
, lpszUrlName
, pUrlEntry
->dwUseCount
);
1602 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1607 /***********************************************************************
1608 * CreateUrlCacheEntryA (WININET.@)
1611 BOOL WINAPI
CreateUrlCacheEntryA(
1612 IN LPCSTR lpszUrlName
,
1613 IN DWORD dwExpectedFileSize
,
1614 IN LPCSTR lpszFileExtension
,
1615 OUT LPSTR lpszFileName
,
1619 URLCACHECONTAINER
* pContainer
;
1620 LPURLCACHE_HEADER pHeader
;
1621 CHAR szFile
[MAX_PATH
];
1622 CHAR szExtension
[MAX_PATH
];
1625 LPCSTR lpszFileNameExtension
;
1626 LPSTR lpszFileNameNoPath
;
1628 int countnoextension
;
1631 BOOL bFound
= FALSE
;
1634 TRACE("(%s, 0x%08lx, %s, %p, 0x%08lx)\n",
1635 debugstr_a(lpszUrlName
),
1637 debugstr_a(lpszFileExtension
),
1643 ERR("dwReserved != 0\n");
1644 SetLastError(ERROR_INVALID_PARAMETER
);
1648 for (lpszUrlEnd
= lpszUrlName
; *lpszUrlEnd
; lpszUrlEnd
++)
1651 if (((lpszUrlEnd
- lpszUrlName
) > 1) && (*(lpszUrlEnd
- 1) == '/'))
1654 for (lpszUrlPart
= lpszUrlEnd
;
1655 (lpszUrlPart
>= lpszUrlName
);
1658 if ((*lpszUrlPart
== '/') && ((lpszUrlEnd
- lpszUrlPart
) > 1))
1665 if (!strcmp(lpszUrlPart
, "www"))
1667 lpszUrlPart
+= strlen("www");
1670 count
= lpszUrlEnd
- lpszUrlPart
;
1672 if (bFound
&& (count
< MAX_PATH
))
1674 memcpy(szFile
, lpszUrlPart
, count
* sizeof(CHAR
));
1675 szFile
[count
] = '\0';
1676 /* FIXME: get rid of illegal characters like \, / and : */
1680 FIXME("need to generate a random filename");
1683 TRACE("File name: %s\n", szFile
);
1685 if (!URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
))
1688 if (!URLCacheContainer_OpenIndex(pContainer
))
1691 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1694 CacheDir
= (BYTE
)(rand() % pHeader
->DirectoryCount
);
1696 lBufferSize
= MAX_PATH
* sizeof(CHAR
);
1697 URLCache_LocalFileNameToPathA(pContainer
, pHeader
, szFile
, CacheDir
, lpszFileName
, &lBufferSize
);
1699 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1701 lpszFileNameNoPath
= lpszFileName
+ lBufferSize
/ sizeof(CHAR
) + DIR_LENGTH
+ 1;
1703 countnoextension
= strlen(lpszFileNameNoPath
);
1704 lpszFileNameExtension
= PathFindExtensionA(lpszFileNameNoPath
);
1705 if (lpszFileNameExtension
)
1706 countnoextension
-= strlen(lpszFileNameExtension
);
1707 *szExtension
= '\0';
1709 if (lpszFileExtension
)
1711 szExtension
[0] = '.';
1712 strcpy(szExtension
+1, lpszFileExtension
);
1715 for (i
= 0; i
< 255; i
++)
1718 strncpy(lpszFileNameNoPath
, szFile
, countnoextension
);
1719 sprintf(lpszFileNameNoPath
+ countnoextension
, "[%u]%s", i
, szExtension
);
1720 TRACE("Trying: %s\n", lpszFileName
);
1721 hFile
= CreateFileA(lpszFileName
, GENERIC_READ
, 0, NULL
, CREATE_NEW
, 0, NULL
);
1722 if (hFile
!= INVALID_HANDLE_VALUE
)
1732 /***********************************************************************
1733 * CommitUrlCacheEntryA (WININET.@)
1736 BOOL WINAPI
CommitUrlCacheEntryA(
1737 IN LPCSTR lpszUrlName
,
1738 IN LPCSTR lpszLocalFileName
,
1739 IN FILETIME ExpireTime
,
1740 IN FILETIME LastModifiedTime
,
1741 IN DWORD CacheEntryType
,
1742 IN LPBYTE lpHeaderInfo
,
1743 IN DWORD dwHeaderSize
,
1744 IN LPCSTR lpszFileExtension
,
1745 IN LPCSTR dwReserved
1748 URLCACHECONTAINER
* pContainer
;
1749 LPURLCACHE_HEADER pHeader
;
1750 CACHEFILE_ENTRY
* pEntry
;
1751 URL_CACHEFILE_ENTRY
* pUrlEntry
;
1752 DWORD dwBytesNeeded
= sizeof(*pUrlEntry
) - sizeof(pUrlEntry
->szSourceUrlName
);
1753 DWORD dwOffsetLocalFileName
= 0;
1754 DWORD dwOffsetHeader
= 0;
1755 DWORD dwFileSizeLow
= 0;
1756 DWORD dwFileSizeHigh
= 0;
1757 BYTE cDirectory
= 0;
1759 TRACE("(%s, %s, ..., ..., %lx, %p, %ld, %s, %p)\n",
1760 debugstr_a(lpszUrlName
),
1761 debugstr_a(lpszLocalFileName
),
1770 ERR("dwReserved != 0\n");
1771 SetLastError(ERROR_INVALID_PARAMETER
);
1774 if (lpHeaderInfo
== NULL
)
1776 FIXME("lpHeaderInfo == NULL - will crash at the moment\n");
1779 if (lpszLocalFileName
)
1782 hFile
= CreateFileA(lpszLocalFileName
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
1783 if (hFile
== INVALID_HANDLE_VALUE
)
1785 ERR("couldn't open file %s (error is %ld)\n", debugstr_a(lpszLocalFileName
), GetLastError());
1790 dwFileSizeLow
= GetFileSize(hFile
, &dwFileSizeHigh
);
1791 if ((dwFileSizeLow
== -1) && (GetLastError() != NO_ERROR
))
1793 ERR("couldn't get file size (error is %ld)\n", GetLastError());
1801 if (!URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
))
1804 if (!URLCacheContainer_OpenIndex(pContainer
))
1807 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
1810 if (URLCache_FindEntryInHash(pHeader
, lpszUrlName
, &pEntry
))
1812 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1813 FIXME("entry already in cache - don't know what to do!\n");
1815 * SetLastError(ERROR_FILE_NOT_FOUND);
1821 if (lpszLocalFileName
)
1823 BOOL bFound
= FALSE
;
1824 char szContainerPath
[MAX_PATH
];
1825 int container_path_len
;
1826 container_path_len
= WideCharToMultiByte(CP_ACP
, 0, pContainer
->path
, -1, szContainerPath
, sizeof(szContainerPath
), NULL
, NULL
);
1827 if (!container_path_len
)
1829 /* WideCharToMultiByte should have called SetLastError */
1833 if (strncmp(lpszLocalFileName
, szContainerPath
, container_path_len
))
1835 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1836 ERR("path %s must begin with cache content path %s\n", debugstr_a(lpszLocalFileName
), debugstr_a(szContainerPath
));
1837 SetLastError(ERROR_INVALID_PARAMETER
);
1841 /* skip container path prefix */
1842 lpszLocalFileName
+= container_path_len
;
1844 for (cDirectory
= 0; cDirectory
< pHeader
->DirectoryCount
; cDirectory
++)
1846 if (!strncmp(pHeader
->directory_data
[cDirectory
].filename
, lpszLocalFileName
, DIR_LENGTH
))
1855 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1856 ERR("cache directory not found in path %s\n", lpszLocalFileName
);
1857 SetLastError(ERROR_INVALID_PARAMETER
);
1861 lpszLocalFileName
+= (DIR_LENGTH
+ 1); /* "1234WXYZ\" */
1864 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(lpszUrlName
) + 1);
1865 if (lpszLocalFileName
)
1867 dwOffsetLocalFileName
= dwBytesNeeded
;
1868 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ strlen(lpszLocalFileName
) + 1);
1872 dwOffsetHeader
= dwBytesNeeded
;
1873 dwBytesNeeded
= DWORD_ALIGN(dwBytesNeeded
+ dwHeaderSize
);
1876 /* round up to next block */
1877 if (dwBytesNeeded
% BLOCKSIZE
)
1879 dwBytesNeeded
-= dwBytesNeeded
% BLOCKSIZE
;
1880 dwBytesNeeded
+= BLOCKSIZE
;
1883 if (!URLCache_FindFirstFreeEntry(pHeader
, dwBytesNeeded
/ BLOCKSIZE
, &pEntry
))
1885 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1886 ERR("no free entries\n");
1890 /* FindFirstFreeEntry fills in blocks used */
1891 pUrlEntry
= (URL_CACHEFILE_ENTRY
*)pEntry
;
1892 pUrlEntry
->CacheFileEntry
.dwSignature
= URL_SIGNATURE
;
1893 pUrlEntry
->CacheDir
= cDirectory
;
1894 pUrlEntry
->CacheEntryType
= CacheEntryType
;
1895 pUrlEntry
->dwHeaderInfoSize
= dwHeaderSize
;
1896 pUrlEntry
->dwExemptDelta
= 0;
1897 pUrlEntry
->dwHitRate
= 0;
1898 pUrlEntry
->dwOffsetHeaderInfo
= dwOffsetHeader
;
1899 pUrlEntry
->dwOffsetLocalName
= dwOffsetLocalFileName
;
1900 pUrlEntry
->dwOffsetUrl
= sizeof(*pUrlEntry
) - sizeof(pUrlEntry
->szSourceUrlName
);
1901 pUrlEntry
->dwSizeHigh
= 0;
1902 pUrlEntry
->dwSizeLow
= dwFileSizeLow
;
1903 pUrlEntry
->dwSizeHigh
= dwFileSizeHigh
;
1904 pUrlEntry
->dwUseCount
= 0;
1905 GetSystemTimeAsFileTime(&pUrlEntry
->LastAccessTime
);
1906 pUrlEntry
->LastModifiedTime
= LastModifiedTime
;
1907 FileTimeToDosDateTime(&pUrlEntry
->LastAccessTime
, &pUrlEntry
->wLastSyncDate
, &pUrlEntry
->wLastSyncTime
);
1908 FileTimeToDosDateTime(&ExpireTime
, &pUrlEntry
->wExpiredDate
, &pUrlEntry
->wExpiredTime
);
1909 pUrlEntry
->wUnknownDate
= pUrlEntry
->wLastSyncDate
;
1910 pUrlEntry
->wUnknownTime
= pUrlEntry
->wLastSyncTime
;
1913 pUrlEntry
->dwUnknown1
= 0;
1914 pUrlEntry
->dwUnknown2
= 0;
1915 pUrlEntry
->dwUnknown3
= 0x60;
1916 pUrlEntry
->Unknown4
= 0;
1917 pUrlEntry
->wUnknown5
= 0x1010;
1918 pUrlEntry
->dwUnknown6
= 0;
1919 pUrlEntry
->dwUnknown7
= 0;
1920 pUrlEntry
->dwUnknown8
= 0;
1922 strcpy(pUrlEntry
->szSourceUrlName
, lpszUrlName
);
1923 if (dwOffsetLocalFileName
)
1924 strcpy((LPSTR
)((LPBYTE
)pUrlEntry
+ dwOffsetLocalFileName
), lpszLocalFileName
);
1926 memcpy((LPSTR
)((LPBYTE
)pUrlEntry
+ dwOffsetHeader
), lpHeaderInfo
, dwHeaderSize
);
1928 if (!URLCache_AddEntryToHash(pHeader
, lpszUrlName
, (DWORD
)((LPBYTE
)pUrlEntry
- (LPBYTE
)pHeader
)))
1930 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1934 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
1939 BOOL WINAPI
ReadUrlCacheEntryStream(
1940 IN HANDLE hUrlCacheStream
,
1941 IN DWORD dwLocation
,
1942 IN OUT LPVOID lpBuffer
,
1943 IN OUT LPDWORD lpdwLen
,
1947 /* Get handle to file from 'stream' */
1948 STREAM_HANDLE
* pStream
= (STREAM_HANDLE
*)hUrlCacheStream
;
1950 if (dwReserved
!= 0)
1952 ERR("dwReserved != 0\n");
1953 SetLastError(ERROR_INVALID_PARAMETER
);
1957 if (IsBadReadPtr(pStream
, sizeof(*pStream
)) || IsBadStringPtrA(pStream
->lpszUrl
, INTERNET_MAX_URL_LENGTH
))
1959 SetLastError(ERROR_INVALID_HANDLE
);
1963 if (SetFilePointer(pStream
->hFile
, dwLocation
, NULL
, FILE_CURRENT
) == -1)
1965 return ReadFile(pStream
->hFile
, lpBuffer
, *lpdwLen
, lpdwLen
, NULL
);
1968 /***********************************************************************
1969 * RetrieveUrlCacheEntryStreamA (WININET.@)
1972 HANDLE WINAPI
RetrieveUrlCacheEntryStreamA(
1973 IN LPCSTR lpszUrlName
,
1974 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo
,
1975 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize
,
1976 IN BOOL fRandomRead
,
1980 /* NOTE: this is not the same as the way that the native
1981 * version allocates 'stream' handles. I did it this way
1982 * as it is much easier and no applications should depend
1983 * on this behaviour. (Native version appears to allocate
1984 * indices into a table)
1986 STREAM_HANDLE
* pStream
;
1989 if (!RetrieveUrlCacheEntryFileA(lpszUrlName
,
1991 lpdwCacheEntryInfoBufferSize
,
1997 hFile
= CreateFileA(lpCacheEntryInfo
->lpszLocalFileName
,
2002 fRandomRead
? FILE_FLAG_RANDOM_ACCESS
: 0,
2004 if (hFile
== INVALID_HANDLE_VALUE
)
2007 /* allocate handle storage space */
2008 pStream
= (STREAM_HANDLE
*)HeapAlloc(GetProcessHeap(), 0, sizeof(STREAM_HANDLE
) + strlen(lpszUrlName
) * sizeof(CHAR
));
2012 SetLastError(ERROR_OUTOFMEMORY
);
2016 pStream
->hFile
= hFile
;
2017 strcpy(pStream
->lpszUrl
, lpszUrlName
);
2018 return (HANDLE
)pStream
;
2021 /***********************************************************************
2022 * UnlockUrlCacheEntryStream (WININET.@)
2025 BOOL WINAPI
UnlockUrlCacheEntryStream(
2026 IN HANDLE hUrlCacheStream
,
2030 STREAM_HANDLE
* pStream
= (STREAM_HANDLE
*)hUrlCacheStream
;
2032 if (dwReserved
!= 0)
2034 ERR("dwReserved != 0\n");
2035 SetLastError(ERROR_INVALID_PARAMETER
);
2039 if (IsBadReadPtr(pStream
, sizeof(*pStream
)) || IsBadStringPtrA(pStream
->lpszUrl
, INTERNET_MAX_URL_LENGTH
))
2041 SetLastError(ERROR_INVALID_HANDLE
);
2045 if (!UnlockUrlCacheEntryFileA(pStream
->lpszUrl
, 0))
2048 /* close file handle */
2049 CloseHandle(pStream
->hFile
);
2051 /* free allocated space */
2052 HeapFree(GetProcessHeap(), 0, pStream
);
2058 /***********************************************************************
2059 * DeleteUrlCacheEntryA (WININET.@)
2062 BOOL WINAPI
DeleteUrlCacheEntryA(LPCSTR lpszUrlName
)
2064 URLCACHECONTAINER
* pContainer
;
2065 LPURLCACHE_HEADER pHeader
;
2066 CACHEFILE_ENTRY
* pEntry
;
2069 BYTE
* AllocationTable
;
2071 TRACE("(%s)\n", debugstr_a(lpszUrlName
));
2073 if (!URLCacheContainers_FindContainerA(lpszUrlName
, &pContainer
))
2076 if (!URLCacheContainer_OpenIndex(pContainer
))
2079 if (!(pHeader
= URLCacheContainer_LockIndex(pContainer
)))
2082 if (!URLCache_FindEntryInHash(pHeader
, lpszUrlName
, &pEntry
))
2084 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2085 TRACE("entry %s not found!\n", lpszUrlName
);
2086 SetLastError(ERROR_FILE_NOT_FOUND
);
2090 AllocationTable
= (LPBYTE
)pHeader
+ ALLOCATION_TABLE_OFFSET
;
2092 /* update allocation table */
2093 dwStartBlock
= ((DWORD
)pEntry
- (DWORD
)pHeader
) / BLOCKSIZE
;
2094 for (dwBlock
= dwStartBlock
; dwBlock
< dwStartBlock
+ pEntry
->dwBlocksUsed
; dwBlock
++)
2095 URLCache_Allocation_BlockFree(AllocationTable
, dwBlock
);
2097 URLCache_DeleteEntry(pEntry
);
2099 URLCache_DeleteEntryFromHash(pHeader
, lpszUrlName
);
2101 URLCacheContainer_UnlockIndex(pContainer
, pHeader
);
2106 /***********************************************************************
2107 * FindFirstUrlCacheEntryA (WININET.@)
2110 INTERNETAPI HANDLE WINAPI
FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern
,
2111 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo
, LPDWORD lpdwFirstCacheEntryInfoBufferSize
)
2113 FIXME("(%s, %p, %p): stub\n", debugstr_a(lpszUrlSearchPattern
), lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
);
2114 SetLastError(ERROR_FILE_NOT_FOUND
);
2118 /***********************************************************************
2119 * FindFirstUrlCacheEntryW (WININET.@)
2122 INTERNETAPI HANDLE WINAPI
FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern
,
2123 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo
, LPDWORD lpdwFirstCacheEntryInfoBufferSize
)
2125 FIXME("(%s, %p, %p): stub\n", debugstr_w(lpszUrlSearchPattern
), lpFirstCacheEntryInfo
, lpdwFirstCacheEntryInfoBufferSize
);
2129 /***********************************************************************
2130 * CreateUrlCacheGroup (WININET.@)
2133 INTERNETAPI GROUPID WINAPI
CreateUrlCacheGroup(DWORD dwFlags
, LPVOID
2136 FIXME("(%lx, %p): stub\n", dwFlags
, lpReserved
);
2140 /***********************************************************************
2141 * DeleteUrlCacheGroup (WININET.@)
2144 BOOL WINAPI
DeleteUrlCacheGroup(GROUPID GroupId
, DWORD dwFlags
, LPVOID lpReserved
)
2150 /***********************************************************************
2151 * SetUrlCacheEntryGroup (WININET.@)
2154 BOOL WINAPI
SetUrlCacheEntryGroup(LPCSTR lpszUrlName
, DWORD dwFlags
,
2155 GROUPID GroupId
, LPBYTE pbGroupAttributes
, DWORD cbGroupAttributes
,
2159 SetLastError(ERROR_FILE_NOT_FOUND
);
2163 /***********************************************************************
2164 * GetUrlCacheConfigInfoW (WININET.@)
2166 BOOL WINAPI
GetUrlCacheConfigInfoW(LPDWORD CacheInfo
, LPDWORD size
, DWORD bitmask
)
2168 FIXME("(%p, %p, %lx)\n", CacheInfo
, size
, bitmask
);
2169 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
2173 /***********************************************************************
2174 * GetUrlCacheConfigInfoA (WININET.@)
2176 * CacheInfo is some CACHE_CONFIG_INFO structure, with no MS info found by google
2178 BOOL WINAPI
GetUrlCacheConfigInfoA(LPDWORD CacheInfo
, LPDWORD size
, DWORD bitmask
)
2180 FIXME("(%p, %p, %lx)\n", CacheInfo
, size
, bitmask
);
2181 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);