io_win32: make mapping checks more robust

fixes zero length mapping errors
This commit is contained in:
Danny Robson 2016-04-27 17:04:56 +10:00
parent ddfb765110
commit 57058ab20f
2 changed files with 74 additions and 22 deletions

View File

@ -25,8 +25,9 @@ using util::detail::win32::mapped_file;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static DWORD static constexpr
fflags_to_native (int flags) { DWORD
fflags_to_generic (int flags) {
switch (flags) { switch (flags) {
case O_RDONLY: return GENERIC_READ; case O_RDONLY: return GENERIC_READ;
case O_WRONLY: return GENERIC_WRITE; case O_WRONLY: return GENERIC_WRITE;
@ -36,48 +37,99 @@ fflags_to_native (int flags) {
unreachable (); 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 & util::detail::win32::PROT_READ) res |= PAGE_READONLY;
if (mflags & util::detail::win32::PROT_WRITE) res |= PAGE_READWRITE;
if (mflags & util::detail::win32::PROT_EXEC) res |= PAGE_EXECUTE;
return res;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
mapped_file::mapped_file (const boost::filesystem::path &path, mapped_file::mapped_file (const boost::filesystem::path &path,
int fflags, int fflags,
int mflags): int mflags):
m_data (nullptr, UnmapViewOfFile) m_data (nullptr, UnmapViewOfFile)
{ {
// Cache the ASCII path to avoid memory scoping issues.
std::string path_str = path.string ();
// Get hold of the file we're attempting to map. Emulate some level of POXIS mmap.
m_file.reset ( m_file.reset (
CreateFile ( CreateFile (
path.string ().c_str (), path_str.c_str (),
fflags_to_native (fflags), fflags_to_generic (fflags),
fflags & O_RDONLY ? FILE_SHARE_READ : 0, fflags == O_RDONLY ? FILE_SHARE_READ : 0,
nullptr, nullptr,
OPEN_EXISTING, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
0 nullptr
) )
); );
if (m_file == INVALID_HANDLE_VALUE) if (m_file == INVALID_HANDLE_VALUE)
win32_error::throw_code (); win32_error::throw_code ();
m_mapping.reset (CreateFileMapping (m_file, // I would rather perform checks on filesize after mapping, but mapping
nullptr, // requires a check for empty files before we perform the mapping to
access == O_RDONLY ? PAGE_READONLY : PAGE_READWRITE, // detect errors it throws in that specific situation.
0, 0, DWORD hi_size, lo_size = GetFileSize (m_file, &hi_size);
nullptr)); m_size = (uint64_t)hi_size << 32 | lo_size;
if (m_mapping == INVALID_HANDLE_VALUE) m_mapping.reset (
win32_error::throw_code (); CreateFileMapping (
m_file,
nullptr,
mflags_to_protect (mflags),
0, 0,
nullptr
)
);
auto view = MapViewOfFile (m_mapping, // Apparently Windows lacks the ability to map zero length files; fucking
access == O_RDONLY ? FILE_MAP_READ : FILE_MAP_WRITE, // hell. Try not to collapse, but instead bail with a null mapping and
0, 0, // pray the user doesn't do something stupid with the result.
0); if (!m_mapping) {
if (view == nullptr) auto err = win32_error::last_code ();
if (err == ERROR_FILE_INVALID && m_size == 0)
return;
win32_error::throw_code (err);
}
auto view = MapViewOfFile (
m_mapping,
fflags_to_access (fflags),
0, 0,
0
);
if (!view)
win32_error::throw_code (); win32_error::throw_code ();
m_data.reset ( m_data.reset (
static_cast<unsigned char*> (view) static_cast<unsigned char*> (view)
); );
m_size = GetFileSize (m_file, nullptr);
} }

View File

@ -38,7 +38,7 @@ namespace util {
class mapped_file { class mapped_file {
public: public:
mapped_file (const boost::filesystem::path &path, mapped_file (const boost::filesystem::path &path,
int fflags = O_RDONLY | O_BINARY, int fflags = O_RDONLY,
int mflags = PROT_READ); int mflags = PROT_READ);
mapped_file (const mapped_file&) = delete; mapped_file (const mapped_file&) = delete;
@ -59,7 +59,7 @@ namespace util {
::util::win32::handle m_mapping; ::util::win32::handle m_mapping;
std::unique_ptr<uint8_t,BOOL(*)(LPCVOID)> m_data; std::unique_ptr<uint8_t,BOOL(*)(LPCVOID)> m_data;
size_t m_size; uint64_t m_size;
}; };
} } } }