⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 urlcache.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * Wininet - Url Cache functions
 *
 * Copyright 2001,2002 CodeWeavers
 * Copyright 2003 Robert Shearman
 *
 * Eric Kohl
 * Aric Stewart
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#define COM_NO_WINDOWS_H
#include "config.h"
#include "wine/port.h"

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define NONAMELESSUNION
#define NONAMELESSSTRUCT

#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "wininet.h"
#include "winerror.h"
#include "internet.h"
#include "winreg.h"
#include "shlwapi.h"
#include "wingdi.h"
#include "shlobj.h"

#include "wine/unicode.h"
#include "wine/list.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(wininet);

#define ENTRY_START_OFFSET  0x4000
#define DIR_LENGTH          8
#define BLOCKSIZE           128
#define HASHTABLE_SIZE      448
#define HASHTABLE_BLOCKSIZE 7
#define HASHTABLE_FREE      3
#define ALLOCATION_TABLE_OFFSET 0x250
#define ALLOCATION_TABLE_SIZE   (0x1000 - ALLOCATION_TABLE_OFFSET)
#define HASHTABLE_NUM_ENTRIES   (HASHTABLE_SIZE / HASHTABLE_BLOCKSIZE)
#define NEWFILE_NUM_BLOCKS	0xd80
#define NEWFILE_SIZE		(NEWFILE_NUM_BLOCKS * BLOCKSIZE + ENTRY_START_OFFSET)

#define DWORD_SIG(a,b,c,d)  (a | (b << 8) | (c << 16) | (d << 24))
#define URL_SIGNATURE   DWORD_SIG('U','R','L',' ')
#define REDR_SIGNATURE  DWORD_SIG('R','E','D','R')
#define LEAK_SIGNATURE  DWORD_SIG('L','E','A','K')
#define HASH_SIGNATURE  DWORD_SIG('H','A','S','H')

#define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) )

typedef struct _CACHEFILE_ENTRY
{
/*  union
    {*/
        DWORD dwSignature; /* e.g. "URL " */
/*      CHAR szSignature[4];
    };*/
    DWORD dwBlocksUsed; /* number of 128byte blocks used by this entry */
} CACHEFILE_ENTRY;

typedef struct _URL_CACHEFILE_ENTRY
{
    CACHEFILE_ENTRY CacheFileEntry;
    FILETIME LastModifiedTime;
    FILETIME LastAccessTime;
    WORD wExpiredDate; /* expire date in dos format */
    WORD wExpiredTime; /* expire time in dos format */
    DWORD dwUnknown1; /* usually zero */
    DWORD dwSizeLow; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeLow */
    DWORD dwSizeHigh; /* see INTERNET_CACHE_ENTRY_INFO::dwSizeHigh */
    DWORD dwUnknown2; /* usually zero */
    DWORD dwExemptDelta; /* see INTERNET_CACHE_ENTRY_INFO::dwExemptDelta */
    DWORD dwUnknown3; /* usually 0x60 */
    DWORD dwOffsetUrl; /* usually 0x68 */
    BYTE CacheDir; /* index of cache directory this url is stored in */
    BYTE Unknown4; /* usually zero */
    WORD wUnknown5; /* usually 0x1010 */
    DWORD dwOffsetLocalName; /* offset of start of local filename from start of entry */
    DWORD CacheEntryType; /* see INTERNET_CACHE_ENTRY_INFO::CacheEntryType */
    DWORD dwOffsetHeaderInfo; /* offset of start of header info from start of entry */
    DWORD dwHeaderInfoSize;
    DWORD dwUnknown6; /* usually zero */
    WORD wLastSyncDate; /* last sync date in dos format */
    WORD wLastSyncTime; /* last sync time in dos format */
    DWORD dwHitRate; /* see INTERNET_CACHE_ENTRY_INFO::dwHitRate */
    DWORD dwUseCount; /* see INTERNET_CACHE_ENTRY_INFO::dwUseCount */
    WORD wUnknownDate; /* usually same as wLastSyncDate */
    WORD wUnknownTime; /* usually same as wLastSyncTime */
    DWORD dwUnknown7; /* usually zero */
    DWORD dwUnknown8; /* usually zero */
    CHAR szSourceUrlName[1]; /* start of url */
    /* packing to dword align start of next field */
    /* CHAR szLocalFileName[]; (local file name exluding path) */
    /* packing to dword align start of next field */
    /* CHAR szHeaderInfo[]; (header info) */
} URL_CACHEFILE_ENTRY;

struct _HASH_ENTRY
{
    DWORD dwHashKey;
    DWORD dwOffsetEntry;
};

typedef struct _HASH_CACHEFILE_ENTRY
{
    CACHEFILE_ENTRY CacheFileEntry;
    DWORD dwAddressNext;
    DWORD dwHashTableNumber;
    struct _HASH_ENTRY HashTable[HASHTABLE_SIZE];
} HASH_CACHEFILE_ENTRY;

typedef struct _DIRECTORY_DATA
{
    DWORD dwUnknown;
    char filename[DIR_LENGTH];
} DIRECTORY_DATA;

typedef struct _URLCACHE_HEADER
{
    char szSignature[28];
    DWORD dwFileSize;
    DWORD dwOffsetFirstHashTable;
    DWORD dwIndexCapacityInBlocks;
    DWORD dwBlocksInUse;
    DWORD dwUnknown1;
    DWORD dwCacheLimitLow; /* disk space limit for cache */
    DWORD dwCacheLimitHigh; /* disk space limit for cache */
    DWORD dwUnknown4; /* current disk space usage for cache */
    DWORD dwUnknown5; /* current disk space usage for cache */
    DWORD dwUnknown6; /* possibly a flag? */
    DWORD dwUnknown7;
    BYTE DirectoryCount; /* number of directory_data's */
    BYTE Unknown8[3]; /* just padding? */
    DIRECTORY_DATA directory_data[1]; /* first directory entry */
} URLCACHE_HEADER, *LPURLCACHE_HEADER;
typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER;

typedef struct _STREAM_HANDLE
{
    HANDLE hFile;
    CHAR lpszUrl[1];
} STREAM_HANDLE;

typedef struct _URLCACHECONTAINER
{
    struct list entry; /* part of a list */
    LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */
    LPWSTR path; /* path to url container directory */
    HANDLE hMapping; /* handle of file mapping */
    DWORD file_size; /* size of file when mapping was opened */
    HANDLE hMutex; /* hande of mutex */
} URLCACHECONTAINER;


/* List of all containers available */
static struct list UrlContainers = LIST_INIT(UrlContainers);

static HASH_CACHEFILE_ENTRY *URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash);

/***********************************************************************
 *           URLCache_PathToObjectName (Internal)
 *
 *  Converts a path to a name suitable for use as a Win32 object name.
 * Replaces '\\' characters in-place with the specified character
 * (usually '_' or '!')
 *
 * RETURNS
 *    nothing
 *
 */
static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace)
{
    for (; *lpszPath; lpszPath++)
    {
        if (*lpszPath == '\\')
            *lpszPath = replace;
    }
}

/***********************************************************************
 *           URLCacheContainer_OpenIndex (Internal)
 *
 *  Opens the index file and saves mapping handle in hCacheIndexMapping
 *
 * RETURNS
 *    TRUE if succeeded
 *    FALSE if failed
 *
 */
static BOOL URLCacheContainer_OpenIndex(URLCACHECONTAINER * pContainer)
{
    HANDLE hFile;
    WCHAR wszFilePath[MAX_PATH];
    DWORD dwFileSize;

    static const WCHAR wszIndex[] = {'i','n','d','e','x','.','d','a','t',0};
    static const WCHAR wszMappingFormat[] = {'%','s','%','s','_','%','l','u',0};

    if (pContainer->hMapping)
        return TRUE;

    strcpyW(wszFilePath, pContainer->path);
    strcatW(wszFilePath, wszIndex);

    hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
	/* Maybe the directory wasn't there? Try to create it */
	if (CreateDirectoryW(pContainer->path, 0))
            hFile = CreateFileW(wszFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
    }
    if (hFile == INVALID_HANDLE_VALUE)
    {
        TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(wszFilePath));
        return FALSE;
    }

    /* At this stage we need the mutex because we may be about to create the
     * file.
     */
    WaitForSingleObject(pContainer->hMutex, INFINITE);

    dwFileSize = GetFileSize(hFile, NULL);
    if (dwFileSize == INVALID_FILE_SIZE)
    {
	ReleaseMutex(pContainer->hMutex);
        return FALSE;
    }

    if (dwFileSize == 0)
    {
        static CHAR const szCacheContent[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Cache\\Content";
	HKEY	key;
	char	achZeroes[0x1000];
	DWORD	dwOffset;
	DWORD dwError = 0;

	/* Write zeroes to the entire file so we can safely map it without
	 * fear of getting a SEGV because the disk is full.
	 */
	memset(achZeroes, 0, sizeof(achZeroes));
	for (dwOffset = 0; dwOffset < NEWFILE_SIZE; dwOffset += sizeof(achZeroes))
	{
	    DWORD dwWrite = sizeof(achZeroes);
	    DWORD dwWritten;

	    if (NEWFILE_SIZE - dwOffset < dwWrite)
		dwWrite = NEWFILE_SIZE - dwOffset;
	    if (!WriteFile(hFile, achZeroes, dwWrite, &dwWritten, 0) ||
		dwWritten != dwWrite)
	    {
		/* If we fail to write, we need to return the error that
		 * cause the problem and also make sure the file is no
		 * longer there, if possible.
		 */
		dwError = GetLastError();

		break;
	    }
	}

	if (!dwError)
	{
	    HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, NEWFILE_SIZE, NULL);

	    if (hMapping)
	    {
		URLCACHE_HEADER *pHeader = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, NEWFILE_SIZE);

		if (pHeader)
		{
		    WCHAR *pwchDir;
		    WCHAR wszDirPath[MAX_PATH];
		    FILETIME ft;
		    int i, j;

		    dwFileSize = NEWFILE_SIZE;
		
		    /* First set some constants and defaults in the header */
		    strcpy(pHeader->szSignature, "WINE URLCache Ver 0.2005001");
		    pHeader->dwFileSize = dwFileSize;
		    pHeader->dwIndexCapacityInBlocks = NEWFILE_NUM_BLOCKS;
		    /* 127MB - taken from default for Windows 2000 */
		    pHeader->dwCacheLimitHigh = 0;
		    pHeader->dwCacheLimitLow = 0x07ff5400;
		    /* Copied from a Windows 2000 cache index */
		    pHeader->DirectoryCount = 4;
		
		    /* If the registry has a cache size set, use the registry value */
		    if (RegOpenKeyA(HKEY_CURRENT_USER, szCacheContent, &key) == ERROR_SUCCESS)
		    {
		        DWORD dw;
		        DWORD len = sizeof(dw);
		        DWORD keytype;
		
		        if (RegQueryValueExA(key, "CacheLimit", NULL, &keytype,
					     (BYTE *) &dw, &len) == ERROR_SUCCESS &&
			    keytype == REG_DWORD)
			{
			    pHeader->dwCacheLimitHigh = (dw >> 22);
			    pHeader->dwCacheLimitLow = dw << 10;
			}
			RegCloseKey(key);
		    }
		
		    URLCache_CreateHashTable(pHeader, NULL);

		    /* Last step - create the directories */
	
		    strcpyW(wszDirPath, pContainer->path);
		    pwchDir = wszDirPath + strlenW(wszDirPath);
		    pwchDir[8] = 0;
	
		    GetSystemTimeAsFileTime(&ft);
	
		    for (i = 0; !dwError && i < pHeader->DirectoryCount; ++i)
		    {
			/* The following values were copied from a Windows index.
			 * I don't know what the values are supposed to mean but
			 * have made them the same in the hope that this will
			 * be better for compatibility
			 */
			pHeader->directory_data[i].dwUnknown = (i > 1) ? 0xfe : 0xff;
			for (j = 0;; ++j)
			{
			    int k;
			    ULONGLONG n = ft.dwHighDateTime;
	
			    /* Generate a file name to attempt to create.
			     * This algorithm will create what will appear
			     * to be random and unrelated directory names
			     * of up to 9 characters in length.
			     */
			    n <<= 32;
			    n += ft.dwLowDateTime;
			    n ^= ((ULONGLONG) i << 56) | ((ULONGLONG) j << 48);
	
			    for (k = 0; k < 8; ++k)
			    {
				int r = (n % 36);
	
				/* Dividing by a prime greater than 36 helps
				 * with the appearance of randomness
				 */
				n /= 37;
	
				if (r < 10)
				    pwchDir[k] = '0' + r;
				else
				    pwchDir[k] = 'A' + (r - 10);
			    }
	
			    if (CreateDirectoryW(wszDirPath, 0))
			    {
				int k;
	
				/* The following is OK because we generated an
				 * 8 character directory name made from characters
				 * [A-Z0-9], which are equivalent for all code
				 * pages and for UTF-16
				 */
				for (k = 0; k < 8; ++k)
				    pHeader->directory_data[i].filename[k] = pwchDir[k];
				break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -