io_win32: make mapping checks more robust
fixes zero length mapping errors
This commit is contained in:
parent
ddfb765110
commit
57058ab20f
92
io_win32.cpp
92
io_win32.cpp
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user