mirror of
https://github.com/boostorg/iostreams.git
synced 2026-02-27 17:12:17 +00:00
295 lines
9.0 KiB
C++
Executable File
295 lines
9.0 KiB
C++
Executable File
// (C) Copyright Craig Henderson 2002 'boost/memmap.hpp' from sandbox
|
|
// (C) Copyright Jonathan Turkanis 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>
|
|
#include <boost/iostreams/device/mapped_file.hpp>
|
|
#include <boost/iostreams/detail/config/dyn_link.hpp>
|
|
#include <boost/iostreams/detail/config/windows_posix.hpp>
|
|
#include <boost/iostreams/detail/ios.hpp> // failure.
|
|
|
|
|
|
#ifdef BOOST_IOSTREAMS_WINDOWS
|
|
# define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
|
# include <windows.h>
|
|
#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
|
|
|
|
namespace boost { namespace iostreams {
|
|
|
|
namespace detail {
|
|
|
|
struct mapped_file_impl {
|
|
mapped_file_impl() : error_(false) { clear(false); }
|
|
~mapped_file_impl() { close(); }
|
|
void clear(bool error)
|
|
{
|
|
data_ = 0;
|
|
size_ = 0;
|
|
mode_ = BOOST_IOS::openmode();
|
|
error_ = error;
|
|
handle_ = 0;
|
|
#ifdef BOOST_IOSTREAMS_WINDOWS
|
|
mapped_handle_ = 0;
|
|
#endif
|
|
}
|
|
void close()
|
|
{
|
|
if (!handle_)
|
|
return;
|
|
#ifdef BOOST_IOSTREAMS_WINDOWS
|
|
::SetLastError(0);
|
|
::UnmapViewOfFile(data_);
|
|
::CloseHandle(mapped_handle_);
|
|
::CloseHandle(handle_);
|
|
error_ = ::GetLastError() != NO_ERROR;
|
|
#else
|
|
errno = 0;
|
|
::munmap(reinterpret_cast<char *>(data_), size_);
|
|
::close(handle_);
|
|
error_ = errno != 0;
|
|
#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
|
|
};
|
|
|
|
} // End namespace detail.
|
|
|
|
mapped_file_source::mapped_file_source( const std::string& path,
|
|
mapped_file_source::size_type length,
|
|
boost::intmax_t offset )
|
|
{ open(path, BOOST_IOS::in, length, offset); }
|
|
|
|
void mapped_file_source::open( const std::string& path, size_type length,
|
|
boost::intmax_t offset )
|
|
{ open(path, BOOST_IOS::in, length, offset); }
|
|
|
|
mapped_file_source::size_type mapped_file_source::size() const
|
|
{ return pimpl_->size_; }
|
|
|
|
bool mapped_file_source::is_open() const
|
|
{ return !!pimpl_ && pimpl_->handle_ != 0; }
|
|
|
|
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 //----------------------------------------------------//
|
|
|
|
void close_handles(detail::mapped_file_impl& impl)
|
|
{
|
|
::CloseHandle(impl.mapped_handle_);
|
|
::CloseHandle(impl.handle_);
|
|
impl.clear(true);
|
|
}
|
|
|
|
void mapped_file_source::open( const std::string& path,
|
|
BOOST_IOS::openmode mode, size_type length,
|
|
boost::intmax_t offset )
|
|
{
|
|
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 = (mode & BOOST_IOS::out) == 0;
|
|
pimpl_->mode_ = readonly ? BOOST_IOS::in : (BOOST_IOS::in | BOOST_IOS::out);
|
|
|
|
//--------------Open underlying file--------------------------------------//
|
|
|
|
pimpl_->handle_ =
|
|
::CreateFileA( path.c_str(),
|
|
readonly ? GENERIC_READ : GENERIC_ALL,
|
|
FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
|
|
if (pimpl_->handle_ == INVALID_HANDLE_VALUE) {
|
|
pimpl_->clear(true);
|
|
return;
|
|
}
|
|
|
|
//--------------Create mapping--------------------------------------------//
|
|
|
|
pimpl_->mapped_handle_ =
|
|
::CreateFileMappingA( pimpl_->handle_, NULL,
|
|
readonly ? PAGE_READONLY : PAGE_READWRITE,
|
|
0, 0, path.c_str() );
|
|
if (pimpl_->mapped_handle_ == NULL) {
|
|
::CloseHandle(pimpl_->handle_);
|
|
pimpl_->clear(true);
|
|
return;
|
|
}
|
|
|
|
//--------------Access data-----------------------------------------------//
|
|
|
|
void* data =
|
|
::MapViewOfFileEx( pimpl_->mapped_handle_,
|
|
readonly ? FILE_MAP_READ : FILE_MAP_WRITE,
|
|
(DWORD) (offset >> 32),
|
|
(DWORD) (offset & 0xffffffff),
|
|
length != max_length ? length : 0, 0 );
|
|
if (!data) {
|
|
close_handles(*pimpl_);
|
|
return;
|
|
}
|
|
|
|
//--------------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>(
|
|
length != max_length ?
|
|
std::min<boost::intmax_t>(length, size) :
|
|
size
|
|
);
|
|
} else {
|
|
close_handles(*pimpl_);
|
|
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>(
|
|
length != max_length ?
|
|
std::min<boost::intmax_t>(length, size) :
|
|
size
|
|
);
|
|
} else {
|
|
close_handles(*pimpl_);
|
|
return;
|
|
}
|
|
}
|
|
|
|
pimpl_->data_ = reinterpret_cast<char*>(data);
|
|
}
|
|
|
|
int mapped_file_source::alignment()
|
|
{
|
|
SYSTEM_INFO info;
|
|
::GetSystemInfo(&info);
|
|
return static_cast<int>(info.dwAllocationGranularity);
|
|
}
|
|
|
|
#else // #ifdef BOOST_IOSTREAMS_WINDOWS //-------------------------------------------//
|
|
|
|
void mapped_file_source::open( const std::string& path,
|
|
BOOST_IOS::openmode mode, size_type length,
|
|
boost::intmax_t offset )
|
|
{
|
|
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 = (mode & BOOST_IOS::out) == 0;
|
|
pimpl_->mode_ = readonly ? BOOST_IOS::in : (BOOST_IOS::in | BOOST_IOS::out);
|
|
|
|
//--------------Open underlying file--------------------------------------//
|
|
|
|
errno = 0;
|
|
pimpl_->handle_ = ::open(path.c_str(), readonly? O_RDONLY : O_RDWR);
|
|
if (errno != 0)
|
|
return;
|
|
|
|
//--------------Determine file size---------------------------------------//
|
|
|
|
bool success = true;
|
|
struct stat info;
|
|
if (length != max_length)
|
|
pimpl_->size_ = length;
|
|
else {
|
|
success = ::fstat(pimpl_->handle_, &info) != -1;
|
|
pimpl_->size_ = info.st_size;
|
|
}
|
|
if (!success) {
|
|
::close(pimpl_->handle_);
|
|
pimpl_->clear(true);
|
|
return;
|
|
}
|
|
|
|
//--------------Create mapping--------------------------------------------//
|
|
|
|
int prot = ((mode & BOOST_IOS::in) ? PROT_READ : 0) |
|
|
((mode & BOOST_IOS::out) ? PROT_WRITE : 0);
|
|
|
|
void* data = ::mmap( 0, pimpl_->size_, prot,
|
|
readonly ? MAP_PRIVATE : MAP_SHARED,
|
|
pimpl_->handle_, offset );
|
|
if (data == MAP_FAILED) {
|
|
::close(pimpl_->handle_);
|
|
pimpl_->clear(true);
|
|
return;
|
|
}
|
|
pimpl_->data_ = reinterpret_cast<char*>(data);
|
|
|
|
return;
|
|
}
|
|
|
|
int mapped_file_source::alignment()
|
|
{ return static_cast<int>(sysconf(_SC_PAGESIZE)); }
|
|
|
|
#endif // #ifdef BOOST_IOSTREAMS_WINDOWS //------------------------------------------//
|
|
|
|
} } // End namespaces iostreams, boost.
|