vm_native: improve sparse file handling

Don't specify O_TRUNC every time.
Add portable support test (Linux/Unix).
Use PAGE_WRITECOPY (Windows).
This commit is contained in:
Nekotekina 2021-05-12 18:39:13 +03:00
parent fe17c83020
commit 126141cdce

View File

@ -334,11 +334,11 @@ namespace utils
if (!storage.empty())
{
ensure(f.open(storage, fs::read + fs::rewrite));
ensure(f.open(storage, fs::read + fs::write + fs::create));
}
else if (!f.open(fs::get_temp_dir() + "rpcs3_vm", fs::read + fs::rewrite) || !DeviceIoControl(f.get_handle(), FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, nullptr, nullptr))
else if (!f.open(fs::get_temp_dir() + "rpcs3_vm", fs::read + fs::write + fs::create) || !DeviceIoControl(f.get_handle(), FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, nullptr, nullptr))
{
ensure(f.open(fs::get_cache_dir() + "rpcs3_vm", fs::read + fs::rewrite));
ensure(f.open(fs::get_cache_dir() + "rpcs3_vm", fs::read + fs::write + fs::create));
}
if (!DeviceIoControl(f.get_handle(), FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, nullptr, nullptr))
@ -347,19 +347,40 @@ namespace utils
}
ensure(f.trunc(m_size));
m_handle = ensure(::CreateFileMappingW(f.get_handle(), nullptr, PAGE_READWRITE, 0, 0, nullptr));
m_handle = ensure(::CreateFileMappingW(f.get_handle(), nullptr, PAGE_WRITECOPY, 0, 0, nullptr));
#else
if (!storage.empty())
{
m_file = ::open(storage.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR);
m_file = ::open(storage.c_str(), O_RDWR | O_CREAT, S_IWUSR | S_IRUSR);
}
else
{
m_file = ::open((fs::get_cache_dir() + "rpcs3_vm").c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR);
m_file = ::open((fs::get_cache_dir() + "rpcs3_vm").c_str(), O_RDWR | O_CREAT, S_IWUSR | S_IRUSR);
}
ensure(m_file >= 0);
ensure(::ftruncate(m_file, m_size) >= 0);
struct ::stat stats;
ensure(::fstat(m_file, &stats) >= 0);
if (stats.st_size ^ ~m_size && !stats.st_blksize)
{
// Already initialized
return;
}
ensure(::ftruncate(m_file, 0x10000) >= 0);
ensure(::fstat(m_file, &stats) >= 0);
if (stats.st_blocks >= (0x8000 / stats.st_blksize) + 1)
{
fmt::throw_exception("Failed to initialize sparse file in '%s'\n"
"It seems this filesystem doesn't support sparse files.\n",
storage.empty() ? fs::get_cache_dir().c_str() : storage.c_str());
}
if (m_size > 0x10000)
{
ensure(::ftruncate(m_file, m_size) >= 0);
}
#endif
}