FileSystem: Add OpenSharedCFile()

This commit is contained in:
Connor McLaughlin 2022-06-06 22:46:39 +10:00 committed by refractionpcsx2
parent 8c0120bdbb
commit afa29facc6
2 changed files with 81 additions and 10 deletions

View File

@ -37,6 +37,7 @@
#if defined(_WIN32)
#include "RedtapeWindows.h"
#include <winioctl.h>
#include <share.h>
#include <shlobj.h>
#if defined(_UWP)
@ -595,12 +596,29 @@ std::string Path::Combine(const std::string_view& base, const std::string_view&
}
#ifdef _UWP
static std::FILE* OpenCFileUWP(const wchar_t* wfilename, const wchar_t* mode)
static std::FILE* OpenCFileUWP(const wchar_t* wfilename, const wchar_t* mode, FileSystem::FileShareMode share_mode)
{
DWORD access = 0;
DWORD share = 0;
DWORD disposition = 0;
switch (share_mode)
{
case FileSystem::FileShareMode::DenyNone:
share = FILE_SHARE_READ | FILE_SHARE_WRITE;
break;
case FileSystem::FileShareMode::DenyRead:
share = FILE_SHARE_WRITE;
break;
case FileSystem::FileShareMode::DenyWrite:
share = FILE_SHARE_READ;
break;
case FileSystem::FileShareMode::DenyReadWrite:
default:
share = 0;
break;
}
int flags = 0;
const wchar_t* tmode = mode;
while (*tmode)
@ -608,7 +626,6 @@ static std::FILE* OpenCFileUWP(const wchar_t* wfilename, const wchar_t* mode)
if (*tmode == L'r' && *(tmode + 1) == L'+')
{
access = GENERIC_READ | GENERIC_WRITE;
share = 0;
disposition = OPEN_EXISTING;
flags |= _O_RDWR;
tmode += 2;
@ -616,7 +633,6 @@ static std::FILE* OpenCFileUWP(const wchar_t* wfilename, const wchar_t* mode)
else if (*tmode == L'w' && *(tmode + 1) == L'+')
{
access = GENERIC_READ | GENERIC_WRITE;
share = 0;
disposition = CREATE_ALWAYS;
flags |= _O_RDWR | _O_CREAT | _O_TRUNC;
tmode += 2;
@ -624,7 +640,6 @@ static std::FILE* OpenCFileUWP(const wchar_t* wfilename, const wchar_t* mode)
else if (*tmode == L'a' && *(tmode + 1) == L'+')
{
access = GENERIC_READ | GENERIC_WRITE;
share = 0;
disposition = CREATE_ALWAYS;
flags |= _O_RDWR | _O_APPEND | _O_CREAT | _O_TRUNC;
tmode += 2;
@ -632,7 +647,6 @@ static std::FILE* OpenCFileUWP(const wchar_t* wfilename, const wchar_t* mode)
else if (*tmode == L'r')
{
access = GENERIC_READ;
share = 0;
disposition = OPEN_EXISTING;
flags |= _O_RDONLY;
tmode++;
@ -640,7 +654,6 @@ static std::FILE* OpenCFileUWP(const wchar_t* wfilename, const wchar_t* mode)
else if (*tmode == L'w')
{
access = GENERIC_WRITE;
share = 0;
disposition = CREATE_ALWAYS;
flags |= _O_WRONLY | _O_CREAT | _O_TRUNC;
tmode++;
@ -648,7 +661,6 @@ static std::FILE* OpenCFileUWP(const wchar_t* wfilename, const wchar_t* mode)
else if (*tmode == L'a')
{
access = GENERIC_READ | GENERIC_WRITE;
share = 0;
disposition = CREATE_ALWAYS;
flags |= _O_WRONLY | _O_APPEND | _O_CREAT | _O_TRUNC;
tmode++;
@ -670,7 +682,7 @@ static std::FILE* OpenCFileUWP(const wchar_t* wfilename, const wchar_t* mode)
}
else
{
Log_ErrorPrintf("Unknown mode flags: '%s'", StringUtil::WideStringToUTF8String(mode).c_str());
Console.Error("Unknown mode flags: '%s'", StringUtil::WideStringToUTF8String(mode).c_str());
return nullptr;
}
}
@ -681,7 +693,7 @@ static std::FILE* OpenCFileUWP(const wchar_t* wfilename, const wchar_t* mode)
if (flags & _O_APPEND && !SetFilePointerEx(hFile, LARGE_INTEGER{}, nullptr, FILE_END))
{
Log_ErrorPrintf("SetFilePointerEx() failed: %08X", GetLastError());
Console.Error("SetFilePointerEx() failed: %08X", GetLastError());
CloseHandle(hFile);
return nullptr;
}
@ -715,7 +727,7 @@ std::FILE* FileSystem::OpenCFile(const char* filename, const char* mode)
if (_wfopen_s(&fp, wfilename.c_str(), wmode.c_str()) != 0)
{
#ifdef _UWP
return OpenCFileUWP(wfilename.c_str(), wmode.c_str());
return OpenCFileUWP(wfilename.c_str(), wmode.c_str(), FileShareMode::DenyReadWrite);
#else
return nullptr;
#endif
@ -755,6 +767,51 @@ FileSystem::ManagedCFilePtr FileSystem::OpenManagedCFile(const char* filename, c
return ManagedCFilePtr(OpenCFile(filename, mode), [](std::FILE* fp) { std::fclose(fp); });
}
std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode)
{
#ifdef _WIN32
const std::wstring wfilename(StringUtil::UTF8StringToWideString(filename));
const std::wstring wmode(StringUtil::UTF8StringToWideString(mode));
if (wfilename.empty() || wmode.empty())
return nullptr;
int share_flags = 0;
switch (share_mode)
{
case FileShareMode::DenyNone:
share_flags = _SH_DENYNO;
break;
case FileShareMode::DenyRead:
share_flags = _SH_DENYRD;
break;
case FileShareMode::DenyWrite:
share_flags = _SH_DENYWR;
break;
case FileShareMode::DenyReadWrite:
default:
share_flags = _SH_DENYRW;
break;
}
std::FILE* fp = _wfsopen(wfilename.c_str(), wmode.c_str(), share_flags);
if (fp)
return fp;
#ifdef _UWP
return OpenCFileUWP(wfilename.c_str(), wmode.c_str(), share_mode);
#else
return nullptr;
#endif
#else
return std::fopen(filename, mode);
#endif
}
FileSystem::ManagedCFilePtr FileSystem::OpenManagedSharedCFile(const char* filename, const char* mode, FileShareMode share_mode)
{
return ManagedCFilePtr(OpenSharedCFile(filename, mode, share_mode), [](std::FILE* fp) { std::fclose(fp); });
}
int FileSystem::FSeek64(std::FILE* fp, s64 offset, int whence)
{
#ifdef _WIN32

View File

@ -110,6 +110,20 @@ namespace FileSystem
int OpenFDFile(const char* filename, int flags, int mode);
/// Sharing modes for OpenSharedCFile().
enum class FileShareMode
{
DenyReadWrite, /// Exclusive access.
DenyWrite, /// Other processes can read from this file.
DenyRead, /// Other processes can write to this file.
DenyNone, /// Other processes can read and write to this file.
};
/// Opens a file in shareable mode (where other processes can access it concurrently).
/// Only has an effect on Windows systems.
ManagedCFilePtr OpenManagedSharedCFile(const char* filename, const char* mode, FileShareMode share_mode);
std::FILE* OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode);
std::optional<std::vector<u8>> ReadBinaryFile(const char* filename);
std::optional<std::vector<u8>> ReadBinaryFile(std::FILE* fp);
std::optional<std::string> ReadFileToString(const char* filename);