mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-02 14:01:10 +00:00
d64a07a784
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@14895 a592a061-630c-0410-9148-cb99ea01b6c8
417 lines
13 KiB
C++
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>
|