mapped_file.cpp
来自「Boost provides free peer-reviewed portab」· C++ 代码 · 共 461 行
CPP
461 行
// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)// (C) Copyright 2004-2007 Jonathan Turkanis// (C) Copyright Craig Henderson 2002 'boost/memmap.hpp' from sandbox// (C) Copyright Jonathan Graehl 2004.// Distributed under the Boost Software License, Version 1.0. (See accompanying// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)// See http://www.boost.org/libs/iostreams for documentation.// Define BOOST_IOSTREAMS_SOURCE so that <boost/iostreams/detail/config.hpp>// knows that we are building the library (possibly exporting code), rather// than using it (possibly importing code).#define BOOST_IOSTREAMS_SOURCE#include <cassert>#ifndef NDEBUG# include <boost/iostreams/detail/absolute_path.hpp>#endif#include <boost/iostreams/detail/config/dyn_link.hpp>#include <boost/iostreams/detail/config/windows_posix.hpp>#include <boost/iostreams/detail/ios.hpp> // failure.#include <boost/iostreams/detail/system_failure.hpp>#include <boost/iostreams/device/mapped_file.hpp>#ifdef BOOST_IOSTREAMS_WINDOWS# define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers# include <windows.h># ifndef INVALID_SET_FILE_POINTER# define INVALID_SET_FILE_POINTER ((DWORD)-1)# endif#else# include <errno.h># include <fcntl.h># include <sys/mman.h> // mmap, munmap.# include <sys/stat.h># include <sys/types.h> // struct stat.# include <unistd.h> // sysconf.#endif#include <boost/iostreams/detail/config/disable_warnings.hpp>namespace boost { namespace iostreams {namespace detail {struct mapped_file_impl { mapped_file_impl() { clear(false); } ~mapped_file_impl() { try { close(); } catch (...) { } } void clear(bool error) { data_ = 0; size_ = 0; mode_ = BOOST_IOS::openmode(); error_ = error; #ifdef BOOST_IOSTREAMS_WINDOWS handle_ = INVALID_HANDLE_VALUE; mapped_handle_ = NULL; #else handle_ = 0; #endif #ifndef NDEBUG path_.erase(); #endif } void close() { bool error = false; #ifdef BOOST_IOSTREAMS_WINDOWS if (handle_ == INVALID_HANDLE_VALUE) return; error = !::UnmapViewOfFile(data_) || error; error = !::CloseHandle(mapped_handle_) || error; error = !::CloseHandle(handle_) || error; handle_ = INVALID_HANDLE_VALUE; mapped_handle_ = NULL; #else if (!handle_) return; error = ::munmap(reinterpret_cast<char*>(data_), size_) != 0 || error; error = ::close(handle_) != 0 || error; handle_ = 0; #endif data_ = 0; size_ = 0; mode_ = BOOST_IOS::openmode(); if (error) { std::string msg("error closing mapped file"); #ifndef NDEBUG msg += std::string(" (\"") + path_ + "\")"; #endif throw_system_failure(msg); } #ifndef NDEBUG path_.erase(); #endif } char* data_; std::size_t size_; BOOST_IOS::openmode mode_; bool error_;#ifdef BOOST_IOSTREAMS_WINDOWS HANDLE handle_; HANDLE mapped_handle_;#else int handle_;#endif#ifndef NDEBUG std::string path_;#endif};} // End namespace detail.//------------------Definition of mapped_file_source--------------------------//mapped_file_source::mapped_file_source(mapped_file_params p) { open(p); }mapped_file_source::mapped_file_source( const std::string& path, mapped_file_source::size_type length, boost::intmax_t offset ){ open(path, length, offset); }void mapped_file_source::open(mapped_file_params p){ p.mode &= ~BOOST_IOS::out; open_impl(p);}void mapped_file_source::open( const std::string& path, mapped_file_source::size_type length, boost::intmax_t offset ){ mapped_file_params p(path); p.mode = BOOST_IOS::in; p.length = length; p.offset = offset; open_impl(p);}mapped_file_source::size_type mapped_file_source::size() const{ return pimpl_->size_; }void mapped_file_source::close() { pimpl_->close(); }mapped_file_source::operator mapped_file_source::safe_bool() const{ return !!pimpl_ && pimpl_->error_ == false ? &safe_bool_helper::x : 0;}bool mapped_file_source::operator!() const{ return !!pimpl_ || pimpl_->error_; }BOOST_IOS::openmode mapped_file_source::mode() const { return pimpl_->mode_; }const char* mapped_file_source::data() const { return pimpl_->data_; }const char* mapped_file_source::begin() const { return data(); }const char* mapped_file_source::end() const { return data() + size(); }#ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//namespace detail {void cleanup_and_throw(detail::mapped_file_impl& impl, std::string msg){ #ifndef NDEBUG msg += std::string(" (\"") + impl.path_ + "\")"; #endif if (impl.mapped_handle_ != INVALID_HANDLE_VALUE) ::CloseHandle(impl.mapped_handle_); if (impl.handle_ != NULL) ::CloseHandle(impl.handle_); impl.clear(true); throw_system_failure(msg);}} // End namespace detail.void mapped_file_source::open_impl(mapped_file_params p){ using namespace std; if (is_open()) throw BOOST_IOSTREAMS_FAILURE("file already open"); if (!pimpl_) pimpl_.reset(new impl_type); else pimpl_->clear(false); bool readonly = (p.mode & BOOST_IOS::out) == 0; pimpl_->mode_ = readonly ? BOOST_IOS::in : (BOOST_IOS::in | BOOST_IOS::out); #ifndef NDEBUG pimpl_->path_ = detail::absolute_path(p.path); #endif //--------------Open underlying file--------------------------------------// pimpl_->handle_ = ::CreateFileA( p.path.c_str(), readonly ? GENERIC_READ : GENERIC_ALL, FILE_SHARE_READ, NULL, (p.new_file_size != 0 && !readonly) ? CREATE_ALWAYS : OPEN_EXISTING, readonly ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_TEMPORARY, NULL ); if (pimpl_->handle_ == INVALID_HANDLE_VALUE) { detail::cleanup_and_throw(*pimpl_, "failed opening file"); } //--------------Set file size---------------------------------------------// if (p.new_file_size != 0 && !readonly) { LONG sizehigh = (p.new_file_size >> (sizeof(LONG) * 8)); LONG sizelow = (p.new_file_size & 0xffffffff); DWORD result = ::SetFilePointer(pimpl_->handle_, sizelow, &sizehigh, FILE_BEGIN); if ( result == INVALID_SET_FILE_POINTER && ::GetLastError() != NO_ERROR || !::SetEndOfFile(pimpl_->handle_) ) { detail::cleanup_and_throw(*pimpl_, "failed setting file size"); } } //--------------Create mapping--------------------------------------------// try_again: // Target of goto in following section. pimpl_->mapped_handle_ = ::CreateFileMappingA( pimpl_->handle_, NULL, readonly ? PAGE_READONLY : PAGE_READWRITE, 0, 0, NULL ); if (pimpl_->mapped_handle_ == NULL) { detail::cleanup_and_throw(*pimpl_, "couldn't create mapping"); } //--------------Access data-----------------------------------------------// void* data = ::MapViewOfFileEx( pimpl_->mapped_handle_, readonly ? FILE_MAP_READ : FILE_MAP_WRITE, (DWORD) (p.offset >> 32), (DWORD) (p.offset & 0xffffffff), p.length != max_length ? p.length : 0, (LPVOID) p.hint ); if (!data) { if (p.hint != 0) { p.hint = 0; goto try_again; } detail::cleanup_and_throw(*pimpl_, "failed mapping view"); } //--------------Determing file size---------------------------------------// // Dynamically locate GetFileSizeEx (thanks to Pavel Vozenilik). typedef BOOL (WINAPI *func)(HANDLE, PLARGE_INTEGER); HMODULE hmod = ::GetModuleHandleA("kernel32.dll"); func get_size = reinterpret_cast<func>(::GetProcAddress(hmod, "GetFileSizeEx")); if (get_size) { LARGE_INTEGER info; if (get_size(pimpl_->handle_, &info)) { boost::intmax_t size = ( (static_cast<boost::intmax_t>(info.HighPart) << 32) | info.LowPart ); pimpl_->size_ = static_cast<std::size_t>( p.length != max_length ? std::min<boost::intmax_t>(p.length, size) : size ); } else { detail::cleanup_and_throw(*pimpl_, "failed getting file size"); return; } } else { DWORD hi; DWORD low; if ( (low = ::GetFileSize(pimpl_->handle_, &hi)) != INVALID_FILE_SIZE ) { boost::intmax_t size = (static_cast<boost::intmax_t>(hi) << 32) | low; pimpl_->size_ = static_cast<std::size_t>( p.length != max_length ? std::min<boost::intmax_t>(p.length, size) : size ); } else { detail::cleanup_and_throw(*pimpl_, "failed getting file size"); return; } } pimpl_->data_ = reinterpret_cast<char*>(data);}bool mapped_file_source::is_open() const{ return !!pimpl_ && pimpl_->handle_ != INVALID_HANDLE_VALUE; }int mapped_file_source::alignment(){ SYSTEM_INFO info; ::GetSystemInfo(&info); return static_cast<int>(info.dwAllocationGranularity);}#else // #ifdef BOOST_IOSTREAMS_WINDOWS //------------------------------------//namespace detail { void cleanup_and_throw(detail::mapped_file_impl& impl, std::string msg){ #ifndef NDEBUG msg += std::string(" (\"") + impl.path_ + "\")"; #endif if (impl.handle_ != 0) ::close(impl.handle_); impl.clear(true); throw_system_failure(msg);}} // End namespace detail.void mapped_file_source::open_impl(mapped_file_params p){ using namespace std; if (is_open()) throw BOOST_IOSTREAMS_FAILURE("file already open"); if (!pimpl_) pimpl_.reset(new impl_type); else pimpl_->clear(false); bool readonly = (p.mode & BOOST_IOS::out) == 0; pimpl_->mode_ = readonly ? BOOST_IOS::in : (BOOST_IOS::in | BOOST_IOS::out); #ifndef NDEBUG pimpl_->path_ = detail::absolute_path(p.path); #endif //--------------Open underlying file--------------------------------------// int flags = (readonly ? O_RDONLY : O_RDWR); if (p.new_file_size != 0 && !readonly) flags |= (O_CREAT | O_TRUNC); errno = 0; pimpl_->handle_ = ::open(p.path.c_str(), flags, S_IRWXU); if (errno != 0) detail::cleanup_and_throw(*pimpl_, "failed opening file"); //--------------Set file size---------------------------------------------// if (p.new_file_size != 0 && !readonly) if (ftruncate(pimpl_->handle_, p.new_file_size) == -1) detail::cleanup_and_throw(*pimpl_, "failed setting file size"); //--------------Determine file size---------------------------------------// bool success = true; struct stat info; if (p.length != max_length) pimpl_->size_ = p.length; else { success = ::fstat(pimpl_->handle_, &info) != -1; pimpl_->size_ = info.st_size; } if (!success) detail::cleanup_and_throw(*pimpl_, "failed getting file size"); //--------------Create mapping--------------------------------------------// try_again: // Target of goto in following section. char* hint = const_cast<char*>(p.hint); void* data = ::mmap( hint, pimpl_->size_, readonly ? PROT_READ : (PROT_READ | PROT_WRITE), readonly ? MAP_PRIVATE : MAP_SHARED, pimpl_->handle_, p.offset ); if (data == MAP_FAILED) { if (hint != 0) { hint = 0; goto try_again; } detail::cleanup_and_throw(*pimpl_, "failed mapping file"); } pimpl_->data_ = reinterpret_cast<char*>(data); return;}bool mapped_file_source::is_open() const{ return !!pimpl_ && pimpl_->handle_ != 0; }int mapped_file_source::alignment(){ return static_cast<int>(sysconf(_SC_PAGESIZE)); }#endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------////------------------Implementation of mapped_file-----------------------------//mapped_file::mapped_file(mapped_file_params p) { delegate_.open_impl(p); }mapped_file::mapped_file( const std::string& path, BOOST_IOS::openmode mode, size_type length, stream_offset offset ){ open(path, mode, length, offset); }void mapped_file::open(mapped_file_params p){ delegate_.open_impl(p); }void mapped_file::open( const std::string& path, BOOST_IOS::openmode mode, size_type length, stream_offset offset ){ mapped_file_params p(path); p.mode = mode; p.length = length; p.offset = offset; open(p);}//------------------Implementation of mapped_file_sink------------------------//mapped_file_sink::mapped_file_sink(mapped_file_params p) { open(p); }mapped_file_sink::mapped_file_sink( const std::string& path, size_type length, stream_offset offset ){ open(path, length, offset); }void mapped_file_sink::open(mapped_file_params p){ p.mode |= BOOST_IOS::out; p.mode &= ~BOOST_IOS::in; mapped_file::open(p);}void mapped_file_sink::open( const std::string& path, size_type length, stream_offset offset ){ mapped_file_params p(path); p.mode = BOOST_IOS::out; p.length = length; p.offset = offset; open(p);}//----------------------------------------------------------------------------//} } // End namespaces iostreams, boost.#include <boost/iostreams/detail/config/enable_warnings.hpp>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?