lyx_mirror/boost/libs/iostreams/src/mapped_file.cpp
Lars Gullik Bjønnes d64a07a784 Update in-tree boost to latest from boost 1.34 cvs.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@14895 a592a061-630c-0410-9148-cb99ea01b6c8
2006-09-05 07:18:36 +00:00

417 lines
13 KiB
C++

// (C) Copyright Craig Henderson 2002 'boost/memmap.hpp' from sandbox
// (C) Copyright Jonathan Turkanis 2004.
// (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>
#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>
#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 (std::exception&) { } }
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
}
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)
throw_system_failure("error closing mapped file");
}
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.
//------------------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_; }
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 //---------------------------------------------//
namespace detail {
void cleanup_and_throw(detail::mapped_file_impl& impl, const char* msg)
{
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);
//--------------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,
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);
::SetFilePointer(pimpl_->handle_, sizelow, &sizehigh, FILE_BEGIN);
if (::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);
}
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, const char* msg)
{
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);
//--------------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;
}
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>