/* * Simple mmap support * * Copyright (C) 2006--2008 Enrico Zini * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #ifdef POSIX #include #include #include #include #include #include #include #include #include using namespace std; namespace wibble { namespace sys { MMap::MMap() : size(0), fd(-1), buf(0) {} MMap::MMap(const std::string& filename) : size(0), fd(-1), buf(0) { // If map throws here, the destructor isn't called (since we're in the // constructor), so we do the cleanup and rethrow. try { map(filename); } catch (...) { unmap(); throw; } } MMap::MMap(const MMap& mmap) : filename(mmap.filename), size(mmap.size), fd(mmap.fd), buf(mmap.buf) { // Cast away const to have auto_ptr semantics MMap* wm = const_cast(&mmap); wm->filename.clear(); wm->size = 0; wm->fd = -1; wm->buf = 0; } MMap& MMap::operator=(const MMap& mmap) { // Handle assignment to self if (this == &mmap) return *this; if (fd) unmap(); filename = mmap.filename; size = mmap.size; fd = mmap.fd; buf = mmap.buf; // Cast away const to have auto_ptr semantics MMap* wm = const_cast(&mmap); wm->filename.clear(); wm->size = 0; wm->fd = -1; wm->buf = 0; return *this; } MMap::~MMap() { unmap(); } void MMap::map(const std::string& filename) { if (buf) unmap(); try { this->filename = filename; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" // Open the file if ((fd = open(filename.c_str(), O_RDONLY)) == -1) throw wibble::exception::System("opening index file " + filename); size = lseek(fd, 0, SEEK_END); if (off_t(size) == off_t(-1)) throw wibble::exception::System("reading the size of index file " + filename); if (size == 0) throw wibble::exception::Consistency("ensuring that there is data in the index", "the mmap index file " + filename + " is empty"); // Map the file into memory if ( ( buf = reinterpret_cast< const char* >( ::mmap( 0, size, PROT_READ, MAP_PRIVATE, fd, 0 ) ) ) == MAP_FAILED ) throw wibble::exception::System("mmapping file " + filename); #pragma GCC diagnostic pop } catch (...) { unmap(); throw; } } void MMap::unmap() { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" // Unmap and close the file if (buf) { if (buf != MAP_FAILED) munmap(const_cast(buf), size); buf = 0; size = 0; } if (fd != -1) { close(fd); fd = -1; } filename.clear(); #pragma GCC diagnostic pop } } } #endif // vim:set ts=4 sw=4: