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

📄 file.cxx

📁 完全免费的邮件发送程序。delphi 6.0
💻 CXX
📖 第 1 页 / 共 4 页
字号:
//-< FILE.CXX >------------------------------------------------------*--------*
// POST++                     Version 1.0        (c) 1998  GARRET    *     ?  *
// (Persistent Object Storage)                                       *   /\|  *
//                                                                   *  /  \  *
//                          Created:      2-Feb-98    K.A. Knizhnik  * / [] \ *
//                          Last update: 21-Jan-99    K.A. Knizhnik  * GARRET *
//                                                                   *  /  \  *
// Port to AIX done by XaoYao 13-Apr-97                              *        *
// Also thanks to Wolfgang Hendriks and Antonio Corrao for reporting
// bugs in this module.
//-------------------------------------------------------------------*--------*
// Mapped on memory file class implementation
//-------------------------------------------------------------------*--------*

#include <time.h>
#include "storage.h"

file* file::chain;
char* program_compilation_time;

void file::set_file_name(const char* file_name)
{
    int len = strlen(file_name);
   
    name = new char[len+5];
    log_name = new char[len+5];
    sav_name = new char[len+5];
    tmp_name = new char[len+5];
    strcpy(name, file_name);
    if (len < 4 || file_name[len-4] != '.') { 
	strcat(name, ".odb");
    }
    strcat(strcpy(log_name, file_name), ".log");
    strcat(strcpy(tmp_name, file_name), ".tmp");
    strcat(strcpy(sav_name, file_name), ".sav");
}

#ifdef _WIN32

bool file::handle_page_access(DWORD* params) 
{
    for (file* fp = chain; fp != NULL; fp = fp->next) { 
	if (params[1] - (DWORD)fp->base < fp->mapped_size) { 
	    return fp->prot != read_only 
		&& fp->create_shadow_page(params[0], (void*)params[1]);
	}
    }  
    return false;
} 

static LONG WINAPI AccessViolationHandler(LPEXCEPTION_POINTERS ep)
{
    return ep->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
	&& file::handle_page_access(ep->ExceptionRecord->ExceptionInformation)
	   ? EXCEPTION_CONTINUE_EXECUTION
	   : EXCEPTION_CONTINUE_SEARCH;
}


file::file(const char* name, size_t max_file_size, size_t max_locked_pages)
{
    SYSTEM_INFO sysinfo;
    MEMORYSTATUS memstat;

    OSVERSIONINFO osinfo;
    osinfo.dwOSVersionInfoSize = sizeof osinfo;
    GetVersionEx(&osinfo);
    platform = osinfo.dwPlatformId;
    
    GetSystemInfo(&sysinfo);
    allocation_granularity = sysinfo.dwAllocationGranularity;
    page_size = sysinfo.dwPageSize;

    if (platform == VER_PLATFORM_WIN32_NT) {     
	DWORD MinimumWorkingSetSize, MaximumWorkingSetSize;
	GetProcessWorkingSetSize(GetCurrentProcess(),
				 &MinimumWorkingSetSize, 
				 &MaximumWorkingSetSize);

	if (max_locked_pages > MinimumWorkingSetSize/page_size) { 
	    MinimumWorkingSetSize = max_locked_pages*2*page_size;
	    if (MaximumWorkingSetSize < MinimumWorkingSetSize) { 
		MaximumWorkingSetSize = MinimumWorkingSetSize;
	    }
	    if (!SetProcessWorkingSetSize(GetCurrentProcess(),
					  MinimumWorkingSetSize,
					  MaximumWorkingSetSize)) 
	    {
		const size_t max_nt_locked_pages = 30;
		TRACE_MSG(("file::file: failed to extend process working set "
			   "size to %ld bytes, set max_locked_pages to %ld\n", 
			   MinimumWorkingSetSize, max_nt_locked_pages));
		max_locked_pages = max_nt_locked_pages;
	    } else { 
		TRACE_MSG(("file::file: extend process working set size "
			   "to %ld bytes\n", MinimumWorkingSetSize));
	    }
	}
    } else { 
	max_locked_pages = 0;
    }
    memstat.dwLength = sizeof(memstat);
    GlobalMemoryStatus(&memstat);
    if (memstat.dwAvailVirtual < max_file_size) { 
	max_file_size = memstat.dwAvailVirtual & ~(allocation_granularity-1);
	TRACE_MSG(("file::file: set max_file_size to %ld bytes\n",
		   max_file_size));
    }

    set_file_name(name);
    this->max_file_size = ALIGN(max_file_size, allocation_granularity);
    this->max_locked_pages = max_locked_pages;

    log_buffer = new char[page_size+sizeof(long)];
    locked_page = new char*[max_locked_pages];
    
    SetUnhandledExceptionFilter(AccessViolationHandler);
    error_code = ok;
}

file::~file() 
{
    delete[] name;
    delete[] log_name;
    delete[] tmp_name;
    delete[] sav_name;
    delete[] log_buffer;
    delete[] locked_page;
}


inline bool file::recover_file()
{
    DWORD read_bytes;
    size_t trans_size = page_size + sizeof(long);
    int n_recovered_pages = 0;
    TRACE_MSG(("file::recover_file: recover data file from transaction log\n"));
    recovery = true;
    while (ReadFile(log, log_buffer, trans_size, &read_bytes, NULL)) { 
	if (read_bytes != trans_size) { 
	    recovery = false;
	    if (read_bytes == 0) { 
		size = ALIGN(((file_header*)base)->file_size, page_size);
		TRACE_MSG(("recover::file: recover %d pages, set file size "
			   "to %ld\n", n_recovered_pages, size));
		error_code = ok;
		return true;	    
	    } else { 
		error_code = end_of_file;
		TRACE_MSG(("file::recover_file: read %ld bytes from log "
			   "instead of %ld\n", 
			   read_bytes, trans_size));
		return false;
	    }
	}    
	size_t offs = *(long*)log_buffer;
	assert(offs < size);
	memcpy(base + offs, log_buffer+sizeof(long), page_size);
	n_recovered_pages += 1;
    }
    error_code = GetLastError();
    TRACE_MSG(("file::recover_file: failed to read log file: %d\n", 
	       error_code));
    recovery = false;
    return false;
}

inline bool file::flush_log_buffer()
{
    if (!FlushFileBuffers(log)) { 
	error_code = GetLastError();
	TRACE_MSG(("file::flush_log_buffer: FlushFileBuffers failed: %d\n", 
		   error_code));
	return false;
    }
    for (int i = n_locked_pages; --i >= 0;) { 
	if (!VirtualUnlock(locked_page[i], page_size)) { 
	    error_code = GetLastError();
	    TRACE_MSG(("file::flush_log_buffer: VirtualUnlock %p failed: %d\n",
		       locked_page[i], error_code));
	    return false;
	}
    }
    n_locked_pages = 0;
    return true;
}


bool file::create_shadow_page(int modify, void* addr)
{
    DWORD old_prot;
    DWORD written_bytes;
    char* page = (char*)(long(addr) & ~(page_size-1));
    DWORD offs = page - base;

    if (!VirtualProtect(page, page_size, 
			modify ? PAGE_READWRITE : PAGE_READONLY, &old_prot)) 
    { 
	TRACE_MSG(("file::create_shadow_page: VirtualProtect %p failed: %ld\n",
		   page, GetLastError()));
	return false;
    }
    if (platform != VER_PLATFORM_WIN32_NT) {     
	if (modify) { 
	    unsigned page_no = offs / page_size;
	    dirty_page_map[page_no >> 5] |= 1 << (page_no & 0x1F);
	    if (recovery) { 
		return true;
	    }
	}
	if (old_prot == PAGE_NOACCESS) { 
	    if (!modify) { 
		if (!VirtualProtect(page,page_size,PAGE_READWRITE,&old_prot)){
		    TRACE_MSG(("file::create_shadow_page: "
			       "VirtualProtect2 %p failed: %ld\n", 
			       page, GetLastError()));
		    return false;
		}
	    }
	    DWORD read_bytes;
	    if (SetFilePointer(fd, offs, NULL, FILE_BEGIN) != offs
		|| !ReadFile(fd, page, page_size, &read_bytes, NULL))
	    {
		return false;
	    }
	    if (!modify) { 
		if (!VirtualProtect(page,page_size,PAGE_READONLY,&old_prot)) {
		    TRACE_MSG(("file::create_shadow_page: "
			       "VirtualProtect3 %p failed: %ld\n", 
			       page, GetLastError()));
		}		    
		return true;
	    }
	}
    }

    *(long*)log_buffer = offs;
    memcpy(log_buffer+sizeof(long), page, page_size);
    size_t trans_size = page_size + sizeof(long);
    if (!WriteFile(log, log_buffer, trans_size, &written_bytes, NULL)
	|| written_bytes != trans_size)
    {
	TRACE_MSG(("file::create_shadow_page: WriteFile failed: %d\n", 
		   GetLastError()));
	return false;
    }
    if (max_locked_pages != 0) { 
	if (n_locked_pages >= max_locked_pages) { 
	    return flush_log_buffer();
	} 
	if (!VirtualLock(page, page_size)) { 
	    TRACE_MSG(("file::create_shadow_page: VirtualLock %p failed,"
		       "number of locked pages %ld: %ld\n",
		       page, n_locked_pages, GetLastError()));
	    if (n_locked_pages != 0) { 
		max_locked_pages = n_locked_pages;
	    }
	    return flush_log_buffer();
	} 
	locked_page[n_locked_pages++] = page;
    }
    return true;
}


bool file::read_file_in_memory()
{
#if DEBUG_LEVEL >= DEBUG_TRACE
    msg_buf buf;
#endif
    DWORD read_bytes;
    vmem = (char*)VirtualAlloc(base, mapped_size, 
			       MEM_RESERVE, PAGE_READWRITE);
    if (vmem == NULL) { 
	error_code = GetLastError();
	TRACE_MSG(("file::read_file_in_memory: failed to virtual alloc at "
		   "address %p: %s\n", base, get_error_text(buf, sizeof buf)));
	vmem = (char*)VirtualAlloc(NULL, mapped_size, 
				   MEM_RESERVE, PAGE_READWRITE);
    }
    if (vmem == NULL) { 
	error_code = GetLastError();
	TRACE_MSG(("file::read_file_in_memory: failed to virtual alloc: %s\n", 
		   get_error_text(buf, sizeof buf)));
	CloseHandle(fd);
	return false;
    }
    base = vmem;
    if (size != 0) { 
	TRACE_MSG(("file::read_file_in_memory: virtual alloc: address=%p, "
		   "mapped_size=%ld, size=%ld\n", vmem, mapped_size, size));
	if (base != (char*)VirtualAlloc(base, size, MEM_COMMIT, 
					PAGE_READWRITE) 
	    || SetFilePointer(fd, 0, NULL, FILE_BEGIN) != 0
	    || ReadFile(fd, base, size, &read_bytes, NULL) == false)
	{
	    error_code = GetLastError();
	    TRACE_MSG(("file::read_file_in_memory: failed to read file in "
		       "memory: %s\n", get_error_text(buf, sizeof buf)));
	    CloseHandle(fd);
	    VirtualFree(vmem, 0, MEM_RELEASE);
	    return false;
	} else if (read_bytes != size) { 
	    error_code = file_size_not_aligned;
	    TRACE_MSG(("file::read_file_in_memory:read %ld bytes instead "
		       "of %ld\n", read_bytes, size));
	    CloseHandle(fd);
	    VirtualFree(vmem, 0, MEM_RELEASE);
	    return false;
	}	    
    }
    return true;
}

bool file::write_dirty_pages_in_file()
{
    size_t offs = 0; 
    unsigned page_no;
    for (page_no = 0; offs < size; page_no += 1) { 
	int mask = 1 << (page_no & 0x1F);
	if (dirty_page_map[page_no >> 5] & mask) {  
	    dirty_page_map[page_no >> 5] &= ~mask;
	    DWORD written_bytes;
	    if (SetFilePointer(fd, offs, NULL, FILE_BEGIN) != offs
		|| !WriteFile(fd, base+offs, page_size, &written_bytes, 0)
		|| written_bytes != page_size)
	    {
		error_code = GetLastError();
		TRACE_MSG(("file::write_dirty_pages_in_file: failed to write"
			   " page in file: %d\n", error_code));
		return false;
	    }
	    DWORD old_prot;
	    if (!VirtualProtect(base+offs, page_size, PAGE_READONLY, &old_prot)) {
		error_code = GetLastError();
		TRACE_MSG(("file::write_dirty_pages_in_file: failed to change protection"
			   " to read-only: %d\n", error_code));
		return false;
	    }
	}
	offs += page_size;
    }
    if (!FlushFileBuffers(fd)) { 
	error_code = GetLastError();
	TRACE_MSG(("file::write_dirty_pages_in_file: FlushFileBuffers "
		   "failed: %d\n", error_code));
	return false;
    }
    return true;
}

bool file::open(open_mode mode, access_prot prot) 
{
#if DEBUG_LEVEL >= DEBUG_TRACE
    msg_buf buf;
#endif
    DWORD old_prot;
    assert(name != NULL);
    if (prot == read_only) { 
	mode = map_file;
    } else if (mode == copy_on_write_map && platform != VER_PLATFORM_WIN32_NT){
	mode = load_in_memory; // copy on write not working in Windows 95
    }

    this->mode = mode;
    this->prot = prot;
    vmem = NULL;
    md = NULL;
    recovery = false;

    if (mode == shadow_pages_transaction) { 
	int flags = (platform == VER_PLATFORM_WIN32_NT)
	    ? FILE_FLAG_WRITE_THROUGH|FILE_FLAG_RANDOM_ACCESS
	    : FILE_FLAG_RANDOM_ACCESS;
	fd = CreateFile(name, GENERIC_READ|GENERIC_WRITE, 0, 
			NULL, OPEN_ALWAYS, flags, NULL);
	if (fd == INVALID_HANDLE_VALUE) { 
	    error_code = GetLastError();
	    TRACE_MSG(("file::open: failed to open file '%s': %s\n", 
		       name, get_error_text(buf, sizeof buf)));
	    return false;
	}
	DWORD read_bytes;
	file_header hdr;
	hdr.base_address = NULL;
	hdr.file_size = 0;
        if (!ReadFile(fd, &hdr, sizeof hdr, &read_bytes, NULL)
	    || (read_bytes != 0 && read_bytes != sizeof hdr))
	{
	    error_code = GetLastError();
	    TRACE_MSG(("file::open: failed to read file: %s\n", 
		       get_error_text(buf, sizeof buf)));
	    CloseHandle(fd);
	    return false;
	}
	base = (char*)hdr.base_address;
	allocated_size = size = ALIGN(hdr.file_size, page_size);
	mapped_size = size > max_file_size ? size : max_file_size;
	if (platform == VER_PLATFORM_WIN32_NT) {     
	    md = CreateFileMapping(fd,NULL,PAGE_READWRITE,0,mapped_size,NULL);
	    if (md == NULL) { 
		error_code = GetLastError();
		TRACE_MSG(("file::open: failed to create file mapping: "
			   "base=%p, size=%ld: %s\n", 
			   base, mapped_size, 
			   get_error_text(buf, sizeof buf)));
		CloseHandle(fd);
		return false;
	    }
	    void* p = MapViewOfFileEx(md, FILE_MAP_ALL_ACCESS, 0, 0, 0, base);
	    if (p == NULL) { 
		error_code = GetLastError();
		TRACE_MSG(("file::open: failed to map view of file on address "
			   "%p: %s\n", base, get_error_text(buf, sizeof buf)));
		p = MapViewOfFileEx(md, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
		if (p == NULL) { 
		    error_code = GetLastError();
		    TRACE_MSG(("file::open: failed to map view of file: %s\n",
			       get_error_text(buf, sizeof buf)));
		    CloseHandle(fd);
		    CloseHandle(md);
		    return false;
		}
	    }
	    base = (char*)p;
	    dirty_page_map = NULL;
	} else { 
	    //
	    // VirtualProtect doesn't work in Winfows 95 with 
	    // mapped on file memory. We have to use VirtualAlloc instead 
	    // to handle page faults and read pages from the file ourself.
	    //
	    vmem = (char*)VirtualAlloc(base, mapped_size, 
				       MEM_RESERVE, PAGE_READWRITE);
	    if (vmem == NULL) { 
		error_code = GetLastError();
		TRACE_MSG(("file::open: failed to virtual alloc at address"
			   " %p: %s\n", base, get_error_text(buf,sizeof buf)));
		vmem = (char*)VirtualAlloc(NULL, mapped_size, 
					   MEM_RESERVE, PAGE_READWRITE);
	    }
	    if (vmem == NULL) { 
		error_code = GetLastError();
		TRACE_MSG(("file::open: failed to virtual alloc: %s\n", 
			   get_error_text(buf, sizeof buf)));
		CloseHandle(fd);
		return false;
	    }
	    base = vmem;
	    if (size != 0) { 
		TRACE_MSG(("file::open: virtual alloc: address=%p, "
			   "mapped_size=%ld, size=%ld\n",
			   vmem, mapped_size, size));
		if (base != (char*)VirtualAlloc(base, size, MEM_COMMIT, 
						PAGE_NOACCESS)) 

⌨️ 快捷键说明

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