/* * 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 2014 Danny Robson */ #include "io_win32.hpp" #include "win32/except.hpp" #include "win32/windows.hpp" #include "debug/panic.hpp" #include using cruft::detail::win32::mapped_file; /////////////////////////////////////////////////////////////////////////////// static constexpr DWORD fflags_to_generic (int flags) { switch (flags) { case O_RDONLY: return GENERIC_READ; case O_WRONLY: return GENERIC_WRITE; case O_RDWR: return GENERIC_READ | GENERIC_WRITE; } unreachable (); } //----------------------------------------------------------------------------- static constexpr DWORD fflags_to_access (int fflags) { switch (fflags) { case O_RDONLY: return FILE_MAP_READ; case O_WRONLY: return FILE_MAP_WRITE; case O_RDWR: return FILE_MAP_WRITE; } unreachable (); } //----------------------------------------------------------------------------- static constexpr DWORD mflags_to_protect (int mflags) { DWORD res = 0; if (mflags & PROT_READ) res |= PAGE_READONLY; if (mflags & PROT_WRITE) res |= PAGE_READWRITE; if (mflags & PROT_EXEC) res |= PAGE_EXECUTE; return res; } /////////////////////////////////////////////////////////////////////////////// mapped_file::mapped_file (::cruft::win32::file &&src, int fflags, int mflags): m_file (std::forward<::cruft::win32::file> (src)), m_data (nullptr, UnmapViewOfFile) { // I would rather perform checks on filesize after mapping, but mapping // requires a check for empty files before we perform the mapping to // detect errors it throws in that specific situation. DWORD hi_size; DWORD lo_size = GetFileSize (m_file.native (), &hi_size); if (lo_size == INVALID_FILE_SIZE) ::cruft::win32::error::throw_code (); m_size = static_cast (hi_size) << 32 | lo_size; m_mapping.reset ( CreateFileMapping ( m_file, nullptr, mflags_to_protect (mflags), 0, 0, nullptr ) ); // Apparently Windows lacks the ability to map zero length files; fucking // hell. Try not to collapse, but instead bail with a null mapping and // pray the user doesn't do something stupid with the result. if (!m_mapping) { auto err = ::cruft::win32::error::last_code (); if (err == ERROR_FILE_INVALID && m_size == 0) return; ::cruft::win32::error::throw_code (err); } auto view = MapViewOfFile ( m_mapping, fflags_to_access (fflags), 0, 0, 0 ); if (!view) ::cruft::win32::error::throw_code (); m_data.reset ( static_cast (view) ); } //----------------------------------------------------------------------------- mapped_file::mapped_file ( std::filesystem::path const &path, int fflags, int mflags ) : mapped_file ( ::cruft::win32::file ( path, fflags_to_generic (fflags), fflags == O_RDONLY ? FILE_SHARE_READ : 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN ), fflags, mflags ) { ; } //----------------------------------------------------------------------------- mapped_file::mapped_file (cruft::posix::fd const &src, int fflags, int mflags): mapped_file (cruft::win32::file (src.dup ()), fflags, mflags) { }; static BOOL noop (LPCVOID) { return TRUE; } //----------------------------------------------------------------------------- mapped_file::mapped_file (mapped_file &&rhs) noexcept : m_data (nullptr, noop) { std::swap (m_file, rhs.m_file); std::swap (m_mapping, rhs.m_mapping); std::swap (m_data, rhs.m_data); std::swap (m_size, rhs.m_size); } /////////////////////////////////////////////////////////////////////////////// size_t mapped_file::size (void) const { return m_size; } //----------------------------------------------------------------------------- bool mapped_file::empty (void) const { return size () == 0; } //----------------------------------------------------------------------------- const uint8_t* mapped_file::data (void) const & { return m_data.get (); } //----------------------------------------------------------------------------- uint8_t* mapped_file::data (void) & { return m_data.get (); } //----------------------------------------------------------------------------- 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 cbegin (); } //----------------------------------------------------------------------------- const uint8_t* mapped_file::end (void) const & { return cend (); } //----------------------------------------------------------------------------- const uint8_t* mapped_file::cbegin (void) const & { return data (); } //----------------------------------------------------------------------------- const uint8_t* mapped_file::cend (void) const & { return data () + size (); }