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

📄 file.cxx

📁 完全免费的邮件发送程序。delphi 6.0
💻 CXX
📖 第 1 页 / 共 4 页
字号:
    sigaction(SIGBUS, &sigact, NULL);
#endif
    sigaction(SIGILL, &sigact, NULL);
    sigaction(SIGABRT, &sigact, NULL);
#endif
    error_code = ok;
}

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

char* file::get_error_text(char* buf, size_t buf_size)
{
    char* err_txt;
    switch (error_code) {
      case ok: 
	err_txt = "no error";
	break;
      case file_size_not_aligned:
	err_txt = "size of file is not aligned on page 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: 
	err_txt = strerror(error_code);
    }
    return strncpy(buf, err_txt, buf_size);
}

inline bool file::recover_file()
{
    ssize_t rc, trans_size = page_size + sizeof(long);
    int n_recovered_pages = 0;
    TRACE_MSG(("file::recover_file: recover data file from transaction log\n"));
    while ((rc = read(log, log_buffer, trans_size)) == trans_size) { 
	memcpy(base + *(long*)log_buffer, log_buffer+sizeof(long), page_size);
	n_recovered_pages += 1;
    }
    if (rc != 0) {
	if (rc < 0) { 
	    error_code = errno;
	    TRACE_MSG(("file::recover: log read failed: %s\n", 
		       strerror(error_code)));
	} else { 
	    error_code = end_of_file;	
	    TRACE_MSG(("file::recover: expected end of log\n"));
	}
	return false;
    }
    allocated_size = 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;
}


bool file::open(open_mode mode, access_prot prot) 
{
    assert(name != NULL);
    if (prot == read_only) { 
	mode = map_file;
    } 
    this->mode = mode;
    this->prot = prot;

    if (mode == shadow_pages_transaction) {
	fd = ::open(name, O_RDWR|O_CREAT|O_SYNC, 0777);
	if (fd < 0) { 
	    error_code = errno;
	    TRACE_MSG(("file::open: failed to open file '%s': %s\n",
		       name, strerror(error_code)));
	    return false;
	}
	file_header hdr;
	hdr.base_address = NULL;
	hdr.file_size = 0;
	read(fd, &hdr, sizeof hdr);
	base = (char*)hdr.base_address;
	allocated_size = size = ALIGN(hdr.file_size, page_size);
	mapped_size = size > max_file_size ? size : max_file_size;
	void* p = mmap(base, mapped_size, PROT_READ|PROT_WRITE,
		       MAP_VARIABLE|MAP_SHARED|MAP_FILE, fd, 0);
	if (p == (char*)MAP_FAILED) { 
	    error_code = errno;
	    TRACE_MSG(("file::open: mmap failed: base=%p, size=%ld: %s\n",
		       base, mapped_size, strerror(error_code)));
	    ::close(fd);
	    return false;
	}
	base = (char*)p;
	n_locked_pages = 0;

	int log_flags = O_RDWR;
	if (max_locked_pages == 0) { 
	    log_flags |= O_SYNC;
	}
	log = ::open(log_name, log_flags, 0); 
	if (log < 0) { 
	    if (errno != ENOENT || 
		(log = ::open(log_name, log_flags|O_CREAT, 0777)) < 0)
	    {
		error_code = errno;
		TRACE_MSG(("file::open: failed to open log file '%s': %s\n",
			   log_name, strerror(error_code)));
		munmap(base, mapped_size);
		::close(fd);
		return false;
	    }
	    if (size != 0 && mprotect(base, size, PROT_READ) != ok) {
		error_code = errno;
		TRACE_MSG(("file::open: mprotect failed: address=%p, size=%ld:"
			   " %s\n", base, size, strerror(error_code)));
		munmap(base, mapped_size);
		::close(fd);
		::close(log);
		return false;
	    }
	    next = chain;
	    chain = this;
	} else { 
	    next = chain;
	    chain = this;
	    recover_file();
	    if (!commit()) { 
		chain = next;
		munmap(base, mapped_size);
		::close(fd);
		::close(log);
		return false;
	    }
	}
    } else { // mapping file in non-transaction mode
	int open_mode = O_RDONLY;
	if (prot != read_only) { 
	    if (mode == map_file) { 
		open_mode = O_RDWR|O_CREAT;
	    } else if (mode == copy_on_write_map) {
		open_mode = O_RDWR;
	    }
	} else { 
	    open_mode = O_RDWR; // to make it possible to change memory object protection
	}

	fd = ::open(name, open_mode, 0777);
	base = NULL;
	int d;
	if (fd >= 0) { 
	    size_t rc = read(fd, &base, sizeof base);
	    if (rc != 0 && rc != sizeof base) { 
		error_code = errno;
		TRACE_MSG(("file::open: failed to read from file '%s': %s\n",
			   name, strerror(error_code)));
		::close(fd);
		return false;
	    }
	    size = ALIGN(lseek(fd, 0, SEEK_END), allocation_granularity);
	    TRACE_MSG(("file::open: file '%s' exists: size=%ld, base=%p\n", 
		       name, size, base));
	} else { 
	    error_code = errno;
	    TRACE_MSG(("file::open: can't open file '%s', %s\n", 
		       name, strerror(error_code)));
	    if (error_code != ENOENT || mode == map_file) { 
		return false;
	    }
	    if (prot == read_only) {
		TRACE_MSG(("file::open: failed to open storage in read_only "
			   "mode because file '%s' doesn't exist\n", name));
		return false;
	    }
	    size = 0;
	}
	mapped_size = (prot == read_only || size > max_file_size) 
	    ? size : max_file_size;
	allocated_size = size;

	int mmap_attr = (mode == map_file) 
	    ? MAP_VARIABLE|MAP_SHARED : MAP_VARIABLE|MAP_PRIVATE;

	if (fd >= 0 && mode != load_in_memory) {
	    mmap_attr |= MAP_FILE;
	    d = fd;
	} else {
#ifndef MAP_ANONYMOUS
	    d = dev_zero;
#else
	    d = -1;
	    mmap_attr |= MAP_ANONYMOUS;
#endif
	}
	int mmap_prot = 
	    (prot == read_only) ? PROT_READ : PROT_READ|PROT_WRITE;
	void* p = mmap(base, mapped_size, mmap_prot, mmap_attr, d, 0);
	if (p == (void*)MAP_FAILED) { 
	    error_code = errno;
	    TRACE_MSG(("file::open: mmap to %p failed: %s\n", 
		       base, strerror(error_code)));
	    if (fd >= 0) { 
		::close(fd);
	    }
	    return false;
	}
	TRACE_MSG(("file::open: map file to address %p\n", p));
	base = (char*)p;
	
	if (fd >= 0 && mode == load_in_memory) { 
	    //
	    // Read file to memory
	    //
	    lseek(fd, 0, SEEK_SET);
	    if ((size_t)read(fd, base, size) != size) { 
		error_code = errno;
		TRACE_MSG(("file::open: failed to read file in memory: %s\n", 
			   strerror(error_code)));
		munmap(base, mapped_size);
		::close(fd);
		return false;
	    }
	    ::close(fd); // file is nor more needed
	    fd = -1;
	}
    } 
    error_code = ok;
    return true;
}

bool file::set_size(size_t new_size)
{
    new_size = ALIGN(new_size, allocation_granularity);
    if (new_size > mapped_size) { 
	error_code = file_mapping_size_exceeded;
	return false;
    } 
    if (fd >= 0 && new_size > allocated_size) { 
	allocated_size = ALIGN(new_size, file_extension_granularity);
	if (ftruncate(fd, allocated_size) != ok) { 
	    error_code = errno;
	    return false;
	}
    }
    error_code = ok;
    size = new_size;
    return true;
}

bool file::set_protection(access_prot prot) 
{
    if (mprotect(base, mapped_size, 
		 prot == read_only ? PROT_READ : PROT_READ|PROT_WRITE) != ok)
    {
	error_code = errno;
	return false;
    } else { 
	error_code = ok;
	this->prot = prot;
	return true;
    }
}

bool file::commit()
{
    if (mode != shadow_pages_transaction) { 
	error_code = not_in_transaction;
	return false;
    }
    if (n_locked_pages != 0 && !flush_log_buffer()) { 
	return false;
    }
    if (size > 0 && msync(base, size, MS_SYNC) != ok) { 
	error_code = errno;
	TRACE_MSG(("file::commit: msync failed for address %p size %ld: %s\n", 
		   base, size, strerror(error_code)));
	return false;
    }
    if (lseek(log, 0, SEEK_SET) != 0 ||
	ftruncate(log, 0) != ok) 
    {
	error_code = errno;
	TRACE_MSG(("file::commit: failed to truncate log file: %s\n",
		   strerror(error_code)));
	return false;
    }
    if (size > 0 && mprotect(base, size, PROT_READ) != ok) {
	error_code = errno;
	TRACE_MSG(("file::commit: mprotect failed for address %p size %ld: "
		   "%s\n", base, size, strerror(error_code)));
	return false;
    }
    error_code = ok;
    return true;
}

bool file::rollback()
{
    if (mode != shadow_pages_transaction) { 
	error_code = not_in_transaction;
	return false;
    }
    if (lseek(log, 0, SEEK_SET) != 0) { 
	error_code = errno;
	TRACE_MSG(("file::rollback; failed to set position in log file: %s\n", 
		   strerror(error_code)));
	return false;
    }
    return recover_file();
}

bool file::flush() 
{
    if (prot == read_only) {
	return true;
    }
    if (mode == shadow_pages_transaction) { 
	return commit();
    } else if (mode == map_file) { 
	if (size > 0 && msync(base, size, MS_ASYNC) != ok) { 
	    TRACE_MSG(("file::flush: failed to flush file: %s\n",
		       strerror(error_code)));
	    return false;
	}
	error_code = ok;
	return true;
    } else { 
	int new_fd = ::open(tmp_name, O_WRONLY|O_CREAT|O_TRUNC, 0666);
	if (new_fd < 0) { 
	    error_code = errno;
	    return false;
	}
	if ((size_t)write(new_fd, base, size) != size) { 
	    error_code = errno;
	    ::close(new_fd);
	    return false;
	}
	::close(new_fd);
	if (rename(tmp_name, name) != ok) { 
	    error_code = errno;
	    return false;
	}
	error_code = ok;
	return true;
    }
}

bool file::close()
{
    if (base == NULL) { 
	if (fd >= 0 && ::close(fd) != ok) { 
	    error_code = errno;
	    TRACE_MSG(("file::close: failed to close file: %s\n",
		       strerror(error_code)));
	    return false;
	}
	return true;
    }
    if (mode == shadow_pages_transaction) { 
	file *fp, **fpp = &chain;
	while ((fp = *fpp) != this) { 
	    fpp = &fp->next;
	}
	*fpp = fp->next;
	    
	if (n_locked_pages != 0 && !flush_log_buffer()) { 
	    return false;
	}
    }
    if (munmap(base, mapped_size) != ok) { 
	error_code = errno;
	TRACE_MSG(("file::close: failed to unmap memory segment: %s\n",
		   strerror(error_code)));
	return false;
    }
    if (fd >= 0) {
	if (size != allocated_size) { 
	    if (ftruncate(fd, size) != ok) {
		error_code = errno;
		TRACE_MSG(("file::close: failed to truncate file: %s\n",
			   strerror(error_code)));
		return false;
	    }
	}
	if (::close(fd) != ok) {
	    error_code = errno;
	    TRACE_MSG(("file::close: failed to close file: %s\n",
		       strerror(error_code)));
	    return false;
	}
    }
    if (mode == shadow_pages_transaction) { 
	if (::close(log) != ok) { 
	    TRACE_MSG(("file::close: failed to close transaction log file: "
		       "%s\n", strerror(errno)));
	}
	if (unlink(log_name) != ok) {
	    TRACE_MSG(("file::close: failed to remove transaction log file: "
		       "%s\n", strerror(errno)));
	}
    }
    error_code = ok;
    return true;	
}

char* file::get_program_timestamp()
{
    static char buf[32];
    if (program_compilation_time == NULL) { 
	char* image = getenv("_");
	assert(image != NULL);
	struct stat fs;
	int rc = stat(image, &fs);
	assert(rc == 0);
	struct tm* fmtime = localtime(&fs.st_mtime);
	sprintf(buf, "%02d.%02d.%04d %02d:%02d.%02d", 
		fmtime->tm_mday, fmtime->tm_mon, fmtime->tm_year+1900,
		fmtime->tm_hour, fmtime->tm_min, fmtime->tm_sec);
	return buf;
    }
    return program_compilation_time;
}

#endif // Unix


#if 0 && DEBUG_LEVEL >= DEBUG_CHECK
//
// Sometimes it is more convenient to catch SIGSEGV instead of SIGABRT. 
// For example in Digital Unix debugger failed to unroll stack after
// assertion failure. And in Windows NT assertion failure will not cause
// invocation of debugger if program is not started from MSDEV. That is
// why this "strange" version of abort() was implemented. 
//
#ifndef _DEBUG
extern "C" 
void abort() { while(1) *(int*)0 = 0; /* do not return */ }
#endif
#endif


⌨️ 快捷键说明

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