mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
Merge pull request #2649 from phire/FileIO_Sanity
IPC_HLE: Don't open/close files for every single file operation.
This commit is contained in:
@ -64,7 +64,7 @@ const IPCCommandResult IPC_DEFAULT_REPLY = { true, IPC_DEFAULT_DELAY };
|
|||||||
namespace WII_IPC_HLE_Interface
|
namespace WII_IPC_HLE_Interface
|
||||||
{
|
{
|
||||||
|
|
||||||
typedef std::map<u32, IWII_IPC_HLE_Device*> TDeviceMap;
|
typedef std::map<u32, std::shared_ptr<IWII_IPC_HLE_Device>> TDeviceMap;
|
||||||
static TDeviceMap g_DeviceMap;
|
static TDeviceMap g_DeviceMap;
|
||||||
|
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
@ -72,9 +72,9 @@ typedef std::map<u32, std::string> TFileNameMap;
|
|||||||
|
|
||||||
#define IPC_MAX_FDS 0x18
|
#define IPC_MAX_FDS 0x18
|
||||||
#define ES_MAX_COUNT 2
|
#define ES_MAX_COUNT 2
|
||||||
static IWII_IPC_HLE_Device* g_FdMap[IPC_MAX_FDS];
|
static std::shared_ptr<IWII_IPC_HLE_Device> g_FdMap[IPC_MAX_FDS];
|
||||||
static bool es_inuse[ES_MAX_COUNT];
|
static bool es_inuse[ES_MAX_COUNT];
|
||||||
static IWII_IPC_HLE_Device* es_handles[ES_MAX_COUNT];
|
static std::shared_ptr<IWII_IPC_HLE_Device> es_handles[ES_MAX_COUNT];
|
||||||
|
|
||||||
|
|
||||||
typedef std::deque<u32> ipc_msg_queue;
|
typedef std::deque<u32> ipc_msg_queue;
|
||||||
@ -105,47 +105,54 @@ static void EnqueueEvent(u64 userdata, int cycles_late = 0)
|
|||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 num_devices;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::shared_ptr<T> AddDevice(const char* deviceName)
|
||||||
|
{
|
||||||
|
auto device = std::make_shared<T>(num_devices, deviceName);
|
||||||
|
g_DeviceMap[num_devices] = device;
|
||||||
|
num_devices++;
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
_dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init");
|
_dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init");
|
||||||
CWII_IPC_HLE_Device_es::m_ContentFile = "";
|
CWII_IPC_HLE_Device_es::m_ContentFile = "";
|
||||||
|
|
||||||
for (IWII_IPC_HLE_Device*& dev : g_FdMap)
|
num_devices = 0;
|
||||||
{
|
|
||||||
dev = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 i = 0;
|
|
||||||
// Build hardware devices
|
// Build hardware devices
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_oh1_57e_305(i, "/dev/usb/oh1/57e/305"); i++;
|
AddDevice<CWII_IPC_HLE_Device_usb_oh1_57e_305>("/dev/usb/oh1/57e/305");
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_immediate(i, "/dev/stm/immediate"); i++;
|
AddDevice<CWII_IPC_HLE_Device_stm_immediate>("/dev/stm/immediate");
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_eventhook(i, "/dev/stm/eventhook"); i++;
|
AddDevice<CWII_IPC_HLE_Device_stm_eventhook>("/dev/stm/eventhook");
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_fs(i, "/dev/fs"); i++;
|
AddDevice<CWII_IPC_HLE_Device_fs>("/dev/fs");
|
||||||
|
|
||||||
// IOS allows two ES devices at a time
|
// IOS allows two ES devices at a time
|
||||||
for (u32 j=0; j<ES_MAX_COUNT; j++)
|
for (u32 j=0; j<ES_MAX_COUNT; j++)
|
||||||
{
|
{
|
||||||
g_DeviceMap[i] = es_handles[j] = new CWII_IPC_HLE_Device_es(i, "/dev/es"); i++;
|
es_handles[j] = AddDevice<CWII_IPC_HLE_Device_es>("/dev/es");
|
||||||
es_inuse[j] = false;
|
es_inuse[j] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_di(i, std::string("/dev/di")); i++;
|
AddDevice<CWII_IPC_HLE_Device_di>("/dev/di");
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_request(i, "/dev/net/kd/request"); i++;
|
AddDevice<CWII_IPC_HLE_Device_net_kd_request>("/dev/net/kd/request");
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_time(i, "/dev/net/kd/time"); i++;
|
AddDevice<CWII_IPC_HLE_Device_net_kd_time>("/dev/net/kd/time");
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ncd_manage(i, "/dev/net/ncd/manage"); i++;
|
AddDevice<CWII_IPC_HLE_Device_net_ncd_manage>("/dev/net/ncd/manage");
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_wd_command(i, "/dev/net/wd/command"); i++;
|
AddDevice<CWII_IPC_HLE_Device_net_wd_command>("/dev/net/wd/command");
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ip_top(i, "/dev/net/ip/top"); i++;
|
AddDevice<CWII_IPC_HLE_Device_net_ip_top>("/dev/net/ip/top");
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ssl(i, "/dev/net/ssl"); i++;
|
AddDevice<CWII_IPC_HLE_Device_net_ssl>("/dev/net/ssl");
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_kbd(i, "/dev/usb/kbd"); i++;
|
AddDevice<CWII_IPC_HLE_Device_usb_kbd>("/dev/usb/kbd");
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_sdio_slot0(i, "/dev/sdio/slot0"); i++;
|
AddDevice<CWII_IPC_HLE_Device_sdio_slot0>("/dev/sdio/slot0");
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, "/dev/sdio/slot1"); i++;
|
AddDevice<CWII_IPC_HLE_Device_stub>("/dev/sdio/slot1");
|
||||||
#if defined(__LIBUSB__) || defined(_WIN32)
|
#if defined(__LIBUSB__) || defined(_WIN32)
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_hid(i, "/dev/usb/hid"); i++;
|
AddDevice<CWII_IPC_HLE_Device_hid>("/dev/usb/hid");
|
||||||
#else
|
#else
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, "/dev/usb/hid"); i++;
|
AddDevice<CWII_IPC_HLE_Device_stub>("/dev/usb/hid");
|
||||||
#endif
|
#endif
|
||||||
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, "/dev/usb/oh1"); i++;
|
AddDevice<CWII_IPC_HLE_Device_stub>("/dev/usb/oh1");
|
||||||
g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, "_Unimplemented_Device_"); i++;
|
AddDevice<IWII_IPC_HLE_Device>("_Unimplemented_Device_");
|
||||||
|
|
||||||
event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent);
|
event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent);
|
||||||
}
|
}
|
||||||
@ -154,16 +161,15 @@ void Reset(bool _bHard)
|
|||||||
{
|
{
|
||||||
CoreTiming::RemoveAllEvents(event_enqueue);
|
CoreTiming::RemoveAllEvents(event_enqueue);
|
||||||
|
|
||||||
for (IWII_IPC_HLE_Device*& dev : g_FdMap)
|
for (auto& dev : g_FdMap)
|
||||||
{
|
{
|
||||||
if (dev != nullptr && !dev->IsHardware())
|
if (dev && !dev->IsHardware())
|
||||||
{
|
{
|
||||||
// close all files and delete their resources
|
// close all files and delete their resources
|
||||||
dev->Close(0, true);
|
dev->Close(0, true);
|
||||||
delete dev;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = nullptr;
|
dev.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (bool& in_use : es_inuse)
|
for (bool& in_use : es_inuse)
|
||||||
@ -177,16 +183,12 @@ void Reset(bool _bHard)
|
|||||||
{
|
{
|
||||||
// Force close
|
// Force close
|
||||||
entry.second->Close(0, true);
|
entry.second->Close(0, true);
|
||||||
|
|
||||||
// Hardware should not be deleted unless it is a hard reset
|
|
||||||
if (_bHard)
|
|
||||||
delete entry.second;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_bHard)
|
if (_bHard)
|
||||||
{
|
{
|
||||||
g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end());
|
g_DeviceMap.clear();
|
||||||
}
|
}
|
||||||
request_queue.clear();
|
request_queue.clear();
|
||||||
reply_queue.clear();
|
reply_queue.clear();
|
||||||
@ -205,7 +207,7 @@ void SetDefaultContentFile(const std::string& _rFilename)
|
|||||||
{
|
{
|
||||||
if (entry.second && entry.second->GetDeviceName().find("/dev/es") == 0)
|
if (entry.second && entry.second->GetDeviceName().find("/dev/es") == 0)
|
||||||
{
|
{
|
||||||
((CWII_IPC_HLE_Device_es*)entry.second)->LoadWAD(_rFilename);
|
static_cast<CWII_IPC_HLE_Device_es*>(entry.second.get())->LoadWAD(_rFilename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,8 +219,7 @@ void ES_DIVerify(u8 *_pTMD, u32 _sz)
|
|||||||
|
|
||||||
void SDIO_EventNotify()
|
void SDIO_EventNotify()
|
||||||
{
|
{
|
||||||
CWII_IPC_HLE_Device_sdio_slot0 *pDevice =
|
auto pDevice = static_cast<CWII_IPC_HLE_Device_sdio_slot0*>(GetDeviceByName("/dev/sdio/slot0").get());
|
||||||
(CWII_IPC_HLE_Device_sdio_slot0*)GetDeviceByName("/dev/sdio/slot0");
|
|
||||||
if (pDevice)
|
if (pDevice)
|
||||||
pDevice->EventNotify();
|
pDevice->EventNotify();
|
||||||
}
|
}
|
||||||
@ -236,7 +237,7 @@ int getFreeDeviceId()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName)
|
std::shared_ptr<IWII_IPC_HLE_Device> GetDeviceByName(const std::string& _rDeviceName)
|
||||||
{
|
{
|
||||||
for (const auto& entry : g_DeviceMap)
|
for (const auto& entry : g_DeviceMap)
|
||||||
{
|
{
|
||||||
@ -249,7 +250,7 @@ IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
|
std::shared_ptr<IWII_IPC_HLE_Device> AccessDeviceByID(u32 _ID)
|
||||||
{
|
{
|
||||||
if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
|
if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
|
||||||
{
|
{
|
||||||
@ -260,11 +261,11 @@ IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is called from ExecuteCommand() COMMAND_OPEN_DEVICE
|
// This is called from ExecuteCommand() COMMAND_OPEN_DEVICE
|
||||||
IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName)
|
std::shared_ptr<IWII_IPC_HLE_Device> CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName)
|
||||||
{
|
{
|
||||||
// scan device name and create the right one
|
// scan device name and create the right one
|
||||||
INFO_LOG(WII_IPC_FILEIO, "IOP: Create FileIO %s", _rDeviceName.c_str());
|
INFO_LOG(WII_IPC_FILEIO, "IOP: Create FileIO %s", _rDeviceName.c_str());
|
||||||
return new CWII_IPC_HLE_Device_FileIO(_DeviceID, _rDeviceName);
|
return std::make_shared<CWII_IPC_HLE_Device_FileIO>(_DeviceID, _rDeviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -300,13 +301,13 @@ void DoState(PointerWrap &p)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_FdMap[i] = new CWII_IPC_HLE_Device_FileIO(i, "");
|
g_FdMap[i] = std::make_shared<CWII_IPC_HLE_Device_FileIO>(i, "");
|
||||||
g_FdMap[i]->DoState(p);
|
g_FdMap[i]->DoState(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_FdMap[i] = nullptr;
|
g_FdMap[i].reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,7 +322,7 @@ void DoState(PointerWrap &p)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (IWII_IPC_HLE_Device*& dev : g_FdMap)
|
for (auto& dev : g_FdMap)
|
||||||
{
|
{
|
||||||
u32 exists = dev ? 1 : 0;
|
u32 exists = dev ? 1 : 0;
|
||||||
p.Do(exists);
|
p.Do(exists);
|
||||||
@ -357,9 +358,9 @@ void ExecuteCommand(u32 _Address)
|
|||||||
IPCCommandType Command = static_cast<IPCCommandType>(Memory::Read_U32(_Address));
|
IPCCommandType Command = static_cast<IPCCommandType>(Memory::Read_U32(_Address));
|
||||||
s32 DeviceID = Memory::Read_U32(_Address + 8);
|
s32 DeviceID = Memory::Read_U32(_Address + 8);
|
||||||
|
|
||||||
IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : nullptr;
|
std::shared_ptr<IWII_IPC_HLE_Device> pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : nullptr;
|
||||||
|
|
||||||
INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice);
|
INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice.get());
|
||||||
|
|
||||||
switch (Command)
|
switch (Command)
|
||||||
{
|
{
|
||||||
@ -423,11 +424,6 @@ void ExecuteCommand(u32 _Address)
|
|||||||
{
|
{
|
||||||
g_FdMap[DeviceID] = pDevice;
|
g_FdMap[DeviceID] = pDevice;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
delete pDevice;
|
|
||||||
pDevice = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -451,14 +447,7 @@ void ExecuteCommand(u32 _Address)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_FdMap[DeviceID] = nullptr;
|
g_FdMap[DeviceID].reset();
|
||||||
|
|
||||||
// Don't delete hardware
|
|
||||||
if (!pDevice->IsHardware())
|
|
||||||
{
|
|
||||||
delete pDevice;
|
|
||||||
pDevice = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
@ -63,10 +64,10 @@ void ES_DIVerify(u8 *_pTMD, u32 _sz);
|
|||||||
void SDIO_EventNotify();
|
void SDIO_EventNotify();
|
||||||
|
|
||||||
|
|
||||||
IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName);
|
std::shared_ptr<IWII_IPC_HLE_Device> CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName);
|
||||||
|
|
||||||
IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName);
|
std::shared_ptr<IWII_IPC_HLE_Device> GetDeviceByName(const std::string& _rDeviceName);
|
||||||
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID);
|
std::shared_ptr<IWII_IPC_HLE_Device> AccessDeviceByID(u32 _ID);
|
||||||
int getFreeDeviceId();
|
int getFreeDeviceId();
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
static Common::replace_v replacements;
|
static Common::replace_v replacements;
|
||||||
|
|
||||||
|
static std::map <std::string, std::weak_ptr<File::IOFile>> openFiles;
|
||||||
|
|
||||||
// This is used by several of the FileIO and /dev/fs functions
|
// This is used by several of the FileIO and /dev/fs functions
|
||||||
std::string HLE_IPC_BuildFilename(std::string path_wii)
|
std::string HLE_IPC_BuildFilename(std::string path_wii)
|
||||||
{
|
{
|
||||||
@ -73,6 +75,7 @@ CWII_IPC_HLE_Device_FileIO::CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std:
|
|||||||
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName, false) // not a real hardware
|
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName, false) // not a real hardware
|
||||||
, m_Mode(0)
|
, m_Mode(0)
|
||||||
, m_SeekPos(0)
|
, m_SeekPos(0)
|
||||||
|
, m_file()
|
||||||
{
|
{
|
||||||
Common::ReadReplacements(replacements);
|
Common::ReadReplacements(replacements);
|
||||||
}
|
}
|
||||||
@ -86,6 +89,9 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Close(u32 _CommandAddress, bool _bF
|
|||||||
INFO_LOG(WII_IPC_FILEIO, "FileIO: Close %s (DeviceID=%08x)", m_Name.c_str(), m_DeviceID);
|
INFO_LOG(WII_IPC_FILEIO, "FileIO: Close %s (DeviceID=%08x)", m_Name.c_str(), m_DeviceID);
|
||||||
m_Mode = 0;
|
m_Mode = 0;
|
||||||
|
|
||||||
|
// Let go of our pointer to the file, it will automatically close if we are the last handle accessing it.
|
||||||
|
m_file.reset();
|
||||||
|
|
||||||
// Close always return 0 for success
|
// Close always return 0 for success
|
||||||
if (_CommandAddress && !_bForce)
|
if (_CommandAddress && !_bForce)
|
||||||
Memory::Write_U32(0, _CommandAddress + 4);
|
Memory::Write_U32(0, _CommandAddress + 4);
|
||||||
@ -113,6 +119,7 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode
|
|||||||
if (File::Exists(m_filepath) && !File::IsDirectory(m_filepath))
|
if (File::Exists(m_filepath) && !File::IsDirectory(m_filepath))
|
||||||
{
|
{
|
||||||
INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s == %08X)", m_Name.c_str(), Modes[_Mode], _Mode);
|
INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s == %08X)", m_Name.c_str(), Modes[_Mode], _Mode);
|
||||||
|
OpenFile();
|
||||||
ReturnValue = m_DeviceID;
|
ReturnValue = m_DeviceID;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -127,27 +134,47 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode
|
|||||||
return IPC_DEFAULT_REPLY;
|
return IPC_DEFAULT_REPLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
File::IOFile CWII_IPC_HLE_Device_FileIO::OpenFile()
|
// This isn't theadsafe, but it's only called from the CPU thread.
|
||||||
|
void CWII_IPC_HLE_Device_FileIO::OpenFile()
|
||||||
{
|
{
|
||||||
const char* open_mode = "";
|
// On the wii, all file operations are strongly ordered.
|
||||||
|
// If a game opens the same file twice (or 8 times, looking at you PokePark Wii)
|
||||||
|
// and writes to one file handle, it will be able to immediately read the written
|
||||||
|
// data from the other handle.
|
||||||
|
// On 'real' operating systems, there are various buffers and caches meaning
|
||||||
|
// applications doing such naughty things will not get expected results.
|
||||||
|
|
||||||
switch (m_Mode)
|
// So we fix this by catching any attempts to open the same file twice and
|
||||||
|
// only opening one file. Accesses to a single file handle are ordered.
|
||||||
|
//
|
||||||
|
// Hall of Shame:
|
||||||
|
// - PokePark Wii (gets stuck on the loading screen of Pikachu falling)
|
||||||
|
// - PokePark 2 (Also gets stuck while loading)
|
||||||
|
// - Wii System Menu (Can't access the system settings, gets stuck on blank screen)
|
||||||
|
// - The Beatles: Rock Band (saving doesn't work)
|
||||||
|
|
||||||
|
// Check if the file has already been opened.
|
||||||
|
auto search = openFiles.find(m_Name);
|
||||||
|
if (search != openFiles.end())
|
||||||
{
|
{
|
||||||
case ISFS_OPEN_READ:
|
m_file = search->second.lock(); // Lock a shared pointer to use.
|
||||||
open_mode = "rb";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ISFS_OPEN_WRITE:
|
|
||||||
case ISFS_OPEN_RW:
|
|
||||||
open_mode = "r+b";
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
PanicAlert("FileIO: Unknown open mode : 0x%02x", m_Mode);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string path = m_Name;
|
||||||
|
// This code will be called when all references to the shared pointer below have been removed.
|
||||||
|
auto deleter = [path](File::IOFile* ptr)
|
||||||
|
{
|
||||||
|
delete ptr; // IOFile's deconstructor closes the file.
|
||||||
|
openFiles.erase(path); // erase the weak pointer from the list of open files.
|
||||||
|
};
|
||||||
|
|
||||||
return File::IOFile(m_filepath, open_mode);
|
// All files are opened read/write. Actual access rights will be controlled per handle by the read/write functions below
|
||||||
|
m_file = std::shared_ptr<File::IOFile>(new File::IOFile(m_filepath, "r+b"), deleter); // Use the custom deleter from above.
|
||||||
|
|
||||||
|
// Store a weak pointer to our newly opened file in the cache.
|
||||||
|
openFiles[path] = std::weak_ptr<File::IOFile>(m_file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
IPCCommandResult CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
||||||
@ -156,11 +183,11 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
|||||||
const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
|
const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
|
||||||
const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
|
const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
|
||||||
|
|
||||||
if (auto file = OpenFile())
|
if (m_file->IsOpen())
|
||||||
{
|
{
|
||||||
ReturnValue = FS_RESULT_FATAL;
|
ReturnValue = FS_RESULT_FATAL;
|
||||||
|
|
||||||
const s32 fileSize = (s32) file.GetSize();
|
const s32 fileSize = (s32) m_file->GetSize();
|
||||||
INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08x)", SeekPosition, Mode, m_Name.c_str(), fileSize);
|
INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08x)", SeekPosition, Mode, m_Name.c_str(), fileSize);
|
||||||
|
|
||||||
switch (Mode)
|
switch (Mode)
|
||||||
@ -221,7 +248,7 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
|
|||||||
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
|
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
|
||||||
|
|
||||||
|
|
||||||
if (auto file = OpenFile())
|
if (m_file->IsOpen())
|
||||||
{
|
{
|
||||||
if (m_Mode == ISFS_OPEN_WRITE)
|
if (m_Mode == ISFS_OPEN_WRITE)
|
||||||
{
|
{
|
||||||
@ -230,9 +257,9 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
INFO_LOG(WII_IPC_FILEIO, "FileIO: Read 0x%x bytes to 0x%08x from %s", Size, Address, m_Name.c_str());
|
INFO_LOG(WII_IPC_FILEIO, "FileIO: Read 0x%x bytes to 0x%08x from %s", Size, Address, m_Name.c_str());
|
||||||
file.Seek(m_SeekPos, SEEK_SET);
|
m_file->Seek(m_SeekPos, SEEK_SET); // File might be opened twice, need to seek before we read
|
||||||
ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, file.GetHandle());
|
ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, m_file->GetHandle());
|
||||||
if (ReturnValue != Size && ferror(file.GetHandle()))
|
if (ReturnValue != Size && ferror(m_file->GetHandle()))
|
||||||
{
|
{
|
||||||
ReturnValue = FS_EACCESS;
|
ReturnValue = FS_EACCESS;
|
||||||
}
|
}
|
||||||
@ -259,7 +286,7 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
|
|||||||
const u32 Address = Memory::Read_U32(_CommandAddress + 0xC); // Write data from this memory address
|
const u32 Address = Memory::Read_U32(_CommandAddress + 0xC); // Write data from this memory address
|
||||||
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
|
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
|
||||||
|
|
||||||
if (auto file = OpenFile())
|
if (m_file->IsOpen())
|
||||||
{
|
{
|
||||||
if (m_Mode == ISFS_OPEN_READ)
|
if (m_Mode == ISFS_OPEN_READ)
|
||||||
{
|
{
|
||||||
@ -268,8 +295,8 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
INFO_LOG(WII_IPC_FILEIO, "FileIO: Write 0x%04x bytes from 0x%08x to %s", Size, Address, m_Name.c_str());
|
INFO_LOG(WII_IPC_FILEIO, "FileIO: Write 0x%04x bytes from 0x%08x to %s", Size, Address, m_Name.c_str());
|
||||||
file.Seek(m_SeekPos, SEEK_SET);
|
m_file->Seek(m_SeekPos, SEEK_SET); // File might be opened twice, need to seek before we write
|
||||||
if (file.WriteBytes(Memory::GetPointer(Address), Size))
|
if (m_file->WriteBytes(Memory::GetPointer(Address), Size))
|
||||||
{
|
{
|
||||||
ReturnValue = Size;
|
ReturnValue = Size;
|
||||||
m_SeekPos += Size;
|
m_SeekPos += Size;
|
||||||
@ -299,9 +326,9 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
|
|||||||
{
|
{
|
||||||
case ISFS_IOCTL_GETFILESTATS:
|
case ISFS_IOCTL_GETFILESTATS:
|
||||||
{
|
{
|
||||||
if (auto file = OpenFile())
|
if (m_file->IsOpen())
|
||||||
{
|
{
|
||||||
u32 m_FileLength = (u32)file.GetSize();
|
u32 m_FileLength = (u32)m_file->GetSize();
|
||||||
|
|
||||||
const u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
const u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
||||||
INFO_LOG(WII_IPC_FILEIO, " File: %s, Length: %i, Pos: %i", m_Name.c_str(), m_FileLength, m_SeekPos);
|
INFO_LOG(WII_IPC_FILEIO, " File: %s, Length: %i, Pos: %i", m_Name.c_str(), m_FileLength, m_SeekPos);
|
||||||
@ -337,4 +364,9 @@ void CWII_IPC_HLE_Device_FileIO::DoState(PointerWrap &p)
|
|||||||
p.Do(m_SeekPos);
|
p.Do(m_SeekPos);
|
||||||
|
|
||||||
m_filepath = HLE_IPC_BuildFilename(m_Name);
|
m_filepath = HLE_IPC_BuildFilename(m_Name);
|
||||||
|
|
||||||
|
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||||
|
{
|
||||||
|
OpenFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ public:
|
|||||||
IPCCommandResult IOCtl(u32 _CommandAddress) override;
|
IPCCommandResult IOCtl(u32 _CommandAddress) override;
|
||||||
void DoState(PointerWrap &p) override;
|
void DoState(PointerWrap &p) override;
|
||||||
|
|
||||||
File::IOFile OpenFile();
|
void OpenFile();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum
|
enum
|
||||||
@ -75,4 +75,5 @@ private:
|
|||||||
u32 m_SeekPos;
|
u32 m_SeekPos;
|
||||||
|
|
||||||
std::string m_filepath;
|
std::string m_filepath;
|
||||||
|
std::shared_ptr<File::IOFile> m_file;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user