/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2010-2014 Danny Robson */ #include "io.hpp" #include "cast.hpp" #include "debug.hpp" #include "except.hpp" #include "posix/fd.hpp" #include "posix/except.hpp" #include using cruft::detail::posix::mapped_file; /////////////////////////////////////////////////////////////////////////////// namespace { struct overflow_error : public cruft::error { std::ostream& describe (std::ostream &os) const override { return os << "mapping is too large for the system"; } }; } ////////////////////////////////////////////////////////////////////////////// mapped_file::mapped_file (const std::filesystem::path &path, int fflags, int mflags): mapped_file (cruft::posix::fd (path, fflags), mflags) { ; } //----------------------------------------------------------------------------- mapped_file::mapped_file (::cruft::posix::fd const &src, int const mflags) { struct stat meta; ::cruft::posix::error::try_value (fstat (src, &meta)); // Zero length mappings aren't allowed by POSIX (even though they're // accepted by some systems; like Linux) if (meta.st_size == 0) { m_data = nullptr; m_size = 0; return; } // Ensure we're not trying to map more than our address space allows. // // It's a little nasty, but we protect a if constexpr (sizeof (meta.st_size) > sizeof (size_t)) { auto const hi = cruft::cast::lossless (std::numeric_limits::max ()); if (meta.st_size > hi) throw overflow_error (); } m_size = cruft::cast::lossless (meta.st_size); m_data = static_cast (mmap (nullptr, m_size, mflags, MAP_SHARED, src, 0)); if (m_data == MAP_FAILED) ::cruft::posix::error::throw_code (); } //----------------------------------------------------------------------------- mapped_file::mapped_file (cruft::mapped_file &&rhs) noexcept : m_data (std::exchange (rhs.m_data, nullptr)) , m_size (std::exchange (rhs.m_size, 0)) { ; } //---------------------------------------------------------------------------- mapped_file::~mapped_file () { if (!m_data) return; munmap (m_data, m_size); } //---------------------------------------------------------------------------- size_t mapped_file::size (void) const { return m_size; } //----------------------------------------------------------------------------- bool mapped_file::empty (void) const { return size () == 0; } ////////////////////////////////////////////////////////////////////////////// uint8_t* mapped_file::data (void) & { return m_data; } //---------------------------------------------------------------------------- const uint8_t* mapped_file::data (void) const & { return m_data; } //---------------------------------------------------------------------------- uint8_t* mapped_file::begin (void) & { return data (); } //---------------------------------------------------------------------------- uint8_t* mapped_file::end (void) & { return data () + size (); } //----------------------------------------------------------------------------- const uint8_t* mapped_file::begin (void) const & { return data (); } //----------------------------------------------------------------------------- const uint8_t* mapped_file::end (void) const & { return data () + size (); } //---------------------------------------------------------------------------- const uint8_t* mapped_file::cbegin (void) const & { return data (); } //---------------------------------------------------------------------------- const uint8_t* mapped_file::cend (void) const & { return data () + size (); }