3#define NONAMELESSSTRUCT
30#define NONAMELESSUNION
31#define NONAMELESSSTRUCT
62#define CHAR_BIT (8 * sizeof(CHAR))
65#define ENTRY_START_OFFSET 0x4000
67#define MAX_DIR_NO 0x20
69#define HASHTABLE_SIZE 448
70#define HASHTABLE_NUM_ENTRIES 64
71#define HASHTABLE_BLOCKSIZE (HASHTABLE_SIZE / HASHTABLE_NUM_ENTRIES)
72#define ALLOCATION_TABLE_OFFSET 0x250
73#define ALLOCATION_TABLE_SIZE (ENTRY_START_OFFSET - ALLOCATION_TABLE_OFFSET)
74#define MIN_BLOCK_NO 0x80
75#define MAX_BLOCK_NO (ALLOCATION_TABLE_SIZE * CHAR_BIT)
76#define FILE_SIZE(blocks) ((blocks) * BLOCKSIZE + ENTRY_START_OFFSET)
78#define HASHTABLE_URL 0
79#define HASHTABLE_DEL 1
80#define HASHTABLE_LOCK 2
81#define HASHTABLE_FREE 3
82#define HASHTABLE_REDR 5
83#define HASHTABLE_FLAG_BITS 6
85#define PENDING_DELETE_CACHE_ENTRY 0x00400000
86#define INSTALLED_CACHE_ENTRY 0x10000000
87#define GET_INSTALLED_ENTRY 0x200
88#define CACHE_CONTAINER_NO_SUBDIR 0xFE
90#define CACHE_HEADER_DATA_ROOT_LEAK_OFFSET 0x16
92#define FILETIME_SECOND 10000000
94#define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
95#define URL_SIGNATURE DWORD_SIG('U','R','L',' ')
96#define REDR_SIGNATURE DWORD_SIG('R','E','D','R')
97#define LEAK_SIGNATURE DWORD_SIG('L','E','A','K')
98#define HASH_SIGNATURE DWORD_SIG('H','A','S','H')
100#define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )
102#define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD
240 return (allocation_table[block_number/
CHAR_BIT] &
mask) == 0;
313 (*entry)->blocks_used = blocks_needed;
315 header->blocks_in_use += blocks_needed;
373 (*hash_table)->
next = 0;
374 (*hash_table)->id = hash_table_prev ? hash_table_prev->
id+1 : 0;
395 for (; *lpszPath; lpszPath++)
397 if (*lpszPath ==
'\\')
453 header->capacity_in_blocks = blocks_no;
467 header->capacity_in_blocks = blocks_no;
469 header->cache_limit.QuadPart = 0x07ff5400;
475 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content", &
key) ==
ERROR_SUCCESS) {
488 dir_name = dir_path +
lstrlenW(dir_path);
494 header->directory_data[
i].files_no = 0;
508 for(
k = 0;
k < 8; ++
k) {
517 dir_name[
k] =
'0' +
r;
519 dir_name[
k] =
'A' + (
r - 10);
528 for (
k = 0;
k < 8; ++
k)
529 header->directory_data[
i].name[
k] = dir_name[
k];
569 for(
i=0;
i<
header->capacity_in_blocks/8;
i++) {
570 for(count_bits =
header->allocation_table[
i]; count_bits!=0; count_bits>>=1) {
579 if(
header->allocation_table[
i])
620 TRACE(
"Could not open or create cache index file \"%s\"\n",
debugstr_w(index_path));
651 WARN(
"detected old or broken index.dat file\n");
692 int cache_prefix_len =
strlen(cache_prefix);
704 if (!pContainer->
path)
753 const WCHAR *shpath_suffix;
754 const char *cache_prefix;
755 DWORD default_entry_type;
756 } DefaultContainerData[] =
767 ERR(
"Environment variable 'USERPROFILE' does not exist!\n");
780 ERR(
"Couldn't get path for default container %u\n",
i);
784 suffix_len =
lstrlenW(DefaultContainerData[
i].shpath_suffix);
788 ERR(
"Path too long\n");
795 lstrcpyW(wszMutexName, wszCachePath);
799 memcpy(wszCachePath +
path_len + 1, DefaultContainerData[
i].shpath_suffix, (suffix_len + 1) *
sizeof(
WCHAR));
800 wszCachePath[
path_len + suffix_len + 1] =
'\\';
801 wszCachePath[
path_len + suffix_len + 2] =
'\0';
805 NULL, 0,
NULL, &def_char) || def_char)
812 NULL, 0,
NULL, &def_char) || def_char)
813 ERR(
"Can't create container path accessible by ANSI functions\n");
819 DefaultContainerData[
i].default_entry_type, wszMutexName);
861 ERR(
"no container found\n");
873 if (search_pattern &&
index > 0)
1015 if (trunc_name && nRequired >= *lpBufferSize)
1016 nRequired = *lpBufferSize;
1017 if (nRequired <= *lpBufferSize)
1025 wszPath[dir_len +
path_len] =
'\\';
1034 wszPath[*lpBufferSize/
sizeof(
WCHAR)-1] = 0;
1035 *lpBufferSize = nRequired;
1038 *lpBufferSize = nRequired;
1063 int path_len, file_name_len, dir_len;
1072 file_name_len =
strlen(szLocalFileName) + 1 ;
1078 nRequired = (
path_len + dir_len + file_name_len) *
sizeof(
char);
1079 if (nRequired <= *lpBufferSize)
1087 *lpBufferSize = nRequired;
1090 *lpBufferSize = nRequired;
1101 *fatdate = *fattime = 0;
1147 header->exempt_usage.QuadPart = 0;
1154 header->cache_usage.QuadPart = 0;
1204 WARN(
"index file has maximal size\n");
1227 if (!fatdate && !fattime)
1239 memset(&uc, 0,
sizeof(uc));
1266 decoded_url ? decoded_url+
len :
NULL, decoded_len);
1274 decoded_len -= part_len;
1278 -1, decoded_url ? decoded_url+
len :
NULL, decoded_len);
1302 if(*info_size >=
size) {
1327 if(*info_size >=
size) {
1328 DWORD url_size = url_len * (unicode ?
sizeof(
WCHAR) :
sizeof(
CHAR));
1342 LONG file_name_size;
1345 file_name_size = *info_size-
size;
1352 size += file_name_size;
1367 size += header_len * (unicode ?
sizeof(
WCHAR) :
sizeof(
CHAR));
1369 if(*info_size >=
size) {
1370 DWORD header_size = header_len * (unicode ?
sizeof(
WCHAR) :
sizeof(
CHAR));
1392 if(*info_size >=
size) {
1406 if(
size > *info_size) {
1436 FIXME(
"CACHE_ENTRY_HEADERINFO_FC unimplemented\n");
1461 static const unsigned char lookupTable[256] =
1463 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77,
1464 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33,
1465 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44,
1466 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41,
1467 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF,
1468 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C,
1469 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E,
1470 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90,
1471 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53,
1472 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE,
1473 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58,
1474 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD,
1475 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
1476 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D,
1477 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63,
1478 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD,
1479 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A,
1480 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2,
1481 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B,
1482 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B,
1483 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C,
1484 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70,
1485 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20,
1486 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B,
1487 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88,
1488 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
1489 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72,
1490 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D,
1491 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34,
1492 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8,
1493 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A,
1494 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1
1500 key[
i] = lookupTable[(*lpszKey +
i) & 0xFF];
1502 for (lpszKey++; *lpszKey; lpszKey++)
1505 key[
i] = lookupTable[*lpszKey ^
key[
i]];
1543 if (pHashEntry->
id !=
id++)
1545 ERR(
"Error: not right hash table number (%d) expected %d\n", pHashEntry->
id,
id);
1566 *ppHashEntry = pHashElement;
1633 pHashPrev = pHashEntry;
1635 if (pHashEntry->
id !=
id++)
1637 ERR(
"not right hash table number (%d) expected %d\n", pHashEntry->
id,
id);
1653 pHashElement->
offset = dwOffsetEntry;
1682 TRACE(
"looking at hash table number %d\n", (*ppHashEntry)->id);
1683 if ((*ppHashEntry)->id != *
id)
1688 ERR(
"Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (
LPCSTR)&(*ppHashEntry)->header.signature);
1693 TRACE(
"hash table number %d found\n", *
id);
1804 FIXME(
"ignoring unsupported flags: %x\n",
flags);
1830 FIXME(
"Trying to retrieve entry of unknown format %s\n",
1875 ERR(
"Reserved value was not 0\n");
1890 LPDWORD lpdwCacheEntryInfoBufferSize)
1904 memset(&uc, 0,
sizeof(uc));
1914 encoded_url, encoded_len,
NULL,
NULL);
1942 encoded_len -= part_len;
1991 ERR(
"Reserved value was not 0\n");
1997 dwFlags &= ~GET_INSTALLED_ENTRY;
2014 LPDWORD lpdwCacheEntryInfoBufferSize)
2025 DWORD dwFieldControl)
2033 TRACE(
"(%s, %p, 0x%08x)\n",
debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl);
2081 DWORD dwFieldControl)
2133 FIXME(
"Trying to retrieve entry of unknown format %s\n",
2151 size, url_entry, unicode);
2178 lpdwCacheEntryInfoBufferSize,
FALSE);
2196 lpdwCacheEntryInfoBufferSize,
TRUE);
2210 FIXME(
"Trying to delete entry of unknown format %s\n",
2219 TRACE(
"Trying to delete locked entry\n");
2267 if(!*hash_table_off) {
2268 *hash_table_off =
header->hash_table_off;
2269 *hash_table_entry = 0;
2273 if(*hash_table_off >=
header->size) {
2274 *hash_table_off = 0;
2282 *hash_table_off = 0;
2288 *hash_table_off = hashtable_entry->
next;
2289 if(!*hash_table_off) {
2290 *hash_table_off = 0;
2295 *hash_table_entry = 0;
2302 (*hash_table_entry)++;
2306 (*hash_table_entry)++;
2309 *hash_table_off = 0;
2341 rating = 400*60*60*24/(60*60*24+
time.QuadPart);
2353 return *(
const DWORD*)p1 - *(
const DWORD*)p2;
2427 DWORD delete_factor, hash_table_off, hash_table_entry;
2446 desired_size =
header->cache_limit.QuadPart*(100-
size)/100;
2447 cur_size =
header->cache_usage.QuadPart+
header->exempt_usage.QuadPart;
2448 if(cur_size <= desired_size)
2451 delete_factor = (cur_size-desired_size)*100/cur_size;
2453 if(!delete_factor) {
2459 hash_table_entry = 0;
2465 WARN(
"only url entries are currently supported\n");
2474 if(
rate[rate_no] != -1)
2479 TRACE(
"nothing to delete\n");
2486 delete_factor = delete_factor*rate_no/100;
2487 delete_factor =
rate[delete_factor];
2488 TRACE(
"deleting files with rating %d or less\n", delete_factor);
2503 if(
header->cache_usage.QuadPart+
header->exempt_usage.QuadPart <= desired_size)
2509 TRACE(
"got dll_unload_event - finishing\n");
2517 TRACE(
"cache size after cleaning 0x%s/0x%s\n",
2558 ERR(
"dwReserved != 0\n");
2641 LONG full_path_len, ext_len = 0;
2651 memset(&uc, 0,
sizeof(uc));
2690 generate_name =
TRUE;
2714 WARN(
"Failed to get full path for filename %s, needed %u bytes.\n",
2719 full_path_len = full_path_len/
sizeof(
WCHAR) - 1;
2729 for(
p=extW; *
p;
p++) {
2739 if(
p[-1]==
' ' ||
p[-1]==
'.')
2745 if(!generate_name && full_path_len+5+ext_len>=
MAX_PATH) {
2746 full_path_len =
MAX_PATH-5-ext_len-1;
2749 for(
i=0;
i<255 && !generate_name;
i++) {
2750 wsprintfW(full_path+full_path_len,
L"[%u]%s",
i, extW);
2760 if(full_path_len+8+ext_len >=
MAX_PATH)
2761 full_path_len =
MAX_PATH-8-ext_len-1;
2765 lstrcpyW(full_path+full_path_len+8, extW);
2767 for(
i=0;
i<255;
i++) {
2774 for(
j=0;
j<8;
j++) {
2777 full_path[full_path_len+
j] = (
r < 10 ?
'0' +
r :
'A' +
r - 10);
2788 WARN(
"Could not find a unique filename\n");
2824 if(lpszFileExtension) {
2843 BYTE *header_info,
DWORD header_size,
const char *file_ext,
2844 const char *original_url)
2851 DWORD url_entry_offset;
2853 DWORD file_name_off = 0;
2854 DWORD header_info_off = 0;
2855 DWORD file_ext_off = 0;
2859 char file_name_no_container[
MAX_PATH];
2860 char *local_file_name = 0;
2862 DWORD exempt_delta = 0;
2865 TRACE(
"(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n",
debugstr_a(
url),
debugstr_w(
file_name),
2873 WARN(
": original_url ignored\n");
2875 memset(&file_attr, 0,
sizeof(file_attr));
2902 TRACE(
"Trying to overwrite locked entry\n");
2932 local_file_name = file_name_no_container;
2935 for(dir_id = 0; dir_id <
header->dirs_no; dir_id++) {
2956 file_name_off =
size;
2959 if(header_info && header_size) {
2960 header_info_off =
size;
2963 if(file_ext && (file_ext_off =
strlen(file_ext))) {
2966 file_ext_off =
size;
2997 exempt_delta = 86400;
3014 url_entry->
unk1 = 0;
3015 url_entry->
unk2 = 0;
3016 url_entry->
unk3 = 0x60;
3017 url_entry->
unk4 = 0;
3018 url_entry->
unk5 = 0x1010;
3019 url_entry->
unk7 = 0;
3020 url_entry->
unk8 = 0;
3027 memcpy((
LPBYTE)url_entry + header_info_off, header_info, header_size);
3053 if(
header->cache_usage.QuadPart+
header->exempt_usage.QuadPart >
header->cache_limit.QuadPart)
3070 if(lpszLocalFileName) {
3077 CacheEntryType, lpHeaderInfo, dwHeaderSize, lpszFileExtension, lpszOriginalUrl);
3101 dwHeaderSize =
strlen(header_info);
3104 if(lpszFileExtension) {
3121 CacheEntryType, (
BYTE*)header_info, dwHeaderSize, file_ext, original_url);
3146 ERR(
"dwReserved != 0\n");
3179 TRACE(
"(%s, %p, %p, %x, 0x%08x)\n",
debugstr_a(lpszUrlName), lpCacheEntryInfo,
3180 lpdwCacheEntryInfoBufferSize, fRandomRead,
dwReserved);
3225 TRACE(
"(%s, %p, %p, %x, 0x%08x)\n",
debugstr_w(lpszUrlName), lpCacheEntryInfo,
3226 lpdwCacheEntryInfoBufferSize, fRandomRead,
dwReserved);
3274 ERR(
"dwReserved != 0\n");
3359 FIXME(
"(0x%08x, 0x%08x) stub\n", d1, d2);
3365 FIXME(
"(0x%08x, 0x%08x) stub\n", d1, d2);
3375 FIXME(
"(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3376 d1, d2, d3, d4, d5, d6, d7, d8);
3386 FIXME(
"(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n",
3387 d1, d2, d3, d4, d5, d6, d7, d8);
3396 FIXME(
"(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3405 FIXME(
"(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 );
3428 LPCSTR lpszUrlSearchPattern,
3433 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3439 FIXME(
"(%s, 0x%08x, 0x%08x, 0x%s, %p, %p, %p, %p, %p) stub\n",
debugstr_a(lpszUrlSearchPattern),
3441 lpdwFirstCacheEntryInfoBufferSize,
lpReserved, pcbReserved2,lpReserved3);
3452 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3458 FIXME(
"(%s, 0x%08x, 0x%08x, 0x%s, %p, %p, %p, %p, %p) stub\n",
debugstr_w(lpszUrlSearchPattern),
3460 lpdwFirstCacheEntryInfoBufferSize,
lpReserved, pcbReserved2,lpReserved3);
3474 TRACE(
"(%s, %p, %p)\n",
debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3476 pEntryHandle =
heap_alloc(
sizeof(*pEntryHandle));
3481 if (lpszUrlSearchPattern)
3501 return pEntryHandle;
3513 TRACE(
"(%s, %p, %p)\n",
debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize);
3515 pEntryHandle =
heap_alloc(
sizeof(*pEntryHandle));
3520 if (lpszUrlSearchPattern)
3540 return pEntryHandle;
3546 LPDWORD lpdwNextCacheEntryInfoBufferSize,
3589 TRACE(
"Found URL: %s\n",
3591 TRACE(
"Header info: %s\n",
3598 lpNextCacheEntryInfo,
3599 lpdwNextCacheEntryInfoBufferSize,
3632 LPDWORD lpdwNextCacheEntryInfoBufferSize)
3634 TRACE(
"(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3637 lpdwNextCacheEntryInfoBufferSize,
FALSE );
3646 LPDWORD lpdwNextCacheEntryInfoBufferSize
3649 TRACE(
"(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize);
3653 lpdwNextCacheEntryInfoBufferSize,
TRUE );
3663 TRACE(
"(%p)\n", hEnumHandle);
3671 pEntryHandle->
magic = 0;
3680 FIXME(
"(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n",
dwFlags, dwFilter, lpSearchCondition,
3688 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3694 FIXME(
"(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3702 LPDWORD lpdwFirstCacheEntryInfoBufferSize,
3708 FIXME(
"(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize,
3735 FIXME(
"(0x%s, 0x%08x, %p) stub\n",
3758 FIXME(
"(%s, 0x%08x, 0x%s, %p, 0x%08x, %p) stub\n",
3760 pbGroupAttributes, cbGroupAttributes,
lpReserved);
3773 FIXME(
"(%s, 0x%08x, 0x%s, %p, 0x%08x, %p) stub\n",
3775 pbGroupAttributes, cbGroupAttributes,
lpReserved);
3836 info->dwContainer = 0;
3838 info->dwReserved4 = 0;
3840 info->dwSyncMode = 0;
3841 info->dwNumCachePaths = 1;
3842 info->dwNormalUsage = 0;
3843 info->dwExemptUsage = 0;
3878 info->dwNumCachePaths =
infoW.dwNumCachePaths;
3879 info->dwNormalUsage =
infoW.dwNormalUsage;
3880 info->dwExemptUsage =
infoW.dwExemptUsage;
3881 info->u.s.dwCacheSize =
infoW.u.s.dwCacheSize;
3891 FIXME(
"(0x%s, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3901 FIXME(
"(0x%s, 0x%08x, 0x%08x, %p, %p, %p) stub\n",
3910 FIXME(
"(0x%s, 0x%08x, 0x%08x, %p, %p) stub\n",
3918 FIXME(
"(0x%s, 0x%08x, 0x%08x, %p, %p) stub\n",
3925 FIXME(
"(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);
3931 FIXME(
"(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl);