Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenurlcache.c
Go to the documentation of this file.
00001 /* 00002 * Wininet - Url Cache functions 00003 * 00004 * Copyright 2001,2002 CodeWeavers 00005 * Copyright 2003-2008 Robert Shearman 00006 * 00007 * Eric Kohl 00008 * Aric Stewart 00009 * 00010 * This library is free software; you can redistribute it and/or 00011 * modify it under the terms of the GNU Lesser General Public 00012 * License as published by the Free Software Foundation; either 00013 * version 2.1 of the License, or (at your option) any later version. 00014 * 00015 * This library is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 * Lesser General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU Lesser General Public 00021 * License along with this library; if not, write to the Free Software 00022 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00023 */ 00024 00025 #include "config.h" 00026 #include "wine/port.h" 00027 00028 #define NONAMELESSUNION 00029 #define NONAMELESSSTRUCT 00030 00031 #if defined(__MINGW32__) || defined (_MSC_VER) 00032 #include <ws2tcpip.h> 00033 #endif 00034 00035 #include <stdarg.h> 00036 #include <stdio.h> 00037 #include <stdlib.h> 00038 #include <string.h> 00039 #include <sys/types.h> 00040 #ifdef HAVE_SYS_SOCKET_H 00041 # include <sys/socket.h> 00042 #endif 00043 #include <time.h> 00044 00045 #include "windef.h" 00046 #include "winbase.h" 00047 #include "winuser.h" 00048 #include "wininet.h" 00049 #include "winineti.h" 00050 #include "winerror.h" 00051 #include "winreg.h" 00052 #include "shlwapi.h" 00053 #include "shlobj.h" 00054 #include "shellapi.h" 00055 00056 #include "internet.h" 00057 00058 #include "wine/unicode.h" 00059 #include "wine/debug.h" 00060 00061 WINE_DEFAULT_DEBUG_CHANNEL(wininet); 00062 00063 #define ENTRY_START_OFFSET 0x4000 00064 #define DIR_LENGTH 8 00065 #define BLOCKSIZE 128 00066 #define HASHTABLE_SIZE 448 00067 #define HASHTABLE_BLOCKSIZE 7 00068 #define HASHTABLE_FREE 3 00069 #define ALLOCATION_TABLE_OFFSET 0x250 00070 #define ALLOCATION_TABLE_SIZE (0x1000 - ALLOCATION_TABLE_OFFSET) 00071 #define HASHTABLE_NUM_ENTRIES (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE) 00072 #define NEWFILE_NUM_BLOCKS 0xd80 00073 #define NEWFILE_SIZE (NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET) 00074 00075 #define DWORD_SIG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24)) 00076 #define URL_SIGNATURE DWORD_SIG('U','R','L',' ') 00077 #define REDR_SIGNATURE DWORD_SIG('R','E','D','R') 00078 #define LEAK_SIGNATURE DWORD_SIG('L','E','A','K') 00079 #define HASH_SIGNATURE DWORD_SIG('H','A','S','H') 00080 00081 #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) ) 00082 00083 typedef struct _CACHEFILE_ENTRY 00084 { 00085 /* union 00086 {*/ 00087 DWORD dwSignature; /* e.g. "URL " */ 00088 /* CHAR szSignature[4]; 00089 };*/ 00090 DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */ 00091 } CACHEFILE_ENTRY; 00092 00093 typedef struct _URL_CACHEFILE_ENTRY 00094 { 00095 CACHEFILE_ENTRY CacheFileEntry; 00096 FILETIME LastModifiedTime; 00097 FILETIME LastAccessTime; 00098 WORD wExpiredDate; /* expire date in dos format */ 00099 WORD wExpiredTime; /* expire time in dos format */ 00100 DWORD dwUnknown1; /* usually zero */ 00101 ULARGE_INTEGER size; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow/High */ 00102 DWORD dwUnknown2; /* usually zero */ 00103 DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */ 00104 DWORD dwUnknown3; /* usually 0x60 */ 00105 DWORD dwOffsetUrl; /* offset of start of url from start of entry */ 00106 BYTE CacheDir; /* index of cache directory this url is stored in */ 00107 BYTE Unknown4; /* usually zero */ 00108 WORD wUnknown5; /* usually 0x1010 */ 00109 DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */ 00110 DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */ 00111 DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */ 00112 DWORD dwHeaderInfoSize; 00113 DWORD dwOffsetFileExtension; /* offset of start of file extension from start of entry */ 00114 WORD wLastSyncDate; /* last sync date in dos format */ 00115 WORD wLastSyncTime; /* last sync time in dos format */ 00116 DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */ 00117 DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */ 00118 WORD wUnknownDate; /* usually same as wLastSyncDate */ 00119 WORD wUnknownTime; /* usually same as wLastSyncTime */ 00120 DWORD dwUnknown7; /* usually zero */ 00121 DWORD dwUnknown8; /* usually zero */ 00122 /* packing to dword align start of next field */ 00123 /* CHAR szSourceUrlName[]; (url) */ 00124 /* packing to dword align start of next field */ 00125 /* CHAR szLocalFileName[]; (local file name excluding path) */ 00126 /* packing to dword align start of next field */ 00127 /* CHAR szHeaderInfo[]; (header info) */ 00128 } URL_CACHEFILE_ENTRY; 00129 00130 struct _HASH_ENTRY 00131 { 00132 DWORD dwHashKey; 00133 DWORD dwOffsetEntry; 00134 }; 00135 00136 typedef struct _HASH_CACHEFILE_ENTRY 00137 { 00138 CACHEFILE_ENTRY CacheFileEntry; 00139 DWORD dwAddressNext; 00140 DWORD dwHashTableNumber; 00141 struct _HASH_ENTRY HashTable[HASHTABLE_SIZE]; 00142 } HASH_CACHEFILE_ENTRY; 00143 00144 typedef struct _DIRECTORY_DATA 00145 { 00146 DWORD dwNumFiles; 00147 char filename[DIR_LENGTH]; 00148 } DIRECTORY_DATA; 00149 00150 typedef struct _URLCACHE_HEADER 00151 { 00152 char szSignature[28]; 00153 DWORD dwFileSize; 00154 DWORD dwOffsetFirstHashTable; 00155 DWORD dwIndexCapacityInBlocks; 00156 DWORD dwBlocksInUse; 00157 DWORD dwUnknown1; 00158 ULARGE_INTEGER CacheLimit; 00159 ULARGE_INTEGER CacheUsage; 00160 ULARGE_INTEGER ExemptUsage; 00161 DWORD DirectoryCount; /* number of directory_data's */ 00162 DIRECTORY_DATA directory_data[1]; /* first directory entry */ 00163 } URLCACHE_HEADER, *LPURLCACHE_HEADER; 00164 typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER; 00165 00166 typedef struct _STREAM_HANDLE 00167 { 00168 HANDLE hFile; 00169 CHAR lpszUrl[1]; 00170 } STREAM_HANDLE; 00171 00172 typedef struct _URLCACHECONTAINER 00173 { 00174 struct list entry; /* part of a list */ 00175 LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */ 00176 LPWSTR path; /* path to url container directory */ 00177 HANDLE hMapping; /* handle of file mapping */ 00178 DWORD file_size; /* size of file when mapping was opened */ 00179 HANDLE hMutex; /* handle of mutex */ 00180 } URLCACHECONTAINER; 00181 00182 00183 /* List of all containers available */ 00184 static struct list UrlContainers = LIST_INIT(UrlContainers); 00185 BOOL bDefaultContainersAdded = FALSE; 00186 00187 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash); 00188 00189 /*********************************************************************** 00190 * URLCache_PathToObjectName (Internal) 00191 * 00192 * Converts a path to a name suitable for use as a Win32 object name. 00193 * Replaces '\\' characters in-place with the specified character 00194 * (usually '_' or '!') 00195 * 00196 * RETURNS 00197 * nothing 00198 * 00199 */ 00200 static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace) 00201 { 00202 for (; *lpszPath; lpszPath++) 00203 { 00204 if (*lpszPath == '\\') 00205 *lpszPath = replace; 00206 } 00207 } 00208 00209 /*********************************************************************** 00210 * URLCacheContainer_OpenIndex (Internal) 00211 * 00212 * Opens the index file and saves mapping handle in hCacheIndexMapping 00213 * 00214 * RETURNS 00215 * ERROR_SUCCESS if succeeded 00216 * Any other Win32 error code if failed 00217 * 00218 */ 00219 static DWORD URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer) 00220 { 00221 HANDLE hFile; 00222 WCHAR wszFilePath[MAX_PATH]; 00223 DWORD dwFileSize; 00224 00225 static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0}; 00226 static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0}; 00227 00228 WaitForSingleObject(pContainer->hMutex, INFINITE); 00229 00230 if (pContainer->hMapping) { 00231 ReleaseMutex(pContainer->hMutex); 00232 return ERROR_SUCCESS; 00233 } 00234 00235 strcpyW(wszFilePath, pContainer->path); 00236 strcatW(wszFilePath, wszIndex); 00237 00238 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL); 00239 if (hFile == INVALID_HANDLE_VALUE) 00240 { 00241 /* Maybe the directory wasn't there? Try to create it */ 00242 if (CreateDirectoryW(pContainer->path, 0)) 00243 hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL); 00244 } 00245 if (hFile == INVALID_HANDLE_VALUE) 00246 { 00247 TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath)); 00248 ReleaseMutex(pContainer->hMutex); 00249 return GetLastError(); 00250 } 00251 00252 dwFileSize = GetFileSize(hFile, NULL); 00253 if (dwFileSize == INVALID_FILE_SIZE) 00254 { 00255 ReleaseMutex(pContainer->hMutex); 00256 return GetLastError(); 00257 } 00258 00259 if (dwFileSize == 0) 00260 { 00261 static const CHAR szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Content"; 00262 HKEY key; 00263 char achZeroes[0x1000]; 00264 DWORD dwOffset; 00265 DWORD dwError = ERROR_SUCCESS; 00266 00267 /* Write zeroes to the entire file so we can safely map it without 00268 * fear of getting a SEGV because the disk is full. 00269 */ 00270 memset(achZeroes, 0, sizeof(achZeroes)); 00271 for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes)) 00272 { 00273 DWORD dwWrite = sizeof(achZeroes); 00274 DWORD dwWritten; 00275 00276 if (NEWFILE_SIZE - dwOffset < dwWrite) 00277 dwWrite = NEWFILE_SIZE - dwOffset; 00278 if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) || 00279 dwWritten != dwWrite) 00280 { 00281 /* If we fail to write, we need to return the error that 00282 * cause the problem and also make sure the file is no 00283 * longer there, if possible. 00284 */ 00285 dwError = GetLastError(); 00286 00287 break; 00288 } 00289 } 00290 00291 if (dwError == ERROR_SUCCESS) 00292 { 00293 HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL); 00294 00295 if (hMapping) 00296 { 00297 URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE); 00298 00299 if (pHeader) 00300 { 00301 WCHAR *pwchDir; 00302 WCHAR wszDirPath[MAX_PATH]; 00303 FILETIME ft; 00304 int i, j; 00305 HASH_CACHEFILE_ENTRY *pHashEntry; 00306 00307 dwFileSize = NEWFILE_SIZE; 00308 00309 /* First set some constants and defaults in the header */ 00310 strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001"); 00311 pHeader->dwFileSize = dwFileSize; 00312 pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS; 00313 /* 127MB - taken from default for Windows 2000 */ 00314 pHeader->CacheLimit.QuadPart = 0x07ff5400; 00315 /* Copied from a Windows 2000 cache index */ 00316 pHeader->DirectoryCount = 4; 00317 00318 /* If the registry has a cache size set, use the registry value */ 00319 if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS) 00320 { 00321 DWORD dw; 00322 DWORD len = sizeof(dw); 00323 DWORD keytype; 00324 00325 if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype, 00326 (BYTE *) &dw, &len) == ERROR_SUCCESS && 00327 keytype == REG_DWORD) 00328 { 00329 pHeader->CacheLimit.QuadPart = (ULONGLONG)dw * 1024; 00330 } 00331 RegCloseKey(key); 00332 } 00333 00334 URLCache_CreateHashTable(pHeader, NULL, &pHashEntry); 00335 00336 /* Last step - create the directories */ 00337 00338 strcpyW(wszDirPath, pContainer->path); 00339 pwchDir = wszDirPath + strlenW(wszDirPath); 00340 pwchDir[8] = 0; 00341 00342 GetSystemTimeAsFileTime(&ft); 00343 00344 for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i) 00345 { 00346 pHeader->directory_data[i].dwNumFiles = 0; 00347 for (j = 0;; ++j) 00348 { 00349 int k; 00350 ULONGLONG n = ft.dwHighDateTime; 00351 00352 /* Generate a file name to attempt to create. 00353 * This algorithm will create what will appear 00354 * to be random and unrelated directory names 00355 * of up to 9 characters in length. 00356 */ 00357 n <<= 32; 00358 n += ft.dwLowDateTime; 00359 n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48); 00360 00361 for (k = 0; k < 8; ++k) 00362 { 00363 int r = (n % 36); 00364 00365 /* Dividing by a prime greater than 36 helps 00366 * with the appearance of randomness 00367 */ 00368 n /= 37; 00369 00370 if (r < 10) 00371 pwchDir[k] = '0' + r; 00372 else 00373 pwchDir[k] = 'A' + (r - 10); 00374 } 00375 00376 if (CreateDirectoryW(wszDirPath, 0)) 00377 { 00378 /* The following is OK because we generated an 00379 * 8 character directory name made from characters 00380 * [A-Z0-9], which are equivalent for all code 00381 * pages and for UTF-16 00382 */ 00383 for (k = 0; k < 8; ++k) 00384 pHeader->directory_data[i].filename[k] = pwchDir[k]; 00385 break; 00386 } 00387 else if (j >= 255) 00388 { 00389 /* Give up. The most likely cause of this 00390 * is a full disk, but whatever the cause 00391 * is, it should be more than apparent that 00392 * we won't succeed. 00393 */ 00394 dwError = GetLastError(); 00395 break; 00396 } 00397 } 00398 } 00399 00400 UnmapViewOfFile(pHeader); 00401 } 00402 else 00403 { 00404 dwError = GetLastError(); 00405 } 00406 CloseHandle(hMapping); 00407 } 00408 else 00409 { 00410 dwError = GetLastError(); 00411 } 00412 } 00413 00414 if (dwError) 00415 { 00416 CloseHandle(hFile); 00417 DeleteFileW(wszFilePath); 00418 ReleaseMutex(pContainer->hMutex); 00419 return dwError; 00420 } 00421 00422 } 00423 00424 wsprintfW(wszFilePath, wszMappingFormat, pContainer->path, wszIndex, dwFileSize); 00425 URLCache_PathToObjectName(wszFilePath, '_'); 00426 pContainer->hMapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, wszFilePath); 00427 if (!pContainer->hMapping) 00428 pContainer->hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, wszFilePath); 00429 CloseHandle(hFile); 00430 if (!pContainer->hMapping) 00431 { 00432 ERR("Couldn't create file mapping (error is %d)\n", GetLastError()); 00433 ReleaseMutex(pContainer->hMutex); 00434 return GetLastError(); 00435 } 00436 00437 ReleaseMutex(pContainer->hMutex); 00438 00439 return ERROR_SUCCESS; 00440 } 00441 00442 /*********************************************************************** 00443 * URLCacheContainer_CloseIndex (Internal) 00444 * 00445 * Closes the index 00446 * 00447 * RETURNS 00448 * nothing 00449 * 00450 */ 00451 static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer) 00452 { 00453 CloseHandle(pContainer->hMapping); 00454 pContainer->hMapping = NULL; 00455 } 00456 00457 static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name) 00458 { 00459 URLCACHECONTAINER * pContainer = heap_alloc(sizeof(URLCACHECONTAINER)); 00460 int cache_prefix_len = strlenW(cache_prefix); 00461 00462 if (!pContainer) 00463 { 00464 return FALSE; 00465 } 00466 00467 pContainer->hMapping = NULL; 00468 pContainer->file_size = 0; 00469 00470 pContainer->path = heap_strdupW(path); 00471 if (!pContainer->path) 00472 { 00473 HeapFree(GetProcessHeap(), 0, pContainer); 00474 return FALSE; 00475 } 00476 00477 pContainer->cache_prefix = heap_alloc((cache_prefix_len + 1) * sizeof(WCHAR)); 00478 if (!pContainer->cache_prefix) 00479 { 00480 HeapFree(GetProcessHeap(), 0, pContainer->path); 00481 HeapFree(GetProcessHeap(), 0, pContainer); 00482 return FALSE; 00483 } 00484 00485 memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR)); 00486 00487 CharLowerW(mutex_name); 00488 URLCache_PathToObjectName(mutex_name, '!'); 00489 00490 if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL) 00491 { 00492 ERR("couldn't create mutex (error is %d)\n", GetLastError()); 00493 HeapFree(GetProcessHeap(), 0, pContainer->path); 00494 HeapFree(GetProcessHeap(), 0, pContainer); 00495 return FALSE; 00496 } 00497 00498 list_add_head(&UrlContainers, &pContainer->entry); 00499 00500 return TRUE; 00501 } 00502 00503 static void URLCacheContainer_DeleteContainer(URLCACHECONTAINER * pContainer) 00504 { 00505 list_remove(&pContainer->entry); 00506 00507 URLCacheContainer_CloseIndex(pContainer); 00508 CloseHandle(pContainer->hMutex); 00509 HeapFree(GetProcessHeap(), 0, pContainer->path); 00510 HeapFree(GetProcessHeap(), 0, pContainer->cache_prefix); 00511 HeapFree(GetProcessHeap(), 0, pContainer); 00512 } 00513 00514 void URLCacheContainers_CreateDefaults(void) 00515 { 00516 static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0}; 00517 static const WCHAR UrlPrefix[] = {0}; 00518 static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0}; 00519 static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0}; 00520 static const WCHAR CookieSuffix[] = {0}; 00521 static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0}; 00522 static const WCHAR UserProfile[] = {'U','S','E','R','P','R','O','F','I','L','E',0}; 00523 static const struct 00524 { 00525 int nFolder; /* CSIDL_* constant */ 00526 const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */ 00527 const WCHAR * cache_prefix; /* prefix used to reference the container */ 00528 } DefaultContainerData[] = 00529 { 00530 { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix }, 00531 { CSIDL_HISTORY, HistorySuffix, HistoryPrefix }, 00532 { CSIDL_COOKIES, CookieSuffix, CookiePrefix }, 00533 }; 00534 DWORD i; 00535 00536 if (GetEnvironmentVariableW(UserProfile, NULL, 0) == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) 00537 { 00538 TRACE("Environment variable 'USERPROFILE' does not exist!\n"); 00539 return; 00540 } 00541 00542 for (i = 0; i < sizeof(DefaultContainerData) / sizeof(DefaultContainerData[0]); i++) 00543 { 00544 WCHAR wszCachePath[MAX_PATH]; 00545 WCHAR wszMutexName[MAX_PATH]; 00546 int path_len, suffix_len; 00547 00548 if (!SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE)) 00549 { 00550 ERR("Couldn't get path for default container %u\n", i); 00551 continue; 00552 } 00553 path_len = strlenW(wszCachePath); 00554 suffix_len = strlenW(DefaultContainerData[i].shpath_suffix); 00555 00556 if (path_len + suffix_len + 2 > MAX_PATH) 00557 { 00558 ERR("Path too long\n"); 00559 continue; 00560 } 00561 00562 wszCachePath[path_len] = '\\'; 00563 wszCachePath[path_len+1] = 0; 00564 00565 strcpyW(wszMutexName, wszCachePath); 00566 00567 if (suffix_len) 00568 { 00569 memcpy(wszCachePath + path_len + 1, DefaultContainerData[i].shpath_suffix, (suffix_len + 1) * sizeof(WCHAR)); 00570 wszCachePath[path_len + suffix_len + 1] = '\\'; 00571 wszCachePath[path_len + suffix_len + 2] = '\0'; 00572 } 00573 00574 URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, wszMutexName); 00575 } 00576 } 00577 00578 void URLCacheContainers_DeleteAll(void) 00579 { 00580 while(!list_empty(&UrlContainers)) 00581 URLCacheContainer_DeleteContainer( 00582 LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry) 00583 ); 00584 } 00585 00586 static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer) 00587 { 00588 URLCACHECONTAINER * pContainer; 00589 00590 TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl)); 00591 00592 if(!lpwszUrl) 00593 return ERROR_INVALID_PARAMETER; 00594 00595 if (!bDefaultContainersAdded) 00596 URLCacheContainers_CreateDefaults(); 00597 00598 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry) 00599 { 00600 int prefix_len = strlenW(pContainer->cache_prefix); 00601 if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len)) 00602 { 00603 TRACE("found container with prefix %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl)); 00604 *ppContainer = pContainer; 00605 return ERROR_SUCCESS; 00606 } 00607 } 00608 ERR("no container found\n"); 00609 return ERROR_FILE_NOT_FOUND; 00610 } 00611 00612 static DWORD URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer) 00613 { 00614 LPWSTR url = NULL; 00615 DWORD ret; 00616 00617 if (lpszUrl && !(url = heap_strdupAtoW(lpszUrl))) 00618 return ERROR_OUTOFMEMORY; 00619 00620 ret = URLCacheContainers_FindContainerW(url, ppContainer); 00621 HeapFree(GetProcessHeap(), 0, url); 00622 return ret; 00623 } 00624 00625 static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, URLCACHECONTAINER ** ppContainer) 00626 { 00627 DWORD i = 0; 00628 URLCACHECONTAINER * pContainer; 00629 00630 TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern)); 00631 00632 /* non-NULL search pattern only returns one container ever */ 00633 if (lpwszSearchPattern && dwIndex > 0) 00634 return FALSE; 00635 00636 if (!bDefaultContainersAdded) 00637 URLCacheContainers_CreateDefaults(); 00638 00639 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry) 00640 { 00641 if (lpwszSearchPattern) 00642 { 00643 if (!strcmpW(pContainer->cache_prefix, lpwszSearchPattern)) 00644 { 00645 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix)); 00646 *ppContainer = pContainer; 00647 return TRUE; 00648 } 00649 } 00650 else 00651 { 00652 if (i == dwIndex) 00653 { 00654 TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix)); 00655 *ppContainer = pContainer; 00656 return TRUE; 00657 } 00658 } 00659 i++; 00660 } 00661 return FALSE; 00662 } 00663 00664 /*********************************************************************** 00665 * URLCacheContainer_LockIndex (Internal) 00666 * 00667 * Locks the index for system-wide exclusive access. 00668 * 00669 * RETURNS 00670 * Cache file header if successful 00671 * NULL if failed and calls SetLastError. 00672 */ 00673 static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContainer) 00674 { 00675 BYTE index; 00676 LPVOID pIndexData; 00677 URLCACHE_HEADER * pHeader; 00678 DWORD error; 00679 00680 /* acquire mutex */ 00681 WaitForSingleObject(pContainer->hMutex, INFINITE); 00682 00683 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0); 00684 00685 if (!pIndexData) 00686 { 00687 ReleaseMutex(pContainer->hMutex); 00688 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError()); 00689 return NULL; 00690 } 00691 pHeader = (URLCACHE_HEADER *)pIndexData; 00692 00693 /* file has grown - we need to remap to prevent us getting 00694 * access violations when we try and access beyond the end 00695 * of the memory mapped file */ 00696 if (pHeader->dwFileSize != pContainer->file_size) 00697 { 00698 UnmapViewOfFile( pHeader ); 00699 URLCacheContainer_CloseIndex(pContainer); 00700 error = URLCacheContainer_OpenIndex(pContainer); 00701 if (error != ERROR_SUCCESS) 00702 { 00703 ReleaseMutex(pContainer->hMutex); 00704 SetLastError(error); 00705 return NULL; 00706 } 00707 pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0); 00708 00709 if (!pIndexData) 00710 { 00711 ReleaseMutex(pContainer->hMutex); 00712 ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError()); 00713 return NULL; 00714 } 00715 pHeader = (URLCACHE_HEADER *)pIndexData; 00716 } 00717 00718 TRACE("Signature: %s, file size: %d bytes\n", pHeader->szSignature, pHeader->dwFileSize); 00719 00720 for (index = 0; index < pHeader->DirectoryCount; index++) 00721 { 00722 TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename); 00723 } 00724 00725 return pHeader; 00726 } 00727 00728 /*********************************************************************** 00729 * URLCacheContainer_UnlockIndex (Internal) 00730 * 00731 */ 00732 static BOOL URLCacheContainer_UnlockIndex(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader) 00733 { 00734 /* release mutex */ 00735 ReleaseMutex(pContainer->hMutex); 00736 return UnmapViewOfFile(pHeader); 00737 } 00738 00739 00740 #ifndef CHAR_BIT 00741 #define CHAR_BIT (8 * sizeof(CHAR)) 00742 #endif 00743 00744 /*********************************************************************** 00745 * URLCache_Allocation_BlockIsFree (Internal) 00746 * 00747 * Is the specified block number free? 00748 * 00749 * RETURNS 00750 * zero if free 00751 * non-zero otherwise 00752 * 00753 */ 00754 static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber) 00755 { 00756 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT); 00757 return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0; 00758 } 00759 00760 /*********************************************************************** 00761 * URLCache_Allocation_BlockFree (Internal) 00762 * 00763 * Marks the specified block as free 00764 * 00765 * RETURNS 00766 * nothing 00767 * 00768 */ 00769 static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber) 00770 { 00771 BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT)); 00772 AllocationTable[dwBlockNumber / CHAR_BIT] &= mask; 00773 } 00774 00775 /*********************************************************************** 00776 * URLCache_Allocation_BlockAllocate (Internal) 00777 * 00778 * Marks the specified block as allocated 00779 * 00780 * RETURNS 00781 * nothing 00782 * 00783 */ 00784 static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber) 00785 { 00786 BYTE mask = 1 << (dwBlockNumber % CHAR_BIT); 00787 AllocationTable[dwBlockNumber / CHAR_BIT] |= mask; 00788 } 00789 00790 /*********************************************************************** 00791 * URLCache_FindFirstFreeEntry (Internal) 00792 * 00793 * Finds and allocates the first block of free space big enough and 00794 * sets ppEntry to point to it. 00795 * 00796 * RETURNS 00797 * TRUE if it had enough space 00798 * FALSE if it couldn't find enough space 00799 * 00800 */ 00801 static BOOL URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, CACHEFILE_ENTRY ** ppEntry) 00802 { 00803 LPBYTE AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET; 00804 DWORD dwBlockNumber; 00805 DWORD dwFreeCounter; 00806 for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++) 00807 { 00808 for (dwFreeCounter = 0; 00809 dwFreeCounter < dwBlocksNeeded && 00810 dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks && 00811 URLCache_Allocation_BlockIsFree(AllocationTable, dwBlockNumber + dwFreeCounter); 00812 dwFreeCounter++) 00813 TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE); 00814 00815 if (dwFreeCounter == dwBlocksNeeded) 00816 { 00817 DWORD index; 00818 TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE); 00819 for (index = 0; index < dwBlocksNeeded; index++) 00820 URLCache_Allocation_BlockAllocate(AllocationTable, dwBlockNumber + index); 00821 *ppEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE); 00822 (*ppEntry)->dwBlocksUsed = dwBlocksNeeded; 00823 return TRUE; 00824 } 00825 } 00826 FIXME("Grow file\n"); 00827 return FALSE; 00828 } 00829 00830 /*********************************************************************** 00831 * URLCache_DeleteEntry (Internal) 00832 * 00833 * Deletes the specified entry and frees the space allocated to it 00834 * 00835 * RETURNS 00836 * TRUE if it succeeded 00837 * FALSE if it failed 00838 * 00839 */ 00840 static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, CACHEFILE_ENTRY * pEntry) 00841 { 00842 DWORD dwStartBlock; 00843 DWORD dwBlock; 00844 BYTE * AllocationTable = (LPBYTE)pHeader + ALLOCATION_TABLE_OFFSET; 00845 00846 /* update allocation table */ 00847 dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader)) / BLOCKSIZE; 00848 for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->dwBlocksUsed; dwBlock++) 00849 URLCache_Allocation_BlockFree(AllocationTable, dwBlock); 00850 00851 ZeroMemory(pEntry, pEntry->dwBlocksUsed * BLOCKSIZE); 00852 return TRUE; 00853 } 00854 00855 /*********************************************************************** 00856 * URLCache_LocalFileNameToPathW (Internal) 00857 * 00858 * Copies the full path to the specified buffer given the local file 00859 * name and the index of the directory it is in. Always sets value in 00860 * lpBufferSize to the required buffer size (in bytes). 00861 * 00862 * RETURNS 00863 * TRUE if the buffer was big enough 00864 * FALSE if the buffer was too small 00865 * 00866 */ 00867 static BOOL URLCache_LocalFileNameToPathW( 00868 const URLCACHECONTAINER * pContainer, 00869 LPCURLCACHE_HEADER pHeader, 00870 LPCSTR szLocalFileName, 00871 BYTE Directory, 00872 LPWSTR wszPath, 00873 LPLONG lpBufferSize) 00874 { 00875 LONG nRequired; 00876 int path_len = strlenW(pContainer->path); 00877 int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0); 00878 if (Directory >= pHeader->DirectoryCount) 00879 { 00880 *lpBufferSize = 0; 00881 return FALSE; 00882 } 00883 00884 nRequired = (path_len + DIR_LENGTH + file_name_len + 1) * sizeof(WCHAR); 00885 if (nRequired <= *lpBufferSize) 00886 { 00887 int dir_len; 00888 00889 memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR)); 00890 dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH); 00891 wszPath[dir_len + path_len] = '\\'; 00892 MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, wszPath + dir_len + path_len + 1, file_name_len); 00893 *lpBufferSize = nRequired; 00894 return TRUE; 00895 } 00896 *lpBufferSize = nRequired; 00897 return FALSE; 00898 } 00899 00900 /*********************************************************************** 00901 * URLCache_LocalFileNameToPathA (Internal) 00902 * 00903 * Copies the full path to the specified buffer given the local file 00904 * name and the index of the directory it is in. Always sets value in 00905 * lpBufferSize to the required buffer size. 00906 * 00907 * RETURNS 00908 * TRUE if the buffer was big enough 00909 * FALSE if the buffer was too small 00910 * 00911 */ 00912 static BOOL URLCache_LocalFileNameToPathA( 00913 const URLCACHECONTAINER * pContainer, 00914 LPCURLCACHE_HEADER pHeader, 00915 LPCSTR szLocalFileName, 00916 BYTE Directory, 00917 LPSTR szPath, 00918 LPLONG lpBufferSize) 00919 { 00920 LONG nRequired; 00921 int path_len, file_name_len, dir_len; 00922 00923 if (Directory >= pHeader->DirectoryCount) 00924 { 00925 *lpBufferSize = 0; 00926 return FALSE; 00927 } 00928 00929 path_len = WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, NULL, 0, NULL, NULL) - 1; 00930 file_name_len = strlen(szLocalFileName) + 1 /* for nul-terminator */; 00931 dir_len = DIR_LENGTH; 00932 00933 nRequired = (path_len + dir_len + 1 + file_name_len) * sizeof(char); 00934 if (nRequired < *lpBufferSize) 00935 { 00936 WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, path_len, NULL, NULL); 00937 memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len); 00938 szPath[path_len + dir_len] = '\\'; 00939 memcpy(szPath + path_len + dir_len + 1, szLocalFileName, file_name_len); 00940 *lpBufferSize = nRequired; 00941 return TRUE; 00942 } 00943 *lpBufferSize = nRequired; 00944 return FALSE; 00945 } 00946 00947 /* Just like DosDateTimeToFileTime, except that it also maps the special 00948 * case of a DOS date/time of (0,0) to a filetime of (0,0). 00949 */ 00950 static void URLCache_DosDateTimeToFileTime(WORD fatdate, WORD fattime, 00951 FILETIME *ft) 00952 { 00953 if (!fatdate && !fattime) 00954 ft->dwLowDateTime = ft->dwHighDateTime = 0; 00955 else 00956 DosDateTimeToFileTime(fatdate, fattime, ft); 00957 } 00958 00959 /*********************************************************************** 00960 * URLCache_CopyEntry (Internal) 00961 * 00962 * Copies an entry from the cache index file to the Win32 structure 00963 * 00964 * RETURNS 00965 * ERROR_SUCCESS if the buffer was big enough 00966 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small 00967 * 00968 */ 00969 static DWORD URLCache_CopyEntry( 00970 URLCACHECONTAINER * pContainer, 00971 LPCURLCACHE_HEADER pHeader, 00972 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, 00973 LPDWORD lpdwBufferSize, 00974 const URL_CACHEFILE_ENTRY * pUrlEntry, 00975 BOOL bUnicode) 00976 { 00977 int lenUrl; 00978 DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo); 00979 00980 if (*lpdwBufferSize >= dwRequiredSize) 00981 { 00982 lpCacheEntryInfo->lpHeaderInfo = NULL; 00983 lpCacheEntryInfo->lpszFileExtension = NULL; 00984 lpCacheEntryInfo->lpszLocalFileName = NULL; 00985 lpCacheEntryInfo->lpszSourceUrlName = NULL; 00986 lpCacheEntryInfo->CacheEntryType = pUrlEntry->CacheEntryType; 00987 lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->dwExemptDelta; 00988 lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->dwHeaderInfoSize; 00989 lpCacheEntryInfo->dwHitRate = pUrlEntry->dwHitRate; 00990 lpCacheEntryInfo->dwSizeHigh = pUrlEntry->size.u.HighPart; 00991 lpCacheEntryInfo->dwSizeLow = pUrlEntry->size.u.LowPart; 00992 lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo); 00993 lpCacheEntryInfo->dwUseCount = pUrlEntry->dwUseCount; 00994 URLCache_DosDateTimeToFileTime(pUrlEntry->wExpiredDate, pUrlEntry->wExpiredTime, &lpCacheEntryInfo->ExpireTime); 00995 lpCacheEntryInfo->LastAccessTime.dwHighDateTime = pUrlEntry->LastAccessTime.dwHighDateTime; 00996 lpCacheEntryInfo->LastAccessTime.dwLowDateTime = pUrlEntry->LastAccessTime.dwLowDateTime; 00997 lpCacheEntryInfo->LastModifiedTime.dwHighDateTime = pUrlEntry->LastModifiedTime.dwHighDateTime; 00998 lpCacheEntryInfo->LastModifiedTime.dwLowDateTime = pUrlEntry->LastModifiedTime.dwLowDateTime; 00999 URLCache_DosDateTimeToFileTime(pUrlEntry->wLastSyncDate, pUrlEntry->wLastSyncTime, &lpCacheEntryInfo->LastSyncTime); 01000 } 01001 01002 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize)) 01003 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4)); 01004 dwRequiredSize = DWORD_ALIGN(dwRequiredSize); 01005 if (bUnicode) 01006 lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, NULL, 0); 01007 else 01008 lenUrl = strlen((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl); 01009 dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)); 01010 01011 /* FIXME: is source url optional? */ 01012 if (*lpdwBufferSize >= dwRequiredSize) 01013 { 01014 DWORD lenUrlBytes = (lenUrl+1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)); 01015 01016 lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrlBytes; 01017 if (bUnicode) 01018 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1); 01019 else 01020 memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lenUrlBytes); 01021 } 01022 01023 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize)) 01024 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4)); 01025 dwRequiredSize = DWORD_ALIGN(dwRequiredSize); 01026 01027 if (pUrlEntry->dwOffsetLocalName) 01028 { 01029 LONG nLocalFilePathSize; 01030 LPSTR lpszLocalFileName; 01031 lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize; 01032 nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize; 01033 if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) || 01034 (!bUnicode && URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName, pUrlEntry->CacheDir, lpszLocalFileName, &nLocalFilePathSize))) 01035 { 01036 lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName; 01037 } 01038 dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ; 01039 01040 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize)) 01041 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4)); 01042 dwRequiredSize = DWORD_ALIGN(dwRequiredSize); 01043 } 01044 dwRequiredSize += pUrlEntry->dwHeaderInfoSize + 1; 01045 01046 if (*lpdwBufferSize >= dwRequiredSize) 01047 { 01048 lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->dwHeaderInfoSize - 1; 01049 memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo, pUrlEntry->dwHeaderInfoSize); 01050 ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0'; 01051 } 01052 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize)) 01053 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4)); 01054 dwRequiredSize = DWORD_ALIGN(dwRequiredSize); 01055 01056 if (pUrlEntry->dwOffsetFileExtension) 01057 { 01058 int lenExtension; 01059 01060 if (bUnicode) 01061 lenExtension = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, NULL, 0); 01062 else 01063 lenExtension = strlen((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension) + 1; 01064 dwRequiredSize += lenExtension * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)); 01065 01066 if (*lpdwBufferSize >= dwRequiredSize) 01067 { 01068 lpCacheEntryInfo->lpszFileExtension = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenExtension; 01069 if (bUnicode) 01070 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenExtension); 01071 else 01072 memcpy(lpCacheEntryInfo->lpszFileExtension, (LPCSTR)pUrlEntry + pUrlEntry->dwOffsetFileExtension, lenExtension * sizeof(CHAR)); 01073 } 01074 01075 if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize)) 01076 ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4)); 01077 dwRequiredSize = DWORD_ALIGN(dwRequiredSize); 01078 } 01079 01080 if (dwRequiredSize > *lpdwBufferSize) 01081 { 01082 *lpdwBufferSize = dwRequiredSize; 01083 return ERROR_INSUFFICIENT_BUFFER; 01084 } 01085 *lpdwBufferSize = dwRequiredSize; 01086 return ERROR_SUCCESS; 01087 } 01088 01089 /* Just like FileTimeToDosDateTime, except that it also maps the special 01090 * case of a filetime of (0,0) to a DOS date/time of (0,0). 01091 */ 01092 static void URLCache_FileTimeToDosDateTime(const FILETIME *ft, WORD *fatdate, 01093 WORD *fattime) 01094 { 01095 if (!ft->dwLowDateTime && !ft->dwHighDateTime) 01096 *fatdate = *fattime = 0; 01097 else 01098 FileTimeToDosDateTime(ft, fatdate, fattime); 01099 } 01100 01101 /*********************************************************************** 01102 * URLCache_SetEntryInfo (Internal) 01103 * 01104 * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry 01105 * according to the flags set by dwFieldControl. 01106 * 01107 * RETURNS 01108 * ERROR_SUCCESS if the buffer was big enough 01109 * ERROR_INSUFFICIENT_BUFFER if the buffer was too small 01110 * 01111 */ 01112 static DWORD URLCache_SetEntryInfo(URL_CACHEFILE_ENTRY * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl) 01113 { 01114 if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC) 01115 pUrlEntry->LastAccessTime = lpCacheEntryInfo->LastAccessTime; 01116 if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC) 01117 pUrlEntry->CacheEntryType = lpCacheEntryInfo->CacheEntryType; 01118 if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC) 01119 pUrlEntry->dwExemptDelta = lpCacheEntryInfo->u.dwExemptDelta; 01120 if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC) 01121 URLCache_FileTimeToDosDateTime(&lpCacheEntryInfo->ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime); 01122 if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC) 01123 FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n"); 01124 if (dwFieldControl & CACHE_ENTRY_HITRATE_FC) 01125 pUrlEntry->dwHitRate = lpCacheEntryInfo->dwHitRate; 01126 if (dwFieldControl & CACHE_ENTRY_MODTIME_FC) 01127 pUrlEntry->LastModifiedTime = lpCacheEntryInfo->LastModifiedTime; 01128 if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC) 01129 URLCache_FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime); 01130 01131 return ERROR_SUCCESS; 01132 } 01133 01134 /*********************************************************************** 01135 * URLCache_HashKey (Internal) 01136 * 01137 * Returns the hash key for a given string 01138 * 01139 * RETURNS 01140 * hash key for the string 01141 * 01142 */ 01143 static DWORD URLCache_HashKey(LPCSTR lpszKey) 01144 { 01145 /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W} 01146 * but the algorithm and result are not the same! 01147 */ 01148 static const unsigned char lookupTable[256] = 01149 { 01150 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77, 01151 0x8A, 0xAA, 0x7D, 0x76, 0x1B, 0xE9, 0x8C, 0x33, 01152 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44, 01153 0x1E, 0x07, 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41, 01154 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, 0xDF, 01155 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C, 01156 0x0C, 0xB5, 0x67, 0x46, 0x16, 0x3A, 0x4B, 0x4E, 01157 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90, 01158 0xB0, 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53, 01159 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, 0x29, 0xFE, 01160 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58, 01161 0x23, 0xCE, 0x5F, 0x74, 0xFC, 0xC0, 0x36, 0xDD, 01162 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9, 01163 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D, 01164 0xA6, 0x50, 0x32, 0x22, 0xAF, 0xC3, 0x64, 0x63, 01165 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD, 01166 0x79, 0x40, 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A, 01167 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, 0xC2, 01168 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B, 01169 0x4A, 0x3B, 0x89, 0xE4, 0x6C, 0xBF, 0xE8, 0x8B, 01170 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C, 01171 0xFB, 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70, 01172 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, 0x0D, 0x20, 01173 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B, 01174 0xF9, 0xEC, 0x2D, 0xF4, 0x6F, 0xB6, 0x99, 0x88, 01175 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47, 01176 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72, 01177 0xA2, 0x35, 0xA0, 0xD7, 0xCD, 0xB4, 0x2F, 0x6D, 01178 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34, 01179 0x3F, 0x17, 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 01180 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, 0x0A, 01181 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 01182 }; 01183 BYTE key[4]; 01184 DWORD i; 01185 01186 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++) 01187 key[i] = lookupTable[i]; 01188 01189 for (lpszKey++; *lpszKey && ((lpszKey[0] != '/') || (lpszKey[1] != 0)); lpszKey++) 01190 { 01191 for (i = 0; i < sizeof(key) / sizeof(key[0]); i++) 01192 key[i] = lookupTable[*lpszKey ^ key[i]]; 01193 } 01194 01195 return *(DWORD *)key; 01196 } 01197 01198 static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset) 01199 { 01200 return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset); 01201 } 01202 01203 static inline BOOL URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY *pHashEntry) 01204 { 01205 /* check pHashEntry located within acceptable bounds in the URL cache mapping */ 01206 return ((DWORD)((const BYTE*)pHashEntry - (const BYTE*)pHeader) >= ENTRY_START_OFFSET) && 01207 ((DWORD)((const BYTE*)pHashEntry - (const BYTE*)pHeader) < pHeader->dwFileSize); 01208 } 01209 01210 static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry) 01211 { 01212 /* structure of hash table: 01213 * 448 entries divided into 64 blocks 01214 * each block therefore contains a chain of 7 key/offset pairs 01215 * how position in table is calculated: 01216 * 1. the url is hashed in helper function 01217 * 2. the key % 64 * 8 is the offset 01218 * 3. the key in the hash table is the hash key aligned to 64 01219 * 01220 * note: 01221 * there can be multiple hash tables in the file and the offset to 01222 * the next one is stored in the header of the hash table 01223 */ 01224 DWORD key = URLCache_HashKey(lpszUrl); 01225 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY); 01226 HASH_CACHEFILE_ENTRY * pHashEntry; 01227 DWORD dwHashTableNumber = 0; 01228 01229 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES; 01230 01231 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable); 01232 URLCache_IsHashEntryValid(pHeader, pHashEntry); 01233 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext)) 01234 { 01235 int i; 01236 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++) 01237 { 01238 ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber); 01239 continue; 01240 } 01241 /* make sure that it is in fact a hash entry */ 01242 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE) 01243 { 01244 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature); 01245 continue; 01246 } 01247 01248 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++) 01249 { 01250 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i]; 01251 if (key == (pHashElement->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES) 01252 { 01253 /* FIXME: we should make sure that this is the right element 01254 * before returning and claiming that it is. We can do this 01255 * by doing a simple compare between the URL we were given 01256 * and the URL stored in the entry. However, this assumes 01257 * we know the format of all the entries stored in the 01258 * hash table */ 01259 *ppHashEntry = pHashElement; 01260 return TRUE; 01261 } 01262 } 01263 } 01264 return FALSE; 01265 } 01266 01267 static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry) 01268 { 01269 LPSTR urlA; 01270 BOOL ret; 01271 01272 urlA = heap_strdupWtoA(lpszUrl); 01273 if (!urlA) 01274 { 01275 SetLastError(ERROR_OUTOFMEMORY); 01276 return FALSE; 01277 } 01278 01279 ret = URLCache_FindHash(pHeader, urlA, ppHashEntry); 01280 HeapFree(GetProcessHeap(), 0, urlA); 01281 return ret; 01282 } 01283 01284 /*********************************************************************** 01285 * URLCache_HashEntrySetUse (Internal) 01286 * 01287 * Searches all the hash tables in the index for the given URL and 01288 * sets the use count (stored or'ed with key) 01289 * 01290 * RETURNS 01291 * TRUE if the entry was found 01292 * FALSE if the entry could not be found 01293 * 01294 */ 01295 static BOOL URLCache_HashEntrySetUse(struct _HASH_ENTRY * pHashEntry, DWORD dwUseCount) 01296 { 01297 pHashEntry->dwHashKey = dwUseCount | (pHashEntry->dwHashKey / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES; 01298 return TRUE; 01299 } 01300 01301 /*********************************************************************** 01302 * URLCache_DeleteEntryFromHash (Internal) 01303 * 01304 * Searches all the hash tables in the index for the given URL and 01305 * then if found deletes the entry. 01306 * 01307 * RETURNS 01308 * TRUE if the entry was found 01309 * FALSE if the entry could not be found 01310 * 01311 */ 01312 static BOOL URLCache_DeleteEntryFromHash(struct _HASH_ENTRY * pHashEntry) 01313 { 01314 pHashEntry->dwHashKey = HASHTABLE_FREE; 01315 pHashEntry->dwOffsetEntry = HASHTABLE_FREE; 01316 return TRUE; 01317 } 01318 01319 /*********************************************************************** 01320 * URLCache_AddEntryToHash (Internal) 01321 * 01322 * Searches all the hash tables for a free slot based on the offset 01323 * generated from the hash key. If a free slot is found, the offset and 01324 * key are entered into the hash table. 01325 * 01326 * RETURNS 01327 * ERROR_SUCCESS if the entry was added 01328 * Any other Win32 error code if the entry could not be added 01329 * 01330 */ 01331 static DWORD URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry) 01332 { 01333 /* see URLCache_FindEntryInHash for structure of hash tables */ 01334 01335 DWORD key = URLCache_HashKey(lpszUrl); 01336 DWORD offset = (key % HASHTABLE_NUM_ENTRIES) * sizeof(struct _HASH_ENTRY); 01337 HASH_CACHEFILE_ENTRY * pHashEntry; 01338 DWORD dwHashTableNumber = 0; 01339 DWORD error; 01340 01341 key = (key / HASHTABLE_NUM_ENTRIES) * HASHTABLE_NUM_ENTRIES; 01342 01343 for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable); 01344 URLCache_IsHashEntryValid(pHeader, pHashEntry); 01345 pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext)) 01346 { 01347 int i; 01348 if (pHashEntry->dwHashTableNumber != dwHashTableNumber++) 01349 { 01350 ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber); 01351 break; 01352 } 01353 /* make sure that it is in fact a hash entry */ 01354 if (pHashEntry->CacheFileEntry.dwSignature != HASH_SIGNATURE) 01355 { 01356 ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.dwSignature); 01357 break; 01358 } 01359 01360 for (i = 0; i < HASHTABLE_BLOCKSIZE; i++) 01361 { 01362 struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i]; 01363 if (pHashElement->dwHashKey == HASHTABLE_FREE) /* if the slot is free */ 01364 { 01365 pHashElement->dwHashKey = key; 01366 pHashElement->dwOffsetEntry = dwOffsetEntry; 01367 return ERROR_SUCCESS; 01368 } 01369 } 01370 } 01371 error = URLCache_CreateHashTable(pHeader, pHashEntry, &pHashEntry); 01372 if (error != ERROR_SUCCESS) 01373 return error; 01374 01375 pHashEntry->HashTable[offset].dwHashKey = key; 01376 pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry; 01377 return ERROR_SUCCESS; 01378 } 01379 01380 /*********************************************************************** 01381 * URLCache_CreateHashTable (Internal) 01382 * 01383 * Creates a new hash table in free space and adds it to the chain of existing 01384 * hash tables. 01385 * 01386 * RETURNS 01387 * ERROR_SUCCESS if the hash table was created 01388 * ERROR_DISK_FULL if the hash table could not be created 01389 * 01390 */ 01391 static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash) 01392 { 01393 DWORD dwOffset; 01394 int i; 01395 01396 if (!URLCache_FindFirstFreeEntry(pHeader, 0x20, (CACHEFILE_ENTRY **)ppHash)) 01397 { 01398 FIXME("no free space for hash table\n"); 01399 return ERROR_DISK_FULL; 01400 } 01401 01402 dwOffset = (BYTE *)*ppHash - (BYTE *)pHeader; 01403 01404 if (pPrevHash) 01405 pPrevHash->dwAddressNext = dwOffset; 01406 else 01407 pHeader->dwOffsetFirstHashTable = dwOffset; 01408 (*ppHash)->CacheFileEntry.dwSignature = HASH_SIGNATURE; 01409 (*ppHash)->CacheFileEntry.dwBlocksUsed = 0x20; 01410 (*ppHash)->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0; 01411 for (i = 0; i < HASHTABLE_SIZE; i++) 01412 { 01413 (*ppHash)->HashTable[i].dwOffsetEntry = 0; 01414 (*ppHash)->HashTable[i].dwHashKey = HASHTABLE_FREE; 01415 } 01416 return ERROR_SUCCESS; 01417 } 01418 01419 /*********************************************************************** 01420 * URLCache_EnumHashTables (Internal) 01421 * 01422 * Enumerates the hash tables in a container. 01423 * 01424 * RETURNS 01425 * TRUE if an entry was found 01426 * FALSE if there are no more tables to enumerate. 01427 * 01428 */ 01429 static BOOL URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader, DWORD *pdwHashTableNumber, HASH_CACHEFILE_ENTRY ** ppHashEntry) 01430 { 01431 for (*ppHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable); 01432 URLCache_IsHashEntryValid(pHeader, *ppHashEntry); 01433 *ppHashEntry = URLCache_HashEntryFromOffset(pHeader, (*ppHashEntry)->dwAddressNext)) 01434 { 01435 TRACE("looking at hash table number %d\n", (*ppHashEntry)->dwHashTableNumber); 01436 if ((*ppHashEntry)->dwHashTableNumber != *pdwHashTableNumber) 01437 continue; 01438 /* make sure that it is in fact a hash entry */ 01439 if ((*ppHashEntry)->CacheFileEntry.dwSignature != HASH_SIGNATURE) 01440 { 01441 ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&(*ppHashEntry)->CacheFileEntry.dwSignature); 01442 (*pdwHashTableNumber)++; 01443 continue; 01444 } 01445 01446 TRACE("hash table number %d found\n", *pdwHashTableNumber); 01447 return TRUE; 01448 } 01449 return FALSE; 01450 } 01451 01452 /*********************************************************************** 01453 * URLCache_EnumHashTableEntries (Internal) 01454 * 01455 * Enumerates entries in a hash table and returns the next non-free entry. 01456 * 01457 * RETURNS 01458 * TRUE if an entry was found 01459 * FALSE if the hash table is empty or there are no more entries to 01460 * enumerate. 01461 * 01462 */ 01463 static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY * pHashEntry, 01464 DWORD * index, const struct _HASH_ENTRY ** ppHashEntry) 01465 { 01466 for (; *index < HASHTABLE_SIZE ; (*index)++) 01467 { 01468 if (pHashEntry->HashTable[*index].dwHashKey == HASHTABLE_FREE) 01469 continue; 01470 01471 *ppHashEntry = &pHashEntry->HashTable[*index]; 01472 TRACE("entry found %d\n", *index); 01473 return TRUE; 01474 } 01475 TRACE("no more entries (%d)\n", *index); 01476 return FALSE; 01477 } 01478 01479 /*********************************************************************** 01480 * URLCache_DeleteCacheDirectory (Internal) 01481 * 01482 * Erase a directory containing an URL cache. 01483 * 01484 * RETURNS 01485 * TRUE success, FALSE failure/aborted. 01486 * 01487 */ 01488 static BOOL URLCache_DeleteCacheDirectory(LPCWSTR lpszPath) 01489 { 01490 DWORD path_len; 01491 WCHAR path[MAX_PATH + 1]; 01492 SHFILEOPSTRUCTW shfos; 01493 int ret; 01494 01495 path_len = strlenW(lpszPath); 01496 if (path_len >= MAX_PATH) 01497 return FALSE; 01498 strcpyW(path, lpszPath); 01499 path[path_len + 1] = 0; /* double-NUL-terminate path */ 01500 01501 shfos.hwnd = NULL; 01502 shfos.wFunc = FO_DELETE; 01503 shfos.pFrom = path; 01504 shfos.pTo = NULL; 01505 shfos.fFlags = 0; 01506 shfos.fAnyOperationsAborted = FALSE; 01507 ret = SHFileOperationW(&shfos); 01508 if (ret) 01509 ERR("SHFileOperationW on %s returned %i\n", debugstr_w(path), ret); 01510 return !(ret || shfos.fAnyOperationsAborted); 01511 } 01512 01513 /*********************************************************************** 01514 * FreeUrlCacheSpaceW (WININET.@) 01515 * 01516 * Frees up some cache. 01517 * 01518 * PARAMETERS 01519 * lpszCachePath [I] Which volume to free up from, or NULL if you don't care. 01520 * dwSize [I] How much space to free up. 01521 * dwSizeType [I] How to interpret dwSize. 01522 * 01523 * RETURNS 01524 * TRUE success. FALSE failure. 01525 * 01526 * IMPLEMENTATION 01527 * This implementation just retrieves the path of the cache directory, and 01528 * deletes its contents from the filesystem. The correct approach would 01529 * probably be to implement and use {FindFirst,FindNext,Delete}UrlCacheGroup(). 01530 */ 01531 BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR lpszCachePath, DWORD dwSize, DWORD dwSizeType) 01532 { 01533 URLCACHECONTAINER * pContainer; 01534 01535 if (lpszCachePath != NULL || dwSize != 100 || dwSizeType != FCS_PERCENT_CACHE_SPACE) 01536 { 01537 FIXME("(%s, %x, %x): partial stub!\n", debugstr_w(lpszCachePath), dwSize, dwSizeType); 01538 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 01539 return FALSE; 01540 } 01541 01542 if (!bDefaultContainersAdded) 01543 URLCacheContainers_CreateDefaults(); 01544 01545 LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry) 01546 { 01547 /* The URL cache has prefix L"" (unlike Cookies and History) */ 01548 if (pContainer->cache_prefix[0] == 0) 01549 { 01550 BOOL ret_del; 01551 DWORD ret_open; 01552 WaitForSingleObject(pContainer->hMutex, INFINITE); 01553 01554 /* unlock, delete, recreate and lock cache */ 01555 URLCacheContainer_CloseIndex(pContainer); 01556 ret_del = URLCache_DeleteCacheDirectory(pContainer->path); 01557 ret_open = URLCacheContainer_OpenIndex(pContainer); 01558 01559 ReleaseMutex(pContainer->hMutex); 01560 return ret_del && (ret_open == ERROR_SUCCESS); 01561 } 01562 } 01563 return FALSE; 01564 } 01565 01566 /*********************************************************************** 01567 * FreeUrlCacheSpaceA (WININET.@) 01568 * 01569 * See FreeUrlCacheSpaceW. 01570 */ 01571 BOOL WINAPI FreeUrlCacheSpaceA(LPCSTR lpszCachePath, DWORD dwSize, DWORD dwSizeType) 01572 { 01573 BOOL ret = FALSE; 01574 LPWSTR path = heap_strdupAtoW(lpszCachePath); 01575 if (lpszCachePath == NULL || path != NULL) 01576 ret = FreeUrlCacheSpaceW(path, dwSize, dwSizeType); 01577 heap_free(path); 01578 return ret; 01579 } 01580 01581 /*********************************************************************** 01582 * GetUrlCacheEntryInfoExA (WININET.@) 01583 * 01584 */ 01585 BOOL WINAPI GetUrlCacheEntryInfoExA( 01586 LPCSTR lpszUrl, 01587 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, 01588 LPDWORD lpdwCacheEntryInfoBufSize, 01589 LPSTR lpszReserved, 01590 LPDWORD lpdwReserved, 01591 LPVOID lpReserved, 01592 DWORD dwFlags) 01593 { 01594 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n", 01595 debugstr_a(lpszUrl), 01596 lpCacheEntryInfo, 01597 lpdwCacheEntryInfoBufSize, 01598 lpszReserved, 01599 lpdwReserved, 01600 lpReserved, 01601 dwFlags); 01602 01603 if ((lpszReserved != NULL) || 01604 (lpdwReserved != NULL) || 01605 (lpReserved != NULL)) 01606 { 01607 ERR("Reserved value was not 0\n"); 01608 SetLastError(ERROR_INVALID_PARAMETER); 01609 return FALSE; 01610 } 01611 if (dwFlags != 0) 01612 { 01613 FIXME("Undocumented flag(s): %x\n", dwFlags); 01614 SetLastError(ERROR_FILE_NOT_FOUND); 01615 return FALSE; 01616 } 01617 return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize); 01618 } 01619 01620 /*********************************************************************** 01621 * GetUrlCacheEntryInfoA (WININET.@) 01622 * 01623 */ 01624 BOOL WINAPI GetUrlCacheEntryInfoA( 01625 IN LPCSTR lpszUrlName, 01626 IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, 01627 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize 01628 ) 01629 { 01630 LPURLCACHE_HEADER pHeader; 01631 struct _HASH_ENTRY * pHashEntry; 01632 const CACHEFILE_ENTRY * pEntry; 01633 const URL_CACHEFILE_ENTRY * pUrlEntry; 01634 URLCACHECONTAINER * pContainer; 01635 DWORD error; 01636 01637 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize); 01638 01639 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer); 01640 if (error != ERROR_SUCCESS) 01641 { 01642 SetLastError(error); 01643 return FALSE; 01644 } 01645 01646 error = URLCacheContainer_OpenIndex(pContainer); 01647 if (error != ERROR_SUCCESS) 01648 { 01649 SetLastError(error); 01650 return FALSE; 01651 } 01652 01653 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 01654 return FALSE; 01655 01656 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry)) 01657 { 01658 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01659 WARN("entry %s not found!\n", debugstr_a(lpszUrlName)); 01660 SetLastError(ERROR_FILE_NOT_FOUND); 01661 return FALSE; 01662 } 01663 01664 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); 01665 if (pEntry->dwSignature != URL_SIGNATURE) 01666 { 01667 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01668 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD))); 01669 SetLastError(ERROR_FILE_NOT_FOUND); 01670 return FALSE; 01671 } 01672 01673 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry; 01674 TRACE("Found URL: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl)); 01675 if (pUrlEntry->dwOffsetHeaderInfo) 01676 TRACE("Header info: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo)); 01677 01678 if (lpdwCacheEntryInfoBufferSize) 01679 { 01680 if (!lpCacheEntryInfo) 01681 *lpdwCacheEntryInfoBufferSize = 0; 01682 01683 error = URLCache_CopyEntry( 01684 pContainer, 01685 pHeader, 01686 lpCacheEntryInfo, 01687 lpdwCacheEntryInfoBufferSize, 01688 pUrlEntry, 01689 FALSE /* ANSI */); 01690 if (error != ERROR_SUCCESS) 01691 { 01692 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01693 SetLastError(error); 01694 return FALSE; 01695 } 01696 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName)); 01697 } 01698 01699 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01700 01701 return TRUE; 01702 } 01703 01704 /*********************************************************************** 01705 * GetUrlCacheEntryInfoW (WININET.@) 01706 * 01707 */ 01708 BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl, 01709 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, 01710 LPDWORD lpdwCacheEntryInfoBufferSize) 01711 { 01712 LPURLCACHE_HEADER pHeader; 01713 struct _HASH_ENTRY * pHashEntry; 01714 const CACHEFILE_ENTRY * pEntry; 01715 const URL_CACHEFILE_ENTRY * pUrlEntry; 01716 URLCACHECONTAINER * pContainer; 01717 DWORD error; 01718 01719 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize); 01720 01721 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer); 01722 if (error != ERROR_SUCCESS) 01723 { 01724 SetLastError(error); 01725 return FALSE; 01726 } 01727 01728 error = URLCacheContainer_OpenIndex(pContainer); 01729 if (error != ERROR_SUCCESS) 01730 { 01731 SetLastError(error); 01732 return FALSE; 01733 } 01734 01735 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 01736 return FALSE; 01737 01738 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry)) 01739 { 01740 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01741 WARN("entry %s not found!\n", debugstr_w(lpszUrl)); 01742 SetLastError(ERROR_FILE_NOT_FOUND); 01743 return FALSE; 01744 } 01745 01746 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); 01747 if (pEntry->dwSignature != URL_SIGNATURE) 01748 { 01749 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01750 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD))); 01751 SetLastError(ERROR_FILE_NOT_FOUND); 01752 return FALSE; 01753 } 01754 01755 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry; 01756 TRACE("Found URL: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl)); 01757 TRACE("Header info: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo)); 01758 01759 if (lpdwCacheEntryInfoBufferSize) 01760 { 01761 if (!lpCacheEntryInfo) 01762 *lpdwCacheEntryInfoBufferSize = 0; 01763 01764 error = URLCache_CopyEntry( 01765 pContainer, 01766 pHeader, 01767 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo, 01768 lpdwCacheEntryInfoBufferSize, 01769 pUrlEntry, 01770 TRUE /* UNICODE */); 01771 if (error != ERROR_SUCCESS) 01772 { 01773 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01774 SetLastError(error); 01775 return FALSE; 01776 } 01777 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName)); 01778 } 01779 01780 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01781 01782 return TRUE; 01783 } 01784 01785 /*********************************************************************** 01786 * GetUrlCacheEntryInfoExW (WININET.@) 01787 * 01788 */ 01789 BOOL WINAPI GetUrlCacheEntryInfoExW( 01790 LPCWSTR lpszUrl, 01791 LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, 01792 LPDWORD lpdwCacheEntryInfoBufSize, 01793 LPWSTR lpszReserved, 01794 LPDWORD lpdwReserved, 01795 LPVOID lpReserved, 01796 DWORD dwFlags) 01797 { 01798 TRACE("(%s, %p, %p, %p, %p, %p, %x)\n", 01799 debugstr_w(lpszUrl), 01800 lpCacheEntryInfo, 01801 lpdwCacheEntryInfoBufSize, 01802 lpszReserved, 01803 lpdwReserved, 01804 lpReserved, 01805 dwFlags); 01806 01807 if ((lpszReserved != NULL) || 01808 (lpdwReserved != NULL) || 01809 (lpReserved != NULL)) 01810 { 01811 ERR("Reserved value was not 0\n"); 01812 SetLastError(ERROR_INVALID_PARAMETER); 01813 return FALSE; 01814 } 01815 if (dwFlags != 0) 01816 { 01817 FIXME("Undocumented flag(s): %x\n", dwFlags); 01818 SetLastError(ERROR_FILE_NOT_FOUND); 01819 return FALSE; 01820 } 01821 return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize); 01822 } 01823 01824 /*********************************************************************** 01825 * SetUrlCacheEntryInfoA (WININET.@) 01826 */ 01827 BOOL WINAPI SetUrlCacheEntryInfoA( 01828 LPCSTR lpszUrlName, 01829 LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, 01830 DWORD dwFieldControl) 01831 { 01832 LPURLCACHE_HEADER pHeader; 01833 struct _HASH_ENTRY * pHashEntry; 01834 CACHEFILE_ENTRY * pEntry; 01835 URLCACHECONTAINER * pContainer; 01836 DWORD error; 01837 01838 TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl); 01839 01840 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer); 01841 if (error != ERROR_SUCCESS) 01842 { 01843 SetLastError(error); 01844 return FALSE; 01845 } 01846 01847 error = URLCacheContainer_OpenIndex(pContainer); 01848 if (error != ERROR_SUCCESS) 01849 { 01850 SetLastError(error); 01851 return FALSE; 01852 } 01853 01854 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 01855 return FALSE; 01856 01857 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry)) 01858 { 01859 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01860 WARN("entry %s not found!\n", debugstr_a(lpszUrlName)); 01861 SetLastError(ERROR_FILE_NOT_FOUND); 01862 return FALSE; 01863 } 01864 01865 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); 01866 if (pEntry->dwSignature != URL_SIGNATURE) 01867 { 01868 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01869 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD))); 01870 SetLastError(ERROR_FILE_NOT_FOUND); 01871 return FALSE; 01872 } 01873 01874 URLCache_SetEntryInfo( 01875 (URL_CACHEFILE_ENTRY *)pEntry, 01876 (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo, 01877 dwFieldControl); 01878 01879 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01880 01881 return TRUE; 01882 } 01883 01884 /*********************************************************************** 01885 * SetUrlCacheEntryInfoW (WININET.@) 01886 */ 01887 BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl) 01888 { 01889 LPURLCACHE_HEADER pHeader; 01890 struct _HASH_ENTRY * pHashEntry; 01891 CACHEFILE_ENTRY * pEntry; 01892 URLCACHECONTAINER * pContainer; 01893 DWORD error; 01894 01895 TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl); 01896 01897 error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer); 01898 if (error != ERROR_SUCCESS) 01899 { 01900 SetLastError(error); 01901 return FALSE; 01902 } 01903 01904 error = URLCacheContainer_OpenIndex(pContainer); 01905 if (error != ERROR_SUCCESS) 01906 { 01907 SetLastError(error); 01908 return FALSE; 01909 } 01910 01911 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 01912 return FALSE; 01913 01914 if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry)) 01915 { 01916 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01917 WARN("entry %s not found!\n", debugstr_w(lpszUrl)); 01918 SetLastError(ERROR_FILE_NOT_FOUND); 01919 return FALSE; 01920 } 01921 01922 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); 01923 if (pEntry->dwSignature != URL_SIGNATURE) 01924 { 01925 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01926 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD))); 01927 SetLastError(ERROR_FILE_NOT_FOUND); 01928 return FALSE; 01929 } 01930 01931 URLCache_SetEntryInfo( 01932 (URL_CACHEFILE_ENTRY *)pEntry, 01933 lpCacheEntryInfo, 01934 dwFieldControl); 01935 01936 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01937 01938 return TRUE; 01939 } 01940 01941 /*********************************************************************** 01942 * RetrieveUrlCacheEntryFileA (WININET.@) 01943 * 01944 */ 01945 BOOL WINAPI RetrieveUrlCacheEntryFileA( 01946 IN LPCSTR lpszUrlName, 01947 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, 01948 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize, 01949 IN DWORD dwReserved 01950 ) 01951 { 01952 LPURLCACHE_HEADER pHeader; 01953 struct _HASH_ENTRY * pHashEntry; 01954 CACHEFILE_ENTRY * pEntry; 01955 URL_CACHEFILE_ENTRY * pUrlEntry; 01956 URLCACHECONTAINER * pContainer; 01957 DWORD error; 01958 01959 TRACE("(%s, %p, %p, 0x%08x)\n", 01960 debugstr_a(lpszUrlName), 01961 lpCacheEntryInfo, 01962 lpdwCacheEntryInfoBufferSize, 01963 dwReserved); 01964 01965 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize || 01966 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize)) 01967 { 01968 SetLastError(ERROR_INVALID_PARAMETER); 01969 return FALSE; 01970 } 01971 01972 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer); 01973 if (error != ERROR_SUCCESS) 01974 { 01975 SetLastError(error); 01976 return FALSE; 01977 } 01978 01979 error = URLCacheContainer_OpenIndex(pContainer); 01980 if (error != ERROR_SUCCESS) 01981 { 01982 SetLastError(error); 01983 return FALSE; 01984 } 01985 01986 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 01987 return FALSE; 01988 01989 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry)) 01990 { 01991 URLCacheContainer_UnlockIndex(pContainer, pHeader); 01992 TRACE("entry %s not found!\n", lpszUrlName); 01993 SetLastError(ERROR_FILE_NOT_FOUND); 01994 return FALSE; 01995 } 01996 01997 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); 01998 if (pEntry->dwSignature != URL_SIGNATURE) 01999 { 02000 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02001 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD))); 02002 SetLastError(ERROR_FILE_NOT_FOUND); 02003 return FALSE; 02004 } 02005 02006 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry; 02007 if (!pUrlEntry->dwOffsetLocalName) 02008 { 02009 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02010 SetLastError(ERROR_INVALID_DATA); 02011 return FALSE; 02012 } 02013 02014 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl); 02015 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo); 02016 02017 error = URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo, 02018 lpdwCacheEntryInfoBufferSize, pUrlEntry, 02019 FALSE); 02020 if (error != ERROR_SUCCESS) 02021 { 02022 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02023 SetLastError(error); 02024 return FALSE; 02025 } 02026 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName)); 02027 02028 pUrlEntry->dwHitRate++; 02029 pUrlEntry->dwUseCount++; 02030 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount); 02031 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime); 02032 02033 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02034 02035 return TRUE; 02036 } 02037 02038 /*********************************************************************** 02039 * RetrieveUrlCacheEntryFileW (WININET.@) 02040 * 02041 */ 02042 BOOL WINAPI RetrieveUrlCacheEntryFileW( 02043 IN LPCWSTR lpszUrlName, 02044 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, 02045 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize, 02046 IN DWORD dwReserved 02047 ) 02048 { 02049 LPURLCACHE_HEADER pHeader; 02050 struct _HASH_ENTRY * pHashEntry; 02051 CACHEFILE_ENTRY * pEntry; 02052 URL_CACHEFILE_ENTRY * pUrlEntry; 02053 URLCACHECONTAINER * pContainer; 02054 DWORD error; 02055 02056 TRACE("(%s, %p, %p, 0x%08x)\n", 02057 debugstr_w(lpszUrlName), 02058 lpCacheEntryInfo, 02059 lpdwCacheEntryInfoBufferSize, 02060 dwReserved); 02061 02062 if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize || 02063 (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize)) 02064 { 02065 SetLastError(ERROR_INVALID_PARAMETER); 02066 return FALSE; 02067 } 02068 02069 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); 02070 if (error != ERROR_SUCCESS) 02071 { 02072 SetLastError(error); 02073 return FALSE; 02074 } 02075 02076 error = URLCacheContainer_OpenIndex(pContainer); 02077 if (error != ERROR_SUCCESS) 02078 { 02079 SetLastError(error); 02080 return FALSE; 02081 } 02082 02083 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 02084 return FALSE; 02085 02086 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry)) 02087 { 02088 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02089 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName)); 02090 SetLastError(ERROR_FILE_NOT_FOUND); 02091 return FALSE; 02092 } 02093 02094 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); 02095 if (pEntry->dwSignature != URL_SIGNATURE) 02096 { 02097 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02098 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD))); 02099 SetLastError(ERROR_FILE_NOT_FOUND); 02100 return FALSE; 02101 } 02102 02103 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry; 02104 if (!pUrlEntry->dwOffsetLocalName) 02105 { 02106 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02107 SetLastError(ERROR_INVALID_DATA); 02108 return FALSE; 02109 } 02110 02111 TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl); 02112 TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo); 02113 02114 error = URLCache_CopyEntry( 02115 pContainer, 02116 pHeader, 02117 (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo, 02118 lpdwCacheEntryInfoBufferSize, 02119 pUrlEntry, 02120 TRUE /* UNICODE */); 02121 if (error != ERROR_SUCCESS) 02122 { 02123 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02124 SetLastError(error); 02125 return FALSE; 02126 } 02127 TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName)); 02128 02129 pUrlEntry->dwHitRate++; 02130 pUrlEntry->dwUseCount++; 02131 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount); 02132 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime); 02133 02134 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02135 02136 return TRUE; 02137 } 02138 02139 static BOOL DeleteUrlCacheEntryInternal(LPURLCACHE_HEADER pHeader, 02140 struct _HASH_ENTRY *pHashEntry) 02141 { 02142 CACHEFILE_ENTRY * pEntry; 02143 URL_CACHEFILE_ENTRY * pUrlEntry; 02144 02145 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); 02146 if (pEntry->dwSignature != URL_SIGNATURE) 02147 { 02148 FIXME("Trying to delete entry of unknown format %s\n", 02149 debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD))); 02150 SetLastError(ERROR_FILE_NOT_FOUND); 02151 return FALSE; 02152 } 02153 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry; 02154 if (pUrlEntry->CacheDir < pHeader->DirectoryCount) 02155 { 02156 if (pHeader->directory_data[pUrlEntry->CacheDir].dwNumFiles) 02157 pHeader->directory_data[pUrlEntry->CacheDir].dwNumFiles--; 02158 } 02159 if (pUrlEntry->CacheEntryType & STICKY_CACHE_ENTRY) 02160 { 02161 if (pUrlEntry->size.QuadPart < pHeader->ExemptUsage.QuadPart) 02162 pHeader->ExemptUsage.QuadPart -= pUrlEntry->size.QuadPart; 02163 else 02164 pHeader->ExemptUsage.QuadPart = 0; 02165 } 02166 else 02167 { 02168 if (pUrlEntry->size.QuadPart < pHeader->CacheUsage.QuadPart) 02169 pHeader->CacheUsage.QuadPart -= pUrlEntry->size.QuadPart; 02170 else 02171 pHeader->CacheUsage.QuadPart = 0; 02172 } 02173 02174 URLCache_DeleteEntry(pHeader, pEntry); 02175 02176 URLCache_DeleteEntryFromHash(pHashEntry); 02177 return TRUE; 02178 } 02179 02180 /*********************************************************************** 02181 * UnlockUrlCacheEntryFileA (WININET.@) 02182 * 02183 */ 02184 BOOL WINAPI UnlockUrlCacheEntryFileA( 02185 IN LPCSTR lpszUrlName, 02186 IN DWORD dwReserved 02187 ) 02188 { 02189 LPURLCACHE_HEADER pHeader; 02190 struct _HASH_ENTRY * pHashEntry; 02191 CACHEFILE_ENTRY * pEntry; 02192 URL_CACHEFILE_ENTRY * pUrlEntry; 02193 URLCACHECONTAINER * pContainer; 02194 DWORD error; 02195 02196 TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved); 02197 02198 if (dwReserved) 02199 { 02200 ERR("dwReserved != 0\n"); 02201 SetLastError(ERROR_INVALID_PARAMETER); 02202 return FALSE; 02203 } 02204 02205 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer); 02206 if (error != ERROR_SUCCESS) 02207 { 02208 SetLastError(error); 02209 return FALSE; 02210 } 02211 02212 error = URLCacheContainer_OpenIndex(pContainer); 02213 if (error != ERROR_SUCCESS) 02214 { 02215 SetLastError(error); 02216 return FALSE; 02217 } 02218 02219 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 02220 return FALSE; 02221 02222 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry)) 02223 { 02224 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02225 TRACE("entry %s not found!\n", lpszUrlName); 02226 SetLastError(ERROR_FILE_NOT_FOUND); 02227 return FALSE; 02228 } 02229 02230 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); 02231 if (pEntry->dwSignature != URL_SIGNATURE) 02232 { 02233 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02234 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD))); 02235 SetLastError(ERROR_FILE_NOT_FOUND); 02236 return FALSE; 02237 } 02238 02239 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry; 02240 02241 if (pUrlEntry->dwUseCount == 0) 02242 { 02243 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02244 return FALSE; 02245 } 02246 pUrlEntry->dwUseCount--; 02247 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount); 02248 02249 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02250 02251 return TRUE; 02252 } 02253 02254 /*********************************************************************** 02255 * UnlockUrlCacheEntryFileW (WININET.@) 02256 * 02257 */ 02258 BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved ) 02259 { 02260 LPURLCACHE_HEADER pHeader; 02261 struct _HASH_ENTRY * pHashEntry; 02262 CACHEFILE_ENTRY * pEntry; 02263 URL_CACHEFILE_ENTRY * pUrlEntry; 02264 URLCACHECONTAINER * pContainer; 02265 DWORD error; 02266 02267 TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved); 02268 02269 if (dwReserved) 02270 { 02271 ERR("dwReserved != 0\n"); 02272 SetLastError(ERROR_INVALID_PARAMETER); 02273 return FALSE; 02274 } 02275 02276 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); 02277 if (error != ERROR_SUCCESS) 02278 { 02279 SetLastError(error); 02280 return FALSE; 02281 } 02282 02283 error = URLCacheContainer_OpenIndex(pContainer); 02284 if (error != ERROR_SUCCESS) 02285 { 02286 SetLastError(error); 02287 return FALSE; 02288 } 02289 02290 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 02291 return FALSE; 02292 02293 if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry)) 02294 { 02295 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02296 TRACE("entry %s not found!\n", debugstr_w(lpszUrlName)); 02297 SetLastError(ERROR_FILE_NOT_FOUND); 02298 return FALSE; 02299 } 02300 02301 pEntry = (CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); 02302 if (pEntry->dwSignature != URL_SIGNATURE) 02303 { 02304 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02305 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->dwSignature, sizeof(DWORD))); 02306 SetLastError(ERROR_FILE_NOT_FOUND); 02307 return FALSE; 02308 } 02309 02310 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry; 02311 02312 if (pUrlEntry->dwUseCount == 0) 02313 { 02314 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02315 return FALSE; 02316 } 02317 pUrlEntry->dwUseCount--; 02318 URLCache_HashEntrySetUse(pHashEntry, pUrlEntry->dwUseCount); 02319 02320 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02321 02322 return TRUE; 02323 } 02324 02325 /*********************************************************************** 02326 * CreateUrlCacheEntryA (WININET.@) 02327 * 02328 */ 02329 BOOL WINAPI CreateUrlCacheEntryA( 02330 IN LPCSTR lpszUrlName, 02331 IN DWORD dwExpectedFileSize, 02332 IN LPCSTR lpszFileExtension, 02333 OUT LPSTR lpszFileName, 02334 IN DWORD dwReserved 02335 ) 02336 { 02337 WCHAR *url_name; 02338 WCHAR *file_extension = NULL; 02339 WCHAR file_name[MAX_PATH]; 02340 BOOL bSuccess = FALSE; 02341 DWORD dwError = 0; 02342 02343 TRACE("(%s %d %s %p %d)\n", debugstr_a(lpszUrlName), dwExpectedFileSize, 02344 debugstr_a(lpszFileExtension), lpszFileName, dwReserved); 02345 02346 if (lpszUrlName && (url_name = heap_strdupAtoW(lpszUrlName))) 02347 { 02348 if (!lpszFileExtension || (file_extension = heap_strdupAtoW(lpszFileExtension))) 02349 { 02350 if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved)) 02351 { 02352 if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH) 02353 { 02354 bSuccess = TRUE; 02355 } 02356 else 02357 { 02358 dwError = GetLastError(); 02359 } 02360 } 02361 else 02362 { 02363 dwError = GetLastError(); 02364 } 02365 HeapFree(GetProcessHeap(), 0, file_extension); 02366 } 02367 else 02368 { 02369 dwError = GetLastError(); 02370 } 02371 HeapFree(GetProcessHeap(), 0, url_name); 02372 if (!bSuccess) 02373 SetLastError(dwError); 02374 } 02375 return bSuccess; 02376 } 02377 /*********************************************************************** 02378 * CreateUrlCacheEntryW (WININET.@) 02379 * 02380 */ 02381 BOOL WINAPI CreateUrlCacheEntryW( 02382 IN LPCWSTR lpszUrlName, 02383 IN DWORD dwExpectedFileSize, 02384 IN LPCWSTR lpszFileExtension, 02385 OUT LPWSTR lpszFileName, 02386 IN DWORD dwReserved 02387 ) 02388 { 02389 URLCACHECONTAINER * pContainer; 02390 LPURLCACHE_HEADER pHeader; 02391 CHAR szFile[MAX_PATH]; 02392 WCHAR szExtension[MAX_PATH]; 02393 LPCWSTR lpszUrlPart; 02394 LPCWSTR lpszUrlEnd; 02395 LPCWSTR lpszFileNameExtension; 02396 LPWSTR lpszFileNameNoPath; 02397 int i; 02398 int countnoextension; 02399 BYTE CacheDir; 02400 LONG lBufferSize; 02401 BOOL bFound = FALSE; 02402 int count; 02403 DWORD error; 02404 HANDLE hFile; 02405 FILETIME ft; 02406 02407 static const WCHAR szWWW[] = {'w','w','w',0}; 02408 static const WCHAR fmt[] = {'%','0','8','X','%','s',0}; 02409 02410 TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n", 02411 debugstr_w(lpszUrlName), 02412 dwExpectedFileSize, 02413 debugstr_w(lpszFileExtension), 02414 lpszFileName, 02415 dwReserved); 02416 02417 if (dwReserved) 02418 FIXME("dwReserved 0x%08x\n", dwReserved); 02419 02420 lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName); 02421 02422 if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\')) 02423 lpszUrlEnd--; 02424 02425 lpszUrlPart = memchrW(lpszUrlName, '?', lpszUrlEnd - lpszUrlName); 02426 if (!lpszUrlPart) 02427 lpszUrlPart = memchrW(lpszUrlName, '#', lpszUrlEnd - lpszUrlName); 02428 if (lpszUrlPart) 02429 lpszUrlEnd = lpszUrlPart; 02430 02431 for (lpszUrlPart = lpszUrlEnd; 02432 (lpszUrlPart >= lpszUrlName); 02433 lpszUrlPart--) 02434 { 02435 if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1)) 02436 { 02437 bFound = TRUE; 02438 lpszUrlPart++; 02439 break; 02440 } 02441 } 02442 if (!lstrcmpW(lpszUrlPart, szWWW)) 02443 { 02444 lpszUrlPart += lstrlenW(szWWW); 02445 } 02446 02447 count = lpszUrlEnd - lpszUrlPart; 02448 02449 if (bFound && (count < MAX_PATH)) 02450 { 02451 int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL); 02452 if (!len) 02453 return FALSE; 02454 szFile[len] = '\0'; 02455 while(len && szFile[--len] == '/') szFile[len] = '\0'; 02456 02457 /* FIXME: get rid of illegal characters like \, / and : */ 02458 } 02459 else 02460 { 02461 FIXME("need to generate a random filename\n"); 02462 } 02463 02464 TRACE("File name: %s\n", debugstr_a(szFile)); 02465 02466 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); 02467 if (error != ERROR_SUCCESS) 02468 { 02469 SetLastError(error); 02470 return FALSE; 02471 } 02472 02473 error = URLCacheContainer_OpenIndex(pContainer); 02474 if (error != ERROR_SUCCESS) 02475 { 02476 SetLastError(error); 02477 return FALSE; 02478 } 02479 02480 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 02481 return FALSE; 02482 02483 CacheDir = (BYTE)(rand() % pHeader->DirectoryCount); 02484 02485 lBufferSize = MAX_PATH * sizeof(WCHAR); 02486 if (!URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize)) 02487 { 02488 WARN("Failed to get full path for filename %s, needed %u bytes.\n", 02489 debugstr_a(szFile), lBufferSize); 02490 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02491 return FALSE; 02492 } 02493 02494 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02495 02496 for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2; 02497 lpszFileNameNoPath >= lpszFileName; 02498 --lpszFileNameNoPath) 02499 { 02500 if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\') 02501 break; 02502 } 02503 02504 countnoextension = lstrlenW(lpszFileNameNoPath); 02505 lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath); 02506 if (lpszFileNameExtension) 02507 countnoextension -= lstrlenW(lpszFileNameExtension); 02508 *szExtension = '\0'; 02509 02510 if (lpszFileExtension) 02511 { 02512 szExtension[0] = '.'; 02513 lstrcpyW(szExtension+1, lpszFileExtension); 02514 } 02515 02516 for (i = 0; i < 255; i++) 02517 { 02518 static const WCHAR szFormat[] = {'[','%','u',']','%','s',0}; 02519 WCHAR *p; 02520 02521 wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension); 02522 for (p = lpszFileNameNoPath + 1; *p; p++) 02523 { 02524 switch (*p) 02525 { 02526 case '<': case '>': 02527 case ':': case '"': 02528 case '/': case '\\': 02529 case '|': case '?': 02530 case '*': 02531 *p = '_'; break; 02532 default: break; 02533 } 02534 } 02535 if (p[-1] == ' ' || p[-1] == '.') p[-1] = '_'; 02536 02537 TRACE("Trying: %s\n", debugstr_w(lpszFileName)); 02538 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL); 02539 if (hFile != INVALID_HANDLE_VALUE) 02540 { 02541 CloseHandle(hFile); 02542 return TRUE; 02543 } 02544 } 02545 02546 GetSystemTimeAsFileTime(&ft); 02547 wsprintfW(lpszFileNameNoPath + countnoextension, fmt, ft.dwLowDateTime, szExtension); 02548 02549 TRACE("Trying: %s\n", debugstr_w(lpszFileName)); 02550 hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL); 02551 if (hFile != INVALID_HANDLE_VALUE) 02552 { 02553 CloseHandle(hFile); 02554 return TRUE; 02555 } 02556 02557 WARN("Could not find a unique filename\n"); 02558 return FALSE; 02559 } 02560 02561 02562 /*********************************************************************** 02563 * CommitUrlCacheEntryInternal (Compensates for an MS bug) 02564 * 02565 * The bug we are compensating for is that some drongo at Microsoft 02566 * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA. 02567 * As a consequence, CommitUrlCacheEntryA has been effectively 02568 * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW 02569 * is still defined as LPCWSTR. The result (other than madness) is 02570 * that we always need to store lpHeaderInfo in CP_ACP rather than 02571 * in UTF16, and we need to avoid converting lpHeaderInfo in 02572 * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the 02573 * result will lose data for arbitrary binary data. 02574 * 02575 */ 02576 static BOOL CommitUrlCacheEntryInternal( 02577 IN LPCWSTR lpszUrlName, 02578 IN LPCWSTR lpszLocalFileName, 02579 IN FILETIME ExpireTime, 02580 IN FILETIME LastModifiedTime, 02581 IN DWORD CacheEntryType, 02582 IN LPBYTE lpHeaderInfo, 02583 IN DWORD dwHeaderSize, 02584 IN LPCWSTR lpszFileExtension, 02585 IN LPCWSTR lpszOriginalUrl 02586 ) 02587 { 02588 URLCACHECONTAINER * pContainer; 02589 LPURLCACHE_HEADER pHeader; 02590 struct _HASH_ENTRY * pHashEntry; 02591 CACHEFILE_ENTRY * pEntry; 02592 URL_CACHEFILE_ENTRY * pUrlEntry; 02593 DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry)); 02594 DWORD dwOffsetLocalFileName = 0; 02595 DWORD dwOffsetHeader = 0; 02596 DWORD dwOffsetFileExtension = 0; 02597 LARGE_INTEGER file_size; 02598 BYTE cDirectory = 0; 02599 char achFile[MAX_PATH]; 02600 LPSTR lpszUrlNameA = NULL; 02601 LPSTR lpszFileExtensionA = NULL; 02602 char *pchLocalFileName = 0; 02603 DWORD error; 02604 02605 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n", 02606 debugstr_w(lpszUrlName), 02607 debugstr_w(lpszLocalFileName), 02608 CacheEntryType, 02609 lpHeaderInfo, 02610 dwHeaderSize, 02611 debugstr_w(lpszFileExtension), 02612 debugstr_w(lpszOriginalUrl)); 02613 02614 if (CacheEntryType & STICKY_CACHE_ENTRY && !lpszLocalFileName) 02615 { 02616 SetLastError(ERROR_INVALID_PARAMETER); 02617 return FALSE; 02618 } 02619 if (lpszOriginalUrl) 02620 WARN(": lpszOriginalUrl ignored\n"); 02621 02622 file_size.QuadPart = 0; 02623 if (lpszLocalFileName) 02624 { 02625 HANDLE hFile; 02626 02627 hFile = CreateFileW(lpszLocalFileName, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); 02628 if (hFile == INVALID_HANDLE_VALUE) 02629 { 02630 ERR("couldn't open file %s (error is %d)\n", debugstr_w(lpszLocalFileName), GetLastError()); 02631 return FALSE; 02632 } 02633 02634 /* Get file size */ 02635 if (!GetFileSizeEx(hFile, &file_size)) 02636 { 02637 ERR("couldn't get file size (error is %d)\n", GetLastError()); 02638 CloseHandle(hFile); 02639 return FALSE; 02640 } 02641 02642 CloseHandle(hFile); 02643 } 02644 02645 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); 02646 if (error != ERROR_SUCCESS) 02647 { 02648 SetLastError(error); 02649 return FALSE; 02650 } 02651 02652 error = URLCacheContainer_OpenIndex(pContainer); 02653 if (error != ERROR_SUCCESS) 02654 { 02655 SetLastError(error); 02656 return FALSE; 02657 } 02658 02659 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 02660 return FALSE; 02661 02662 lpszUrlNameA = heap_strdupWtoA(lpszUrlName); 02663 if (!lpszUrlNameA) 02664 { 02665 error = GetLastError(); 02666 goto cleanup; 02667 } 02668 02669 if (lpszFileExtension && !(lpszFileExtensionA = heap_strdupWtoA(lpszFileExtension))) 02670 { 02671 error = GetLastError(); 02672 goto cleanup; 02673 } 02674 02675 if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry)) 02676 { 02677 FIXME("entry already in cache - don't know what to do!\n"); 02678 /* 02679 * SetLastError(ERROR_FILE_NOT_FOUND); 02680 * return FALSE; 02681 */ 02682 goto cleanup; 02683 } 02684 02685 if (lpszLocalFileName) 02686 { 02687 BOOL bFound = FALSE; 02688 02689 if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path))) 02690 { 02691 ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path)); 02692 error = ERROR_INVALID_PARAMETER; 02693 goto cleanup; 02694 } 02695 02696 /* skip container path prefix */ 02697 lpszLocalFileName += lstrlenW(pContainer->path); 02698 02699 WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL); 02700 pchLocalFileName = achFile; 02701 02702 for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++) 02703 { 02704 if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH)) 02705 { 02706 bFound = TRUE; 02707 break; 02708 } 02709 } 02710 02711 if (!bFound) 02712 { 02713 ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName)); 02714 error = ERROR_INVALID_PARAMETER; 02715 goto cleanup; 02716 } 02717 02718 lpszLocalFileName += (DIR_LENGTH + 1); /* "1234WXYZ\" */ 02719 } 02720 02721 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1); 02722 if (lpszLocalFileName) 02723 { 02724 dwOffsetLocalFileName = dwBytesNeeded; 02725 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1); 02726 } 02727 if (lpHeaderInfo) 02728 { 02729 dwOffsetHeader = dwBytesNeeded; 02730 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize); 02731 } 02732 if (lpszFileExtensionA) 02733 { 02734 dwOffsetFileExtension = dwBytesNeeded; 02735 dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1); 02736 } 02737 02738 /* round up to next block */ 02739 if (dwBytesNeeded % BLOCKSIZE) 02740 { 02741 dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE; 02742 dwBytesNeeded += BLOCKSIZE; 02743 } 02744 02745 if (!URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry)) 02746 { 02747 ERR("no free entries\n"); 02748 error = ERROR_DISK_FULL; 02749 goto cleanup; 02750 } 02751 02752 /* FindFirstFreeEntry fills in blocks used */ 02753 pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry; 02754 pUrlEntry->CacheFileEntry.dwSignature = URL_SIGNATURE; 02755 pUrlEntry->CacheDir = cDirectory; 02756 pUrlEntry->CacheEntryType = CacheEntryType; 02757 pUrlEntry->dwHeaderInfoSize = dwHeaderSize; 02758 if (CacheEntryType & STICKY_CACHE_ENTRY) 02759 { 02760 /* Sticky entries have a default exempt time of one day */ 02761 pUrlEntry->dwExemptDelta = 86400; 02762 } 02763 else 02764 pUrlEntry->dwExemptDelta = 0; 02765 pUrlEntry->dwHitRate = 0; 02766 pUrlEntry->dwOffsetFileExtension = dwOffsetFileExtension; 02767 pUrlEntry->dwOffsetHeaderInfo = dwOffsetHeader; 02768 pUrlEntry->dwOffsetLocalName = dwOffsetLocalFileName; 02769 pUrlEntry->dwOffsetUrl = DWORD_ALIGN(sizeof(*pUrlEntry)); 02770 pUrlEntry->size.QuadPart = file_size.QuadPart; 02771 pUrlEntry->dwUseCount = 0; 02772 GetSystemTimeAsFileTime(&pUrlEntry->LastAccessTime); 02773 pUrlEntry->LastModifiedTime = LastModifiedTime; 02774 URLCache_FileTimeToDosDateTime(&pUrlEntry->LastAccessTime, &pUrlEntry->wLastSyncDate, &pUrlEntry->wLastSyncTime); 02775 URLCache_FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->wExpiredDate, &pUrlEntry->wExpiredTime); 02776 pUrlEntry->wUnknownDate = pUrlEntry->wLastSyncDate; 02777 pUrlEntry->wUnknownTime = pUrlEntry->wLastSyncTime; 02778 02779 /*** Unknowns ***/ 02780 pUrlEntry->dwUnknown1 = 0; 02781 pUrlEntry->dwUnknown2 = 0; 02782 pUrlEntry->dwUnknown3 = 0x60; 02783 pUrlEntry->Unknown4 = 0; 02784 pUrlEntry->wUnknown5 = 0x1010; 02785 pUrlEntry->dwUnknown7 = 0; 02786 pUrlEntry->dwUnknown8 = 0; 02787 02788 02789 strcpy((LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl, lpszUrlNameA); 02790 if (dwOffsetLocalFileName) 02791 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName + DIR_LENGTH + 1); 02792 if (dwOffsetHeader) 02793 memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize); 02794 if (dwOffsetFileExtension) 02795 strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA); 02796 02797 error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA, 02798 (DWORD)((LPBYTE)pUrlEntry - (LPBYTE)pHeader)); 02799 if (error != ERROR_SUCCESS) 02800 URLCache_DeleteEntry(pHeader, &pUrlEntry->CacheFileEntry); 02801 else 02802 { 02803 if (pUrlEntry->CacheDir < pHeader->DirectoryCount) 02804 pHeader->directory_data[pUrlEntry->CacheDir].dwNumFiles++; 02805 if (CacheEntryType & STICKY_CACHE_ENTRY) 02806 pHeader->ExemptUsage.QuadPart += file_size.QuadPart; 02807 else 02808 pHeader->CacheUsage.QuadPart += file_size.QuadPart; 02809 if (pHeader->CacheUsage.QuadPart + pHeader->ExemptUsage.QuadPart > 02810 pHeader->CacheLimit.QuadPart) 02811 FIXME("file of size %s bytes fills cache\n", wine_dbgstr_longlong(file_size.QuadPart)); 02812 } 02813 02814 cleanup: 02815 URLCacheContainer_UnlockIndex(pContainer, pHeader); 02816 HeapFree(GetProcessHeap(), 0, lpszUrlNameA); 02817 HeapFree(GetProcessHeap(), 0, lpszFileExtensionA); 02818 02819 if (error == ERROR_SUCCESS) 02820 return TRUE; 02821 else 02822 { 02823 SetLastError(error); 02824 return FALSE; 02825 } 02826 } 02827 02828 /*********************************************************************** 02829 * CommitUrlCacheEntryA (WININET.@) 02830 * 02831 */ 02832 BOOL WINAPI CommitUrlCacheEntryA( 02833 IN LPCSTR lpszUrlName, 02834 IN LPCSTR lpszLocalFileName, 02835 IN FILETIME ExpireTime, 02836 IN FILETIME LastModifiedTime, 02837 IN DWORD CacheEntryType, 02838 IN LPBYTE lpHeaderInfo, 02839 IN DWORD dwHeaderSize, 02840 IN LPCSTR lpszFileExtension, 02841 IN LPCSTR lpszOriginalUrl 02842 ) 02843 { 02844 WCHAR *url_name = NULL; 02845 WCHAR *local_file_name = NULL; 02846 WCHAR *original_url = NULL; 02847 WCHAR *file_extension = NULL; 02848 BOOL bSuccess = FALSE; 02849 02850 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n", 02851 debugstr_a(lpszUrlName), 02852 debugstr_a(lpszLocalFileName), 02853 CacheEntryType, 02854 lpHeaderInfo, 02855 dwHeaderSize, 02856 debugstr_a(lpszFileExtension), 02857 debugstr_a(lpszOriginalUrl)); 02858 02859 url_name = heap_strdupAtoW(lpszUrlName); 02860 if (!url_name) 02861 goto cleanup; 02862 02863 if (lpszLocalFileName) 02864 { 02865 local_file_name = heap_strdupAtoW(lpszLocalFileName); 02866 if (!local_file_name) 02867 goto cleanup; 02868 } 02869 if (lpszFileExtension) 02870 { 02871 file_extension = heap_strdupAtoW(lpszFileExtension); 02872 if (!file_extension) 02873 goto cleanup; 02874 } 02875 if (lpszOriginalUrl) 02876 { 02877 original_url = heap_strdupAtoW(lpszOriginalUrl); 02878 if (!original_url) 02879 goto cleanup; 02880 } 02881 02882 bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime, 02883 CacheEntryType, lpHeaderInfo, dwHeaderSize, 02884 file_extension, original_url); 02885 02886 cleanup: 02887 HeapFree(GetProcessHeap(), 0, original_url); 02888 HeapFree(GetProcessHeap(), 0, file_extension); 02889 HeapFree(GetProcessHeap(), 0, local_file_name); 02890 HeapFree(GetProcessHeap(), 0, url_name); 02891 02892 return bSuccess; 02893 } 02894 02895 /*********************************************************************** 02896 * CommitUrlCacheEntryW (WININET.@) 02897 * 02898 */ 02899 BOOL WINAPI CommitUrlCacheEntryW( 02900 IN LPCWSTR lpszUrlName, 02901 IN LPCWSTR lpszLocalFileName, 02902 IN FILETIME ExpireTime, 02903 IN FILETIME LastModifiedTime, 02904 IN DWORD CacheEntryType, 02905 IN LPWSTR lpHeaderInfo, 02906 IN DWORD dwHeaderSize, 02907 IN LPCWSTR lpszFileExtension, 02908 IN LPCWSTR lpszOriginalUrl 02909 ) 02910 { 02911 DWORD dwError = 0; 02912 BOOL bSuccess = FALSE; 02913 DWORD len = 0; 02914 CHAR *header_info = NULL; 02915 02916 TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n", 02917 debugstr_w(lpszUrlName), 02918 debugstr_w(lpszLocalFileName), 02919 CacheEntryType, 02920 lpHeaderInfo, 02921 dwHeaderSize, 02922 debugstr_w(lpszFileExtension), 02923 debugstr_w(lpszOriginalUrl)); 02924 02925 if (!lpHeaderInfo || (header_info = heap_strdupWtoA(lpHeaderInfo))) 02926 { 02927 if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime, 02928 CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl)) 02929 { 02930 bSuccess = TRUE; 02931 } 02932 else 02933 { 02934 dwError = GetLastError(); 02935 } 02936 if (header_info) 02937 { 02938 HeapFree(GetProcessHeap(), 0, header_info); 02939 if (!bSuccess) 02940 SetLastError(dwError); 02941 } 02942 } 02943 return bSuccess; 02944 } 02945 02946 /*********************************************************************** 02947 * ReadUrlCacheEntryStream (WININET.@) 02948 * 02949 */ 02950 BOOL WINAPI ReadUrlCacheEntryStream( 02951 IN HANDLE hUrlCacheStream, 02952 IN DWORD dwLocation, 02953 IN OUT LPVOID lpBuffer, 02954 IN OUT LPDWORD lpdwLen, 02955 IN DWORD dwReserved 02956 ) 02957 { 02958 /* Get handle to file from 'stream' */ 02959 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream; 02960 02961 if (dwReserved != 0) 02962 { 02963 ERR("dwReserved != 0\n"); 02964 SetLastError(ERROR_INVALID_PARAMETER); 02965 return FALSE; 02966 } 02967 02968 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH)) 02969 { 02970 SetLastError(ERROR_INVALID_HANDLE); 02971 return FALSE; 02972 } 02973 02974 if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) 02975 return FALSE; 02976 return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL); 02977 } 02978 02979 /*********************************************************************** 02980 * RetrieveUrlCacheEntryStreamA (WININET.@) 02981 * 02982 */ 02983 HANDLE WINAPI RetrieveUrlCacheEntryStreamA( 02984 IN LPCSTR lpszUrlName, 02985 OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, 02986 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize, 02987 IN BOOL fRandomRead, 02988 IN DWORD dwReserved 02989 ) 02990 { 02991 /* NOTE: this is not the same as the way that the native 02992 * version allocates 'stream' handles. I did it this way 02993 * as it is much easier and no applications should depend 02994 * on this behaviour. (Native version appears to allocate 02995 * indices into a table) 02996 */ 02997 STREAM_HANDLE * pStream; 02998 HANDLE hFile; 02999 03000 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, 03001 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved ); 03002 03003 if (!RetrieveUrlCacheEntryFileA(lpszUrlName, 03004 lpCacheEntryInfo, 03005 lpdwCacheEntryInfoBufferSize, 03006 dwReserved)) 03007 { 03008 return NULL; 03009 } 03010 03011 hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName, 03012 GENERIC_READ, 03013 FILE_SHARE_READ, 03014 NULL, 03015 OPEN_EXISTING, 03016 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0, 03017 NULL); 03018 if (hFile == INVALID_HANDLE_VALUE) 03019 return FALSE; 03020 03021 /* allocate handle storage space */ 03022 pStream = heap_alloc(sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR)); 03023 if (!pStream) 03024 { 03025 CloseHandle(hFile); 03026 SetLastError(ERROR_OUTOFMEMORY); 03027 return FALSE; 03028 } 03029 03030 pStream->hFile = hFile; 03031 strcpy(pStream->lpszUrl, lpszUrlName); 03032 return pStream; 03033 } 03034 03035 /*********************************************************************** 03036 * RetrieveUrlCacheEntryStreamW (WININET.@) 03037 * 03038 */ 03039 HANDLE WINAPI RetrieveUrlCacheEntryStreamW( 03040 IN LPCWSTR lpszUrlName, 03041 OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, 03042 IN OUT LPDWORD lpdwCacheEntryInfoBufferSize, 03043 IN BOOL fRandomRead, 03044 IN DWORD dwReserved 03045 ) 03046 { 03047 DWORD size; 03048 int url_len; 03049 /* NOTE: this is not the same as the way that the native 03050 * version allocates 'stream' handles. I did it this way 03051 * as it is much easier and no applications should depend 03052 * on this behaviour. (Native version appears to allocate 03053 * indices into a table) 03054 */ 03055 STREAM_HANDLE * pStream; 03056 HANDLE hFile; 03057 03058 TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo, 03059 lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved ); 03060 03061 if (!RetrieveUrlCacheEntryFileW(lpszUrlName, 03062 lpCacheEntryInfo, 03063 lpdwCacheEntryInfoBufferSize, 03064 dwReserved)) 03065 { 03066 return NULL; 03067 } 03068 03069 hFile = CreateFileW(lpCacheEntryInfo->lpszLocalFileName, 03070 GENERIC_READ, 03071 FILE_SHARE_READ, 03072 NULL, 03073 OPEN_EXISTING, 03074 fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0, 03075 NULL); 03076 if (hFile == INVALID_HANDLE_VALUE) 03077 return FALSE; 03078 03079 /* allocate handle storage space */ 03080 size = sizeof(STREAM_HANDLE); 03081 url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL); 03082 size += url_len; 03083 pStream = heap_alloc(size); 03084 if (!pStream) 03085 { 03086 CloseHandle(hFile); 03087 SetLastError(ERROR_OUTOFMEMORY); 03088 return FALSE; 03089 } 03090 03091 pStream->hFile = hFile; 03092 WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, pStream->lpszUrl, url_len, NULL, NULL); 03093 return pStream; 03094 } 03095 03096 /*********************************************************************** 03097 * UnlockUrlCacheEntryStream (WININET.@) 03098 * 03099 */ 03100 BOOL WINAPI UnlockUrlCacheEntryStream( 03101 IN HANDLE hUrlCacheStream, 03102 IN DWORD dwReserved 03103 ) 03104 { 03105 STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream; 03106 03107 if (dwReserved != 0) 03108 { 03109 ERR("dwReserved != 0\n"); 03110 SetLastError(ERROR_INVALID_PARAMETER); 03111 return FALSE; 03112 } 03113 03114 if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH)) 03115 { 03116 SetLastError(ERROR_INVALID_HANDLE); 03117 return FALSE; 03118 } 03119 03120 if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0)) 03121 return FALSE; 03122 03123 /* close file handle */ 03124 CloseHandle(pStream->hFile); 03125 03126 /* free allocated space */ 03127 HeapFree(GetProcessHeap(), 0, pStream); 03128 03129 return TRUE; 03130 } 03131 03132 03133 /*********************************************************************** 03134 * DeleteUrlCacheEntryA (WININET.@) 03135 * 03136 */ 03137 BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName) 03138 { 03139 URLCACHECONTAINER * pContainer; 03140 LPURLCACHE_HEADER pHeader; 03141 struct _HASH_ENTRY * pHashEntry; 03142 DWORD error; 03143 BOOL ret; 03144 03145 TRACE("(%s)\n", debugstr_a(lpszUrlName)); 03146 03147 error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer); 03148 if (error != ERROR_SUCCESS) 03149 { 03150 SetLastError(error); 03151 return FALSE; 03152 } 03153 03154 error = URLCacheContainer_OpenIndex(pContainer); 03155 if (error != ERROR_SUCCESS) 03156 { 03157 SetLastError(error); 03158 return FALSE; 03159 } 03160 03161 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 03162 return FALSE; 03163 03164 if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry)) 03165 { 03166 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03167 TRACE("entry %s not found!\n", lpszUrlName); 03168 SetLastError(ERROR_FILE_NOT_FOUND); 03169 return FALSE; 03170 } 03171 03172 ret = DeleteUrlCacheEntryInternal(pHeader, pHashEntry); 03173 03174 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03175 03176 return ret; 03177 } 03178 03179 /*********************************************************************** 03180 * DeleteUrlCacheEntryW (WININET.@) 03181 * 03182 */ 03183 BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName) 03184 { 03185 URLCACHECONTAINER * pContainer; 03186 LPURLCACHE_HEADER pHeader; 03187 struct _HASH_ENTRY * pHashEntry; 03188 LPSTR urlA; 03189 DWORD error; 03190 BOOL ret; 03191 03192 TRACE("(%s)\n", debugstr_w(lpszUrlName)); 03193 03194 urlA = heap_strdupWtoA(lpszUrlName); 03195 if (!urlA) 03196 { 03197 SetLastError(ERROR_OUTOFMEMORY); 03198 return FALSE; 03199 } 03200 03201 error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); 03202 if (error != ERROR_SUCCESS) 03203 { 03204 HeapFree(GetProcessHeap(), 0, urlA); 03205 SetLastError(error); 03206 return FALSE; 03207 } 03208 03209 error = URLCacheContainer_OpenIndex(pContainer); 03210 if (error != ERROR_SUCCESS) 03211 { 03212 HeapFree(GetProcessHeap(), 0, urlA); 03213 SetLastError(error); 03214 return FALSE; 03215 } 03216 03217 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 03218 { 03219 HeapFree(GetProcessHeap(), 0, urlA); 03220 return FALSE; 03221 } 03222 03223 if (!URLCache_FindHash(pHeader, urlA, &pHashEntry)) 03224 { 03225 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03226 TRACE("entry %s not found!\n", debugstr_a(urlA)); 03227 HeapFree(GetProcessHeap(), 0, urlA); 03228 SetLastError(ERROR_FILE_NOT_FOUND); 03229 return FALSE; 03230 } 03231 03232 ret = DeleteUrlCacheEntryInternal(pHeader, pHashEntry); 03233 03234 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03235 03236 HeapFree(GetProcessHeap(), 0, urlA); 03237 return ret; 03238 } 03239 03240 BOOL WINAPI DeleteUrlCacheContainerA(DWORD d1, DWORD d2) 03241 { 03242 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2); 03243 return TRUE; 03244 } 03245 03246 BOOL WINAPI DeleteUrlCacheContainerW(DWORD d1, DWORD d2) 03247 { 03248 FIXME("(0x%08x, 0x%08x) stub\n", d1, d2); 03249 return TRUE; 03250 } 03251 03252 /*********************************************************************** 03253 * CreateCacheContainerA (WININET.@) 03254 */ 03255 BOOL WINAPI CreateUrlCacheContainerA(DWORD d1, DWORD d2, DWORD d3, DWORD d4, 03256 DWORD d5, DWORD d6, DWORD d7, DWORD d8) 03257 { 03258 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n", 03259 d1, d2, d3, d4, d5, d6, d7, d8); 03260 return TRUE; 03261 } 03262 03263 /*********************************************************************** 03264 * CreateCacheContainerW (WININET.@) 03265 */ 03266 BOOL WINAPI CreateUrlCacheContainerW(DWORD d1, DWORD d2, DWORD d3, DWORD d4, 03267 DWORD d5, DWORD d6, DWORD d7, DWORD d8) 03268 { 03269 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x) stub\n", 03270 d1, d2, d3, d4, d5, d6, d7, d8); 03271 return TRUE; 03272 } 03273 03274 /*********************************************************************** 03275 * FindFirstUrlCacheContainerA (WININET.@) 03276 */ 03277 HANDLE WINAPI FindFirstUrlCacheContainerA( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 ) 03278 { 03279 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 ); 03280 return NULL; 03281 } 03282 03283 /*********************************************************************** 03284 * FindFirstUrlCacheContainerW (WININET.@) 03285 */ 03286 HANDLE WINAPI FindFirstUrlCacheContainerW( LPVOID p1, LPVOID p2, LPVOID p3, DWORD d1 ) 03287 { 03288 FIXME("(%p, %p, %p, 0x%08x) stub\n", p1, p2, p3, d1 ); 03289 return NULL; 03290 } 03291 03292 /*********************************************************************** 03293 * FindNextUrlCacheContainerA (WININET.@) 03294 */ 03295 BOOL WINAPI FindNextUrlCacheContainerA( HANDLE handle, LPVOID p1, LPVOID p2 ) 03296 { 03297 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 ); 03298 return FALSE; 03299 } 03300 03301 /*********************************************************************** 03302 * FindNextUrlCacheContainerW (WININET.@) 03303 */ 03304 BOOL WINAPI FindNextUrlCacheContainerW( HANDLE handle, LPVOID p1, LPVOID p2 ) 03305 { 03306 FIXME("(%p, %p, %p) stub\n", handle, p1, p2 ); 03307 return FALSE; 03308 } 03309 03310 HANDLE WINAPI FindFirstUrlCacheEntryExA( 03311 LPCSTR lpszUrlSearchPattern, 03312 DWORD dwFlags, 03313 DWORD dwFilter, 03314 GROUPID GroupId, 03315 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, 03316 LPDWORD lpdwFirstCacheEntryInfoBufferSize, 03317 LPVOID lpReserved, 03318 LPDWORD pcbReserved2, 03319 LPVOID lpReserved3 03320 ) 03321 { 03322 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_a(lpszUrlSearchPattern), 03323 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo, 03324 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3); 03325 SetLastError(ERROR_FILE_NOT_FOUND); 03326 return NULL; 03327 } 03328 03329 HANDLE WINAPI FindFirstUrlCacheEntryExW( 03330 LPCWSTR lpszUrlSearchPattern, 03331 DWORD dwFlags, 03332 DWORD dwFilter, 03333 GROUPID GroupId, 03334 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, 03335 LPDWORD lpdwFirstCacheEntryInfoBufferSize, 03336 LPVOID lpReserved, 03337 LPDWORD pcbReserved2, 03338 LPVOID lpReserved3 03339 ) 03340 { 03341 FIXME("(%s, 0x%08x, 0x%08x, 0x%08x%08x, %p, %p, %p, %p, %p) stub\n", debugstr_w(lpszUrlSearchPattern), 03342 dwFlags, dwFilter, (ULONG)(GroupId >> 32), (ULONG)GroupId, lpFirstCacheEntryInfo, 03343 lpdwFirstCacheEntryInfoBufferSize, lpReserved, pcbReserved2,lpReserved3); 03344 SetLastError(ERROR_FILE_NOT_FOUND); 03345 return NULL; 03346 } 03347 03348 #define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD 03349 03350 typedef struct URLCacheFindEntryHandle 03351 { 03352 DWORD dwMagic; 03353 LPWSTR lpszUrlSearchPattern; 03354 DWORD dwContainerIndex; 03355 DWORD dwHashTableIndex; 03356 DWORD dwHashEntryIndex; 03357 } URLCacheFindEntryHandle; 03358 03359 /*********************************************************************** 03360 * FindFirstUrlCacheEntryA (WININET.@) 03361 * 03362 */ 03363 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern, 03364 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize) 03365 { 03366 URLCacheFindEntryHandle *pEntryHandle; 03367 03368 TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize); 03369 03370 pEntryHandle = heap_alloc(sizeof(*pEntryHandle)); 03371 if (!pEntryHandle) 03372 return NULL; 03373 03374 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC; 03375 if (lpszUrlSearchPattern) 03376 { 03377 pEntryHandle->lpszUrlSearchPattern = heap_strdupAtoW(lpszUrlSearchPattern); 03378 if (!pEntryHandle->lpszUrlSearchPattern) 03379 { 03380 HeapFree(GetProcessHeap(), 0, pEntryHandle); 03381 return NULL; 03382 } 03383 } 03384 else 03385 pEntryHandle->lpszUrlSearchPattern = NULL; 03386 pEntryHandle->dwContainerIndex = 0; 03387 pEntryHandle->dwHashTableIndex = 0; 03388 pEntryHandle->dwHashEntryIndex = 0; 03389 03390 if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize)) 03391 { 03392 HeapFree(GetProcessHeap(), 0, pEntryHandle); 03393 return NULL; 03394 } 03395 return pEntryHandle; 03396 } 03397 03398 /*********************************************************************** 03399 * FindFirstUrlCacheEntryW (WININET.@) 03400 * 03401 */ 03402 INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern, 03403 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize) 03404 { 03405 URLCacheFindEntryHandle *pEntryHandle; 03406 03407 TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize); 03408 03409 pEntryHandle = heap_alloc(sizeof(*pEntryHandle)); 03410 if (!pEntryHandle) 03411 return NULL; 03412 03413 pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC; 03414 if (lpszUrlSearchPattern) 03415 { 03416 pEntryHandle->lpszUrlSearchPattern = heap_strdupW(lpszUrlSearchPattern); 03417 if (!pEntryHandle->lpszUrlSearchPattern) 03418 { 03419 HeapFree(GetProcessHeap(), 0, pEntryHandle); 03420 return NULL; 03421 } 03422 } 03423 else 03424 pEntryHandle->lpszUrlSearchPattern = NULL; 03425 pEntryHandle->dwContainerIndex = 0; 03426 pEntryHandle->dwHashTableIndex = 0; 03427 pEntryHandle->dwHashEntryIndex = 0; 03428 03429 if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize)) 03430 { 03431 HeapFree(GetProcessHeap(), 0, pEntryHandle); 03432 return NULL; 03433 } 03434 return pEntryHandle; 03435 } 03436 03437 static BOOL FindNextUrlCacheEntryInternal( 03438 HANDLE hEnumHandle, 03439 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo, 03440 LPDWORD lpdwNextCacheEntryInfoBufferSize, 03441 BOOL unicode) 03442 { 03443 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle; 03444 URLCACHECONTAINER * pContainer; 03445 03446 if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC) 03447 { 03448 SetLastError(ERROR_INVALID_HANDLE); 03449 return FALSE; 03450 } 03451 03452 for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer); 03453 pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0) 03454 { 03455 LPURLCACHE_HEADER pHeader; 03456 HASH_CACHEFILE_ENTRY *pHashTableEntry; 03457 DWORD error; 03458 03459 error = URLCacheContainer_OpenIndex(pContainer); 03460 if (error != ERROR_SUCCESS) 03461 { 03462 SetLastError(error); 03463 return FALSE; 03464 } 03465 03466 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 03467 return FALSE; 03468 03469 for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry); 03470 pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0) 03471 { 03472 const struct _HASH_ENTRY *pHashEntry = NULL; 03473 for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry); 03474 pEntryHandle->dwHashEntryIndex++) 03475 { 03476 const URL_CACHEFILE_ENTRY *pUrlEntry; 03477 const CACHEFILE_ENTRY *pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); 03478 03479 if (pEntry->dwSignature != URL_SIGNATURE) 03480 continue; 03481 03482 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry; 03483 TRACE("Found URL: %s\n", 03484 debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetUrl)); 03485 TRACE("Header info: %s\n", 03486 debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo)); 03487 03488 error = URLCache_CopyEntry( 03489 pContainer, 03490 pHeader, 03491 lpNextCacheEntryInfo, 03492 lpdwNextCacheEntryInfoBufferSize, 03493 pUrlEntry, 03494 unicode); 03495 if (error != ERROR_SUCCESS) 03496 { 03497 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03498 SetLastError(error); 03499 return FALSE; 03500 } 03501 TRACE("Local File Name: %s\n", 03502 debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->dwOffsetLocalName)); 03503 03504 /* increment the current index so that next time the function 03505 * is called the next entry is returned */ 03506 pEntryHandle->dwHashEntryIndex++; 03507 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03508 return TRUE; 03509 } 03510 } 03511 03512 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03513 } 03514 03515 SetLastError(ERROR_NO_MORE_ITEMS); 03516 return FALSE; 03517 } 03518 03519 /*********************************************************************** 03520 * FindNextUrlCacheEntryA (WININET.@) 03521 */ 03522 BOOL WINAPI FindNextUrlCacheEntryA( 03523 HANDLE hEnumHandle, 03524 LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo, 03525 LPDWORD lpdwNextCacheEntryInfoBufferSize) 03526 { 03527 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize); 03528 03529 return FindNextUrlCacheEntryInternal(hEnumHandle, lpNextCacheEntryInfo, 03530 lpdwNextCacheEntryInfoBufferSize, FALSE /* not UNICODE */); 03531 } 03532 03533 /*********************************************************************** 03534 * FindNextUrlCacheEntryW (WININET.@) 03535 */ 03536 BOOL WINAPI FindNextUrlCacheEntryW( 03537 HANDLE hEnumHandle, 03538 LPINTERNET_CACHE_ENTRY_INFOW lpNextCacheEntryInfo, 03539 LPDWORD lpdwNextCacheEntryInfoBufferSize 03540 ) 03541 { 03542 TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize); 03543 03544 return FindNextUrlCacheEntryInternal(hEnumHandle, 03545 (LPINTERNET_CACHE_ENTRY_INFOA)lpNextCacheEntryInfo, 03546 lpdwNextCacheEntryInfoBufferSize, TRUE /* UNICODE */); 03547 } 03548 03549 /*********************************************************************** 03550 * FindCloseUrlCache (WININET.@) 03551 */ 03552 BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle) 03553 { 03554 URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle; 03555 03556 TRACE("(%p)\n", hEnumHandle); 03557 03558 if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC) 03559 { 03560 SetLastError(ERROR_INVALID_HANDLE); 03561 return FALSE; 03562 } 03563 03564 pEntryHandle->dwMagic = 0; 03565 HeapFree(GetProcessHeap(), 0, pEntryHandle->lpszUrlSearchPattern); 03566 HeapFree(GetProcessHeap(), 0, pEntryHandle); 03567 03568 return TRUE; 03569 } 03570 03571 HANDLE WINAPI FindFirstUrlCacheGroup( DWORD dwFlags, DWORD dwFilter, LPVOID lpSearchCondition, 03572 DWORD dwSearchCondition, GROUPID* lpGroupId, LPVOID lpReserved ) 03573 { 03574 FIXME("(0x%08x, 0x%08x, %p, 0x%08x, %p, %p) stub\n", dwFlags, dwFilter, lpSearchCondition, 03575 dwSearchCondition, lpGroupId, lpReserved); 03576 return NULL; 03577 } 03578 03579 BOOL WINAPI FindNextUrlCacheEntryExA( 03580 HANDLE hEnumHandle, 03581 LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, 03582 LPDWORD lpdwFirstCacheEntryInfoBufferSize, 03583 LPVOID lpReserved, 03584 LPDWORD pcbReserved2, 03585 LPVOID lpReserved3 03586 ) 03587 { 03588 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize, 03589 lpReserved, pcbReserved2, lpReserved3); 03590 return FALSE; 03591 } 03592 03593 BOOL WINAPI FindNextUrlCacheEntryExW( 03594 HANDLE hEnumHandle, 03595 LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, 03596 LPDWORD lpdwFirstCacheEntryInfoBufferSize, 03597 LPVOID lpReserved, 03598 LPDWORD pcbReserved2, 03599 LPVOID lpReserved3 03600 ) 03601 { 03602 FIXME("(%p, %p, %p, %p, %p, %p) stub\n", hEnumHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize, 03603 lpReserved, pcbReserved2, lpReserved3); 03604 return FALSE; 03605 } 03606 03607 BOOL WINAPI FindNextUrlCacheGroup( HANDLE hFind, GROUPID* lpGroupId, LPVOID lpReserved ) 03608 { 03609 FIXME("(%p, %p, %p) stub\n", hFind, lpGroupId, lpReserved); 03610 return FALSE; 03611 } 03612 03613 /*********************************************************************** 03614 * CreateUrlCacheGroup (WININET.@) 03615 * 03616 */ 03617 INTERNETAPI GROUPID WINAPI CreateUrlCacheGroup(DWORD dwFlags, LPVOID lpReserved) 03618 { 03619 FIXME("(0x%08x, %p): stub\n", dwFlags, lpReserved); 03620 return FALSE; 03621 } 03622 03623 /*********************************************************************** 03624 * DeleteUrlCacheGroup (WININET.@) 03625 * 03626 */ 03627 BOOL WINAPI DeleteUrlCacheGroup(GROUPID GroupId, DWORD dwFlags, LPVOID lpReserved) 03628 { 03629 FIXME("(0x%08x%08x, 0x%08x, %p) stub\n", 03630 (ULONG)(GroupId >> 32), (ULONG)GroupId, dwFlags, lpReserved); 03631 return FALSE; 03632 } 03633 03634 /*********************************************************************** 03635 * SetUrlCacheEntryGroupA (WININET.@) 03636 * 03637 */ 03638 BOOL WINAPI SetUrlCacheEntryGroupA(LPCSTR lpszUrlName, DWORD dwFlags, 03639 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes, 03640 LPVOID lpReserved) 03641 { 03642 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n", 03643 debugstr_a(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId, 03644 pbGroupAttributes, cbGroupAttributes, lpReserved); 03645 SetLastError(ERROR_FILE_NOT_FOUND); 03646 return FALSE; 03647 } 03648 03649 /*********************************************************************** 03650 * SetUrlCacheEntryGroupW (WININET.@) 03651 * 03652 */ 03653 BOOL WINAPI SetUrlCacheEntryGroupW(LPCWSTR lpszUrlName, DWORD dwFlags, 03654 GROUPID GroupId, LPBYTE pbGroupAttributes, DWORD cbGroupAttributes, 03655 LPVOID lpReserved) 03656 { 03657 FIXME("(%s, 0x%08x, 0x%08x%08x, %p, 0x%08x, %p) stub\n", 03658 debugstr_w(lpszUrlName), dwFlags, (ULONG)(GroupId >> 32), (ULONG)GroupId, 03659 pbGroupAttributes, cbGroupAttributes, lpReserved); 03660 SetLastError(ERROR_FILE_NOT_FOUND); 03661 return FALSE; 03662 } 03663 03664 /*********************************************************************** 03665 * GetUrlCacheConfigInfoW (WININET.@) 03666 */ 03667 BOOL WINAPI GetUrlCacheConfigInfoW(LPINTERNET_CACHE_CONFIG_INFOW CacheInfo, LPDWORD size, DWORD bitmask) 03668 { 03669 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask); 03670 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 03671 return FALSE; 03672 } 03673 03674 /*********************************************************************** 03675 * GetUrlCacheConfigInfoA (WININET.@) 03676 */ 03677 BOOL WINAPI GetUrlCacheConfigInfoA(LPINTERNET_CACHE_CONFIG_INFOA CacheInfo, LPDWORD size, DWORD bitmask) 03678 { 03679 FIXME("(%p, %p, %x)\n", CacheInfo, size, bitmask); 03680 INTERNET_SetLastError(ERROR_INVALID_PARAMETER); 03681 return FALSE; 03682 } 03683 03684 BOOL WINAPI GetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes, 03685 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, 03686 LPDWORD lpdwGroupInfo, LPVOID lpReserved ) 03687 { 03688 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n", 03689 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, 03690 lpdwGroupInfo, lpReserved); 03691 return FALSE; 03692 } 03693 03694 BOOL WINAPI GetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes, 03695 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, 03696 LPDWORD lpdwGroupInfo, LPVOID lpReserved ) 03697 { 03698 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p, %p) stub\n", 03699 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, 03700 lpdwGroupInfo, lpReserved); 03701 return FALSE; 03702 } 03703 03704 BOOL WINAPI SetUrlCacheGroupAttributeA( GROUPID gid, DWORD dwFlags, DWORD dwAttributes, 03705 LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, LPVOID lpReserved ) 03706 { 03707 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n", 03708 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved); 03709 return TRUE; 03710 } 03711 03712 BOOL WINAPI SetUrlCacheGroupAttributeW( GROUPID gid, DWORD dwFlags, DWORD dwAttributes, 03713 LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, LPVOID lpReserved ) 03714 { 03715 FIXME("(0x%08x%08x, 0x%08x, 0x%08x, %p, %p) stub\n", 03716 (ULONG)(gid >> 32), (ULONG)gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved); 03717 return TRUE; 03718 } 03719 03720 BOOL WINAPI SetUrlCacheConfigInfoA( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwFieldControl ) 03721 { 03722 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl); 03723 return TRUE; 03724 } 03725 03726 BOOL WINAPI SetUrlCacheConfigInfoW( LPINTERNET_CACHE_CONFIG_INFOW lpCacheConfigInfo, DWORD dwFieldControl ) 03727 { 03728 FIXME("(%p, 0x%08x) stub\n", lpCacheConfigInfo, dwFieldControl); 03729 return TRUE; 03730 } 03731 03732 /*********************************************************************** 03733 * DeleteIE3Cache (WININET.@) 03734 * 03735 * Deletes the files used by the IE3 URL caching system. 03736 * 03737 * PARAMS 03738 * hWnd [I] A dummy window. 03739 * hInst [I] Instance of process calling the function. 03740 * lpszCmdLine [I] Options used by function. 03741 * nCmdShow [I] The nCmdShow value to use when showing windows created, if any. 03742 */ 03743 DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow) 03744 { 03745 FIXME("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_a(lpszCmdLine), nCmdShow); 03746 return 0; 03747 } 03748 03749 static BOOL IsUrlCacheEntryExpiredInternal(const URL_CACHEFILE_ENTRY *pUrlEntry, 03750 FILETIME *pftLastModified) 03751 { 03752 BOOL ret; 03753 FILETIME now, expired; 03754 03755 *pftLastModified = pUrlEntry->LastModifiedTime; 03756 GetSystemTimeAsFileTime(&now); 03757 URLCache_DosDateTimeToFileTime(pUrlEntry->wExpiredDate, 03758 pUrlEntry->wExpiredTime, &expired); 03759 /* If the expired time is 0, it's interpreted as not expired */ 03760 if (!expired.dwLowDateTime && !expired.dwHighDateTime) 03761 ret = FALSE; 03762 else 03763 ret = CompareFileTime(&expired, &now) < 0; 03764 return ret; 03765 } 03766 03767 /*********************************************************************** 03768 * IsUrlCacheEntryExpiredA (WININET.@) 03769 * 03770 * PARAMS 03771 * url [I] Url 03772 * dwFlags [I] Unknown 03773 * pftLastModified [O] Last modified time 03774 */ 03775 BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified ) 03776 { 03777 LPURLCACHE_HEADER pHeader; 03778 struct _HASH_ENTRY * pHashEntry; 03779 const CACHEFILE_ENTRY * pEntry; 03780 const URL_CACHEFILE_ENTRY * pUrlEntry; 03781 URLCACHECONTAINER * pContainer; 03782 BOOL expired; 03783 03784 TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified); 03785 03786 if (!url || !pftLastModified) 03787 return TRUE; 03788 if (dwFlags) 03789 FIXME("unknown flags 0x%08x\n", dwFlags); 03790 03791 /* Any error implies that the URL is expired, i.e. not in the cache */ 03792 if (URLCacheContainers_FindContainerA(url, &pContainer)) 03793 { 03794 memset(pftLastModified, 0, sizeof(*pftLastModified)); 03795 return TRUE; 03796 } 03797 03798 if (URLCacheContainer_OpenIndex(pContainer)) 03799 { 03800 memset(pftLastModified, 0, sizeof(*pftLastModified)); 03801 return TRUE; 03802 } 03803 03804 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 03805 { 03806 memset(pftLastModified, 0, sizeof(*pftLastModified)); 03807 return TRUE; 03808 } 03809 03810 if (!URLCache_FindHash(pHeader, url, &pHashEntry)) 03811 { 03812 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03813 memset(pftLastModified, 0, sizeof(*pftLastModified)); 03814 TRACE("entry %s not found!\n", url); 03815 return TRUE; 03816 } 03817 03818 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); 03819 if (pEntry->dwSignature != URL_SIGNATURE) 03820 { 03821 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03822 memset(pftLastModified, 0, sizeof(*pftLastModified)); 03823 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD))); 03824 return TRUE; 03825 } 03826 03827 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry; 03828 expired = IsUrlCacheEntryExpiredInternal(pUrlEntry, pftLastModified); 03829 03830 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03831 03832 return expired; 03833 } 03834 03835 /*********************************************************************** 03836 * IsUrlCacheEntryExpiredW (WININET.@) 03837 * 03838 * PARAMS 03839 * url [I] Url 03840 * dwFlags [I] Unknown 03841 * pftLastModified [O] Last modified time 03842 */ 03843 BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified ) 03844 { 03845 LPURLCACHE_HEADER pHeader; 03846 struct _HASH_ENTRY * pHashEntry; 03847 const CACHEFILE_ENTRY * pEntry; 03848 const URL_CACHEFILE_ENTRY * pUrlEntry; 03849 URLCACHECONTAINER * pContainer; 03850 BOOL expired; 03851 03852 TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified); 03853 03854 if (!url || !pftLastModified) 03855 return TRUE; 03856 if (dwFlags) 03857 FIXME("unknown flags 0x%08x\n", dwFlags); 03858 03859 /* Any error implies that the URL is expired, i.e. not in the cache */ 03860 if (URLCacheContainers_FindContainerW(url, &pContainer)) 03861 { 03862 memset(pftLastModified, 0, sizeof(*pftLastModified)); 03863 return TRUE; 03864 } 03865 03866 if (URLCacheContainer_OpenIndex(pContainer)) 03867 { 03868 memset(pftLastModified, 0, sizeof(*pftLastModified)); 03869 return TRUE; 03870 } 03871 03872 if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) 03873 { 03874 memset(pftLastModified, 0, sizeof(*pftLastModified)); 03875 return TRUE; 03876 } 03877 03878 if (!URLCache_FindHashW(pHeader, url, &pHashEntry)) 03879 { 03880 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03881 memset(pftLastModified, 0, sizeof(*pftLastModified)); 03882 TRACE("entry %s not found!\n", debugstr_w(url)); 03883 return TRUE; 03884 } 03885 03886 if (!URLCache_FindHashW(pHeader, url, &pHashEntry)) 03887 { 03888 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03889 memset(pftLastModified, 0, sizeof(*pftLastModified)); 03890 TRACE("entry %s not found!\n", debugstr_w(url)); 03891 return TRUE; 03892 } 03893 03894 pEntry = (const CACHEFILE_ENTRY *)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); 03895 if (pEntry->dwSignature != URL_SIGNATURE) 03896 { 03897 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03898 memset(pftLastModified, 0, sizeof(*pftLastModified)); 03899 FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->dwSignature, sizeof(DWORD))); 03900 return TRUE; 03901 } 03902 03903 pUrlEntry = (const URL_CACHEFILE_ENTRY *)pEntry; 03904 expired = IsUrlCacheEntryExpiredInternal(pUrlEntry, pftLastModified); 03905 03906 URLCacheContainer_UnlockIndex(pContainer, pHeader); 03907 03908 return expired; 03909 } 03910 03911 /*********************************************************************** 03912 * GetDiskInfoA (WININET.@) 03913 */ 03914 BOOL WINAPI GetDiskInfoA(PCSTR path, PDWORD cluster_size, PDWORDLONG free, PDWORDLONG total) 03915 { 03916 BOOL ret; 03917 ULARGE_INTEGER bytes_free, bytes_total; 03918 03919 TRACE("(%s, %p, %p, %p)\n", debugstr_a(path), cluster_size, free, total); 03920 03921 if (!path) 03922 { 03923 SetLastError(ERROR_INVALID_PARAMETER); 03924 return FALSE; 03925 } 03926 03927 if ((ret = GetDiskFreeSpaceExA(path, NULL, &bytes_total, &bytes_free))) 03928 { 03929 if (cluster_size) *cluster_size = 1; 03930 if (free) *free = bytes_free.QuadPart; 03931 if (total) *total = bytes_total.QuadPart; 03932 } 03933 return ret; 03934 } 03935 03936 /*********************************************************************** 03937 * RegisterUrlCacheNotification (WININET.@) 03938 */ 03939 DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f) 03940 { 03941 FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f); 03942 return 0; 03943 } 03944 03945 /*********************************************************************** 03946 * IncrementUrlCacheHeaderData (WININET.@) 03947 */ 03948 BOOL WINAPI IncrementUrlCacheHeaderData(DWORD index, LPDWORD data) 03949 { 03950 FIXME("(%u, %p)\n", index, data); 03951 return FALSE; 03952 } Generated on Sat May 26 2012 04:25:27 for ReactOS by
1.7.6.1
|