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

📄 file.cxx

📁 完全免费的邮件发送程序。delphi 6.0
💻 CXX
📖 第 1 页 / 共 4 页
字号:
		    return false;
		}
	    }
	} else { // windows 95
	    if (fd != INVALID_HANDLE_VALUE) { 
		CloseHandle(fd);
		fd = INVALID_HANDLE_VALUE;
	    }
	    BOOL backup = MoveFile(name, sav_name);// may be exists, may be not
	    if (!backup && GetLastError() == ERROR_ALREADY_EXISTS) {
		DeleteFile(sav_name); // remove previous backup file
		backup = MoveFile(name, sav_name);
		if (!backup) { 
		    error_code = GetLastError();
		    TRACE_MSG(("file::flush: failed to make backup copy of "
			       "file '%s'\n", name));
		    return false;
		}
	    }
	    if (!MoveFile(tmp_name, name)) { 
		error_code = GetLastError();
		TRACE_MSG(("file::flush: failed to rename file '%s' to '%s'\n",
			   tmp_name, name));
		return false;
	    }
	    if (backup) { 
		DeleteFile(sav_name); 
	    }
	}
	error_code = ok;
	return true;
    }
}

bool file::close()
{
    if (mode == shadow_pages_transaction) { 
	file *fp, **fpp = &chain;
	while ((fp = *fpp) != this) { 
	    fpp = &fp->next;
	}
	*fpp = fp->next;
	    
	if (n_locked_pages != 0 || platform != VER_PLATFORM_WIN32_NT) { 
	    if (!flush_log_buffer()) { 
		return false;
	    }
	}
	if (platform != VER_PLATFORM_WIN32_NT) { 
	    if (!write_dirty_pages_in_file()) {
		return false;
	    }
	    delete[] dirty_page_map;
	}
    }
    if (vmem != NULL) { 
	if (!VirtualFree(vmem, 0, MEM_RELEASE)) { 
	    error_code = GetLastError();
	    TRACE_MSG(("file::close: failed to free %p: %d\n", 
		       vmem, error_code));
	    return false;
	}
    }
    if (md != NULL) { 
        if (!UnmapViewOfFile(base)) { 
	    error_code = GetLastError();
	    TRACE_MSG(("file::close: failed to unmap %p: %d\n", 
		       base, error_code));
	    return false;
	}
	if (!CloseHandle(md)) { 
	    error_code = GetLastError();
	    TRACE_MSG(("file::close: failed to close file mapping: %d\n",
		       error_code));
	    return false;
	}	    
    }
    if ((mode == shadow_pages_transaction 
	 && platform == VER_PLATFORM_WIN32_NT) 
	|| mode == map_file)
    {
	if (SetFilePointer(fd, size, NULL, FILE_BEGIN) != size ||
	    !SetEndOfFile(fd)) 
	{ 
	    error_code = GetLastError();
	    TRACE_MSG(("file::close: failed to change size of file to %ld: "
		       "%d\n", size, error_code));
	    return false;
	}	    	    
    }
    if (fd != INVALID_HANDLE_VALUE) { 
	if (!CloseHandle(fd)) { 	    
 	    error_code = GetLastError();
	    TRACE_MSG(("file::close: failed to close file: %d\n", error_code));
	    return false;
	}
    }
    if (mode == shadow_pages_transaction) { 
	if (!CloseHandle(log)) { 
	    TRACE_MSG(("file::close: CloseHandle for log failed: %d\n", 
		       GetLastError()));
	}
	if (!DeleteFile(log_name)) { 
	    TRACE_MSG(("file::close: failed to remove log file: %d\n", 
		       GetLastError()));
	}
    }
    error_code = ok;
    return true;
}

char* file::get_error_text(char* buf, size_t buf_size)
{
    char* err_txt;
    char errbuf[64];

    switch (error_code) {
      case ok: 
	err_txt = "no error";
	break;
      case file_size_not_aligned:
	err_txt = "size of file is not aligned on segment boundary";
	break;
      case file_mapping_size_exceeded:
	err_txt = "attempt to exeed the limit on mapped object size";
	break;
      case not_in_transaction:
	err_txt = "operation is possible only inside transaction"; 
	break;
      case end_of_file:
	err_txt = "unexpected end of file"; 
	break;
      default: 
	if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
			  NULL, error_code, 0,
			  buf, buf_size, NULL) > 0)
	{
	    return buf;
	} else { 
	    sprintf(errbuf, "unknown error code %u", error_code);
	    err_txt = errbuf;
	}
    }
    return strncpy(buf, err_txt, buf_size);
}

char* file::get_program_timestamp()
{
    static char buf[32];
    char program_name[MAX_PATH];
    GetModuleFileName(NULL, program_name, sizeof program_name);
    FILETIME mftime;
    SYSTEMTIME mstime;
    HANDLE program = CreateFile(program_name, GENERIC_READ, 
				FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    
    if (program != INVALID_HANDLE_VALUE) { 
	if (GetFileTime(program, NULL, NULL, &mftime)
	    && FileTimeToSystemTime(&mftime, &mstime))
	{
	    sprintf(buf, "%02d.%02d.%04d %02d:%02d.%02d", 
		    mstime.wDay, mstime.wMonth, mstime.wYear, 		    
		    mstime.wHour, mstime.wMinute, mstime.wSecond);
	} 
	CloseHandle(program);
    } 
    assert(*buf != '\0'); 
    return buf;
}

#else // Unix

#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/resource.h>

#ifdef SA_SIGINFO
#if defined(__linux__) && !defined(__alpha__)
#undef SA_SIGINFO  // Intel Linux doesn't set sa_addr in siginfo 
#define SA_SIGINFO 0 
#else
#include <sys/siginfo.h>
#endif
#else
#if defined(__linux__) // Linux 5.0 doesn't define sigcontext 
#define sigcontext_struct sigcontext
#include <asm/sigcontext.h>
#endif
#define SA_SIGINFO 0
#endif

#ifndef SA_RESTART
#define SA_RESTART 0
#endif

#ifndef MAP_FAILED
#define MAP_FAILED (-1)
#endif

#ifndef MAP_FILE
#define MAP_FILE 0
#endif

#ifndef MAP_VARIABLE
#define MAP_VARIABLE 0
#endif

#ifndef MAP_NORESERVE
// This attrbute used in Solaris to avoid reservation space in swap file
#define MAP_NORESERVE 0
#endif

#define USE_WRITEV 1 // most modern Unix-s have this function
#ifdef USE_WRITEV
#include <sys/uio.h>
#endif

#define USE_FDATASYNC 0 // more efficient version of fsync()

#ifndef O_SYNC
#define O_SYNC O_FSYNC
#endif

// minimal number of pages appended to the file at each file extensin
#define FILE_EXTENSION_QUANTUM 256

//
// mlock(), munlock() functions can be used in transaction mode to 
// provide buffering of shadow pages writes to transaction log.
// In Unix unly superuser can use this functions. Method file::open()
// will check if it is possible to use mlock() function.
// 
#if !defined(__osf__) && !defined(_AIX) && !defined(__hpux__)
// These systems doesn't support mlock() 
#define USE_MLOCK 1
#endif

#ifndef USE_MLOCK
#undef mlock
#undef munlock
#define mlock(p, s) -1
#define munlock(p, s) -1
#endif

#ifndef MAP_ANONYMOUS 
int dev_zero = open("/dev/zero", O_RDONLY, 0);
#endif

#if defined(__sun__)
extern "C" int getpagesize(void);
#endif

bool file::handle_page_modification(void* addr) 
{
    for (file* fp = chain; fp != NULL; fp = fp->next) { 
	if (size_t((char*)addr - fp->base) < fp->mapped_size) { 
	    return fp->prot != read_only && fp->create_shadow_page(true, addr);
	}
    }  
    return false;
} 

//
// It will takes a lot of time and disk space to produce core file
// for program with huge memory mapped segment. This option allows you
// to automatically start debugger when some exception is happened in program.
//
#define CATCH_SIGNALS 1

#ifdef CATCH_SIGNALS
#include <signal.h>

#define WAIT_DEBUGGER_TIMEOUT 10

static void fatal_error_handler(int signo) { 
    char  buf[64];
    char* exe_name = getenv("_"); // defined by BASH
    if (exe_name == NULL) { 
	exe_name = "a.out";
    }
    fprintf(stderr, "\
Program catch signal %d.\n\
Input path to executable file to debug or press Ctrl/C to terminate program:\n\
[%s] ", 
	    signo, exe_name);
    int pid = getpid();
    if (fgets(buf, sizeof buf, stdin)) { 
	char pid_str[16];
	int len = strlen(buf);
	if (len > 1) { 
	    buf[len-1] = '\0'; // truncate '\n'
	    exe_name = buf;
	}
	sprintf(pid_str, "%d", pid); 
	if (fork()) { 
	    sleep(WAIT_DEBUGGER_TIMEOUT);
	} else { 
	    execlp("gdb", "gdb", "-q", "-s", exe_name, exe_name, pid_str, 0);
	}
    } else { 
	kill(pid, SIGKILL);
    }
}
#endif


inline bool file::flush_log_buffer()
{
#if USE_FDATASYNC
    if (fdatasync(log) != ok) { 
#else
    if (fsync(log) != ok) { 
#endif
	error_code = errno;
	TRACE_MSG(("file::flush_log_buffer: fsync failed: %s\n", 
		   strerror(error_code)));
	return false;
    }
    for (int i = n_locked_pages; --i >= 0;) { 
	if (munlock(locked_page[i], page_size) != ok) { 
	    error_code = errno;
	    TRACE_MSG(("file::flush_log_buffer: munlock %p failed: %s\n",
		       locked_page[i], strerror(error_code)));
	    return false;
	}
    }
    n_locked_pages = 0;
    return true;
}

bool file::create_shadow_page(int, void* addr)
{
    char* page = (char*)(long(addr) & ~(page_size-1));
    if (mprotect(page, page_size, PROT_READ|PROT_WRITE) != ok) { 
	TRACE_MSG(("file::create_shadow_page: mprotect failed for %p: %s\n", 
		   page, strerror(errno)));
	return false;
    }
#if USE_WRITEV
    iovec iov[2];
    long offs = page - base;
    iov[0].iov_base = (char*)&offs;
    iov[0].iov_len = sizeof offs;
    iov[1].iov_base = page;
    iov[1].iov_len = page_size;
    if ((size_t)writev(log, iov, 2) != sizeof(long) + page_size) { 
	TRACE_MSG(("file::create_shadow_page: writev failed: %s\n",
		   strerror(errno)));
	return false;
    }
#else
    *(long*)log_buffer = page - base;
    memcpy(log_buffer + sizeof(long), page, page_size);
    size_t trans_size = page_size + sizeof(long);
    if (write(log, log_buffer, trans_size) != trans_size) { 
	TRACE_MSG(("file::create_shadow_page: failed to write log file: %s\n", 
		   strerror(errno)));
	return false;
    }
#endif
    if (max_locked_pages != 0) { 
	if (n_locked_pages >= max_locked_pages) { 
	    return flush_log_buffer();
	}  
	if (mlock(page, page_size) != ok) { 
	    TRACE_MSG(("file::create_shadow_page: mlock %p failed: %s\n", 
		       page, strerror(errno)));
	    if (n_locked_pages != 0) { 
		max_locked_pages = n_locked_pages;
	    }
	    return flush_log_buffer();
	}  
	locked_page[n_locked_pages++] = page;
    }
    return true;
}


#if defined(__linux__) && !defined(__alpha__)
static void sigsegv_handler(int, struct sigcontext scp)
#elif defined(_AIX) || defined(__FreeBSD__)
static void sigsegv_handler(int, int, struct sigcontext *scp)
#else
static void sigsegv_handler(int, siginfo_t *info)
#endif
{
    char* fault_addr;
#if defined(__linux__) && !defined(__alpha__)
    fault_addr = (char*)scp.cr2;
#elif defined(_AIX)
    fault_addr = (char*)scp->sc_jmpbuf.jmp_context.o_vaddr;
#elif defined(__FreeBSD__)
    fault_addr = (char*)scp->sc_err;
#else
    fault_addr = (char*)info->si_addr;
#endif

    if (!file::handle_page_modification(fault_addr)) {
	kill(getpid(), SIGABRT);
    }
}

file::file(const char* name, size_t max_file_size, size_t max_locked_pages)
{
    // reserver one char for backup/log file names construction
    set_file_name(name);
#ifndef USE_MLOCK
    max_locked_pages = 0;
#else
    if (max_locked_pages != 0) { 
	// Check if we can use mlock()
	if (mlock((char*)this, page_size) != ok) { 
	    max_locked_pages = 0;
	    TRACE_MSG(("file::open: mlock test failed: %s\n",
		       strerror(errno)));
	} else { 
	    munlock((char*)this, page_size);
	}
    }
#endif
    allocation_granularity = page_size = getpagesize();

    struct rlimit mem_limit;
    if (getrlimit(RLIMIT_DATA, &mem_limit) == ok) { 
	if (max_file_size > size_t(mem_limit.rlim_cur)) { 
	    max_file_size = mem_limit.rlim_cur & ~(allocation_granularity-1);
	    TRACE_MSG(("file::file: set max_file_size to %ld bytes\n", 
		       max_file_size));
	}
    } else {
	TRACE_MSG(("file::file: getrlimit failed: %s\n", strerror(errno)));
    }

    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];
    file_extension_granularity = FILE_EXTENSION_QUANTUM*page_size;

    static struct sigaction sigact; 
    sigact.sa_handler = (void(*)(int))sigsegv_handler;
    sigact.sa_flags = SA_RESTART|SA_SIGINFO;
    sigaction(SIGSEGV, &sigact, NULL);
#if defined(__FreeBSD__)
    sigaction(SIGBUS, &sigact, NULL);
#endif
#ifdef CATCH_SIGNALS
    sigact.sa_flags = 0;
    sigact.sa_handler = fatal_error_handler;
#if !defined(__FreeBSD__)

⌨️ 快捷键说明

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