2019-08-17 13:51:31 -04:00
|
|
|
#include <cstring>
|
2008-01-15 20:27:44 +00:00
|
|
|
#include <stdexcept>
|
2018-04-19 09:14:30 -04:00
|
|
|
#include <cctype>
|
2019-09-16 17:54:33 -04:00
|
|
|
|
|
|
|
#include "StdStream.h"
|
|
|
|
#include "xml/Utils.h"
|
2019-02-09 11:34:01 -05:00
|
|
|
#include "std_experimental_map.h"
|
2008-01-15 20:27:44 +00:00
|
|
|
|
2019-09-16 17:54:33 -04:00
|
|
|
#include "Iop_Ioman.h"
|
2019-09-16 18:29:18 -04:00
|
|
|
#include "IopBios.h"
|
2025-03-11 12:48:26 -04:00
|
|
|
#include "AppConfig.h"
|
|
|
|
#include "Log.h"
|
2019-09-16 17:54:33 -04:00
|
|
|
#include "../states/XmlStateFile.h"
|
2021-01-05 17:19:49 -05:00
|
|
|
#include "ioman/PathDirectoryDevice.h"
|
2019-09-16 17:54:33 -04:00
|
|
|
|
2008-01-15 20:27:44 +00:00
|
|
|
using namespace Iop;
|
|
|
|
|
2014-08-07 02:34:03 -04:00
|
|
|
#define LOG_NAME "iop_ioman"
|
|
|
|
|
2019-02-06 20:19:22 -05:00
|
|
|
#define STATE_FILES_FILENAME ("iop_ioman/files.xml")
|
|
|
|
#define STATE_FILES_FILESNODE "Files"
|
|
|
|
#define STATE_FILES_FILENODE "File"
|
|
|
|
#define STATE_FILES_FILENODE_IDATTRIBUTE ("Id")
|
|
|
|
#define STATE_FILES_FILENODE_PATHATTRIBUTE ("Path")
|
|
|
|
#define STATE_FILES_FILENODE_FLAGSATTRIBUTE ("Flags")
|
2019-09-17 12:38:18 -04:00
|
|
|
#define STATE_FILES_FILENODE_DESCPTRATTRIBUTE ("DescPtr")
|
2023-11-28 10:57:52 -05:00
|
|
|
#define STATE_FILES_FILENODE_POSITIONATTRIBUTE ("Position")
|
2019-09-17 12:38:18 -04:00
|
|
|
|
|
|
|
#define STATE_USERDEVICES_FILENAME ("iop_ioman/userdevices.xml")
|
|
|
|
#define STATE_USERDEVICES_DEVICESNODE "Devices"
|
|
|
|
#define STATE_USERDEVICES_DEVICENODE "Device"
|
|
|
|
#define STATE_USERDEVICES_DEVICENODE_NAMEATTRIBUTE ("Name")
|
|
|
|
#define STATE_USERDEVICES_DEVICENODE_DESCPTRATTRIBUTE ("DescPtr")
|
2019-02-06 20:19:22 -05:00
|
|
|
|
2023-01-11 10:39:32 -05:00
|
|
|
#define STATE_MOUNTEDDEVICES_FILENAME ("iop_ioman/mounteddevices.xml")
|
|
|
|
#define STATE_MOUNTEDDEVICES_DEVICESNODE "Devices"
|
|
|
|
#define STATE_MOUNTEDDEVICES_DEVICENODE "Device"
|
|
|
|
#define STATE_MOUNTEDDEVICES_DEVICENODE_NAMEATTRIBUTE ("Name")
|
|
|
|
#define STATE_MOUNTEDDEVICES_DEVICENODE_PATHATTRIBUTE ("Path")
|
|
|
|
|
2008-01-15 20:27:44 +00:00
|
|
|
#define PREF_IOP_FILEIO_STDLOGGING ("iop.fileio.stdlogging")
|
|
|
|
|
2021-01-22 19:20:34 -05:00
|
|
|
#define FUNCTION_WRITE "Write"
|
2024-08-09 17:05:21 -04:00
|
|
|
#define FUNCTION_CHSTAT "ChStat"
|
2018-04-30 21:01:23 +01:00
|
|
|
#define FUNCTION_ADDDRV "AddDrv"
|
|
|
|
#define FUNCTION_DELDRV "DelDrv"
|
2024-08-12 18:10:33 -04:00
|
|
|
#define FUNCTION_RENAME "Rename"
|
2021-01-05 17:19:49 -05:00
|
|
|
#define FUNCTION_MOUNT "Mount"
|
|
|
|
#define FUNCTION_UMOUNT "Umount"
|
2021-01-06 10:54:25 -05:00
|
|
|
#define FUNCTION_SEEK64 "Seek64"
|
2021-03-04 20:35:23 -05:00
|
|
|
#define FUNCTION_DEVCTL "DevCtl"
|
2016-12-08 00:25:07 -05:00
|
|
|
|
2020-11-06 22:06:01 +01:00
|
|
|
/** No such file or directory */
|
|
|
|
#define ERROR_ENOENT 2
|
|
|
|
|
2021-03-04 20:33:00 -05:00
|
|
|
//Ref: https://github.com/ps2homebrew/Open-PS2-Loader/blob/master/modules/iopcore/common/cdvdman.h
|
2021-03-08 20:02:14 -05:00
|
|
|
#define DEVCTL_CDVD_READCLOCK 0x430C
|
2021-03-04 20:33:00 -05:00
|
|
|
#define DEVCTL_CDVD_GETERROR 0x4320
|
2023-03-14 14:28:06 -04:00
|
|
|
#define DEVCTL_CDVD_STATUS 0x4322
|
2021-03-04 20:33:00 -05:00
|
|
|
#define DEVCTL_CDVD_DISKREADY 0x4325
|
|
|
|
|
|
|
|
#define DEVCTL_HDD_STATUS 0x4807
|
2022-01-31 16:33:24 -05:00
|
|
|
#define DEVCTL_HDD_MAXSECTOR 0x4801
|
2021-03-04 20:33:00 -05:00
|
|
|
#define DEVCTL_HDD_TOTALSECTOR 0x4802
|
|
|
|
#define DEVCTL_HDD_FREESECTOR 0x480A
|
|
|
|
|
|
|
|
#define DEVCTL_PFS_ZONESIZE 0x5001
|
|
|
|
#define DEVCTL_PFS_ZONEFREE 0x5002
|
|
|
|
|
2018-04-19 09:14:30 -04:00
|
|
|
static std::string RightTrim(std::string inputString)
|
|
|
|
{
|
2018-04-30 21:01:23 +01:00
|
|
|
auto nonSpaceEnd = std::find_if(inputString.rbegin(), inputString.rend(), [](int ch) { return !std::isspace(ch); });
|
2018-04-19 09:14:30 -04:00
|
|
|
inputString.erase(nonSpaceEnd.base(), inputString.end());
|
|
|
|
return inputString;
|
|
|
|
}
|
|
|
|
|
2018-09-20 19:19:25 -04:00
|
|
|
struct PATHINFO
|
|
|
|
{
|
|
|
|
std::string deviceName;
|
|
|
|
std::string devicePath;
|
|
|
|
};
|
|
|
|
|
|
|
|
static PATHINFO SplitPath(const char* path)
|
|
|
|
{
|
|
|
|
std::string fullPath(path);
|
|
|
|
auto position = fullPath.find(":");
|
|
|
|
if(position == std::string::npos)
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Invalid path.");
|
|
|
|
}
|
|
|
|
PATHINFO result;
|
|
|
|
result.deviceName = std::string(fullPath.begin(), fullPath.begin() + position);
|
|
|
|
result.devicePath = std::string(fullPath.begin() + position + 1, fullPath.end());
|
|
|
|
//Some games (Street Fighter EX3) provide paths with trailing spaces
|
|
|
|
result.devicePath = RightTrim(result.devicePath);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-09-16 18:29:18 -04:00
|
|
|
CIoman::CIoman(CIopBios& bios, uint8* ram)
|
|
|
|
: m_bios(bios)
|
|
|
|
, m_ram(ram)
|
2018-04-30 21:01:23 +01:00
|
|
|
, m_nextFileHandle(3)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2008-08-24 21:28:42 +00:00
|
|
|
CAppConfig::GetInstance().RegisterPreferenceBoolean(PREF_IOP_FILEIO_STDLOGGING, false);
|
2008-01-15 20:27:44 +00:00
|
|
|
|
|
|
|
//Insert standard files if requested.
|
2014-08-02 21:18:07 -04:00
|
|
|
if(CAppConfig::GetInstance().GetPreferenceBoolean(PREF_IOP_FILEIO_STDLOGGING)
|
|
|
|
#ifdef DEBUGGER_INCLUDED
|
2018-04-30 21:01:23 +01:00
|
|
|
|| true
|
2014-08-02 21:18:07 -04:00
|
|
|
#endif
|
2018-04-30 21:01:23 +01:00
|
|
|
)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2023-08-30 17:35:10 -04:00
|
|
|
auto stdoutPath = CAppConfig::GetInstance().GetBasePath() / "ps2_stdout.txt";
|
|
|
|
auto stderrPath = CAppConfig::GetInstance().GetBasePath() / "ps2_stderr.txt";
|
2014-08-02 21:18:07 -04:00
|
|
|
|
2019-02-06 20:18:27 -05:00
|
|
|
m_files[FID_STDOUT] = FileInfo{new Framework::CStdStream(fopen(stdoutPath.string().c_str(), "ab"))};
|
|
|
|
m_files[FID_STDERR] = FileInfo{new Framework::CStdStream(fopen(stderrPath.string().c_str(), "ab"))};
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
catch(...)
|
|
|
|
{
|
|
|
|
//Humm, some error occured when opening these files...
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CIoman::~CIoman()
|
|
|
|
{
|
2019-02-06 20:18:27 -05:00
|
|
|
m_files.clear();
|
2008-11-04 03:47:36 +00:00
|
|
|
m_devices.clear();
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2019-09-16 18:38:55 -04:00
|
|
|
void CIoman::PrepareOpenThunk()
|
|
|
|
{
|
|
|
|
if(m_openThunkPtr != 0) return;
|
|
|
|
|
|
|
|
static const uint32 thunkSize = 0x30;
|
|
|
|
auto sysmem = m_bios.GetSysmem();
|
|
|
|
m_openThunkPtr = sysmem->AllocateMemory(thunkSize, 0, 0);
|
|
|
|
|
|
|
|
static const int16 stackAlloc = 0x10;
|
|
|
|
|
|
|
|
CMIPSAssembler assembler(reinterpret_cast<uint32*>(m_ram + m_openThunkPtr));
|
|
|
|
|
|
|
|
auto finishLabel = assembler.CreateLabel();
|
|
|
|
|
|
|
|
//Save return value (stored in T0)
|
|
|
|
assembler.ADDIU(CMIPS::SP, CMIPS::SP, -stackAlloc);
|
|
|
|
assembler.SW(CMIPS::RA, 0x00, CMIPS::SP);
|
|
|
|
|
|
|
|
//Call open handler
|
|
|
|
assembler.JALR(CMIPS::A3);
|
|
|
|
assembler.SW(CMIPS::T0, 0x04, CMIPS::SP);
|
|
|
|
|
|
|
|
//Check if open handler reported error, if so, leave return value untouched
|
|
|
|
//TODO: Release handle if we failed to open properly
|
|
|
|
assembler.BLTZ(CMIPS::V0, finishLabel);
|
|
|
|
assembler.LW(CMIPS::RA, 0x00, CMIPS::SP);
|
|
|
|
|
|
|
|
assembler.LW(CMIPS::V0, 0x04, CMIPS::SP);
|
|
|
|
|
|
|
|
assembler.MarkLabel(finishLabel);
|
|
|
|
assembler.JR(CMIPS::RA);
|
|
|
|
assembler.ADDIU(CMIPS::SP, CMIPS::SP, stackAlloc);
|
|
|
|
|
|
|
|
assert((assembler.GetProgramSize() * 4) <= thunkSize);
|
|
|
|
}
|
|
|
|
|
2008-01-15 20:27:44 +00:00
|
|
|
std::string CIoman::GetId() const
|
|
|
|
{
|
2012-05-26 18:37:09 +00:00
|
|
|
return "ioman";
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2012-05-26 18:37:09 +00:00
|
|
|
std::string CIoman::GetFunctionName(unsigned int functionId) const
|
2008-11-28 23:46:52 +00:00
|
|
|
{
|
2012-11-10 22:53:43 +00:00
|
|
|
switch(functionId)
|
|
|
|
{
|
|
|
|
case 4:
|
|
|
|
return "open";
|
|
|
|
break;
|
2016-01-09 18:47:54 -05:00
|
|
|
case 5:
|
|
|
|
return "close";
|
|
|
|
break;
|
2012-11-10 22:53:43 +00:00
|
|
|
case 6:
|
|
|
|
return "read";
|
|
|
|
break;
|
2021-01-22 19:20:34 -05:00
|
|
|
case 7:
|
|
|
|
return FUNCTION_WRITE;
|
|
|
|
break;
|
2012-11-10 22:53:43 +00:00
|
|
|
case 8:
|
|
|
|
return "seek";
|
|
|
|
break;
|
2022-03-10 13:44:20 +01:00
|
|
|
case 11:
|
|
|
|
return "mkdir";
|
|
|
|
break;
|
|
|
|
case 13:
|
|
|
|
return "dopen";
|
|
|
|
break;
|
|
|
|
case 14:
|
|
|
|
return "dclose";
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
return "dread";
|
|
|
|
break;
|
2016-07-09 21:20:52 -04:00
|
|
|
case 16:
|
|
|
|
return "getstat";
|
|
|
|
break;
|
2024-08-09 17:05:21 -04:00
|
|
|
case 17:
|
|
|
|
return FUNCTION_CHSTAT;
|
|
|
|
break;
|
2016-12-08 00:25:07 -05:00
|
|
|
case 20:
|
|
|
|
return FUNCTION_ADDDRV;
|
|
|
|
break;
|
|
|
|
case 21:
|
|
|
|
return FUNCTION_DELDRV;
|
|
|
|
break;
|
2024-08-12 18:10:33 -04:00
|
|
|
case 25:
|
|
|
|
return FUNCTION_RENAME;
|
|
|
|
break;
|
2021-03-04 20:35:23 -05:00
|
|
|
case 31:
|
|
|
|
return FUNCTION_DEVCTL;
|
|
|
|
break;
|
2012-11-10 22:53:43 +00:00
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
break;
|
|
|
|
}
|
2008-11-28 23:46:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-03 21:18:18 -05:00
|
|
|
void CIoman::RegisterDevice(const char* name, const Ioman::DevicePtr& device)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2012-05-26 18:37:09 +00:00
|
|
|
m_devices[name] = device;
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CIoman::Open(uint32 flags, const char* path)
|
|
|
|
{
|
2017-05-29 06:01:32 +01:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Open(flags = 0x%08X, path = '%s');\r\n", flags, path);
|
2014-08-07 02:34:03 -04:00
|
|
|
|
2019-09-16 18:38:55 -04:00
|
|
|
int32 handle = PreOpen(flags, path);
|
|
|
|
if(handle < 0)
|
2016-08-12 22:29:01 -04:00
|
|
|
{
|
2019-09-16 18:38:55 -04:00
|
|
|
return handle;
|
2016-08-12 22:29:01 -04:00
|
|
|
}
|
|
|
|
|
2019-09-16 18:38:55 -04:00
|
|
|
assert(!IsUserDeviceFileHandle(handle));
|
2012-05-26 18:37:09 +00:00
|
|
|
return handle;
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2019-02-06 20:18:27 -05:00
|
|
|
Framework::CStream* CIoman::OpenInternal(uint32 flags, const char* path)
|
|
|
|
{
|
|
|
|
auto pathInfo = SplitPath(path);
|
|
|
|
auto deviceIterator = m_devices.find(pathInfo.deviceName);
|
|
|
|
if(deviceIterator == m_devices.end())
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Device not found.");
|
|
|
|
}
|
|
|
|
auto stream = deviceIterator->second->GetFile(flags, pathInfo.devicePath.c_str());
|
|
|
|
if(!stream)
|
|
|
|
{
|
|
|
|
throw std::runtime_error("File not found.");
|
|
|
|
}
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
|
2008-01-15 20:27:44 +00:00
|
|
|
uint32 CIoman::Close(uint32 handle)
|
|
|
|
{
|
2014-08-07 02:34:03 -04:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Close(handle = %d);\r\n", handle);
|
|
|
|
|
2012-05-26 18:37:09 +00:00
|
|
|
uint32 result = 0xFFFFFFFF;
|
2019-09-16 18:38:55 -04:00
|
|
|
assert(!IsUserDeviceFileHandle(handle));
|
2012-05-26 18:37:09 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
auto file(m_files.find(handle));
|
|
|
|
if(file == std::end(m_files))
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Invalid file handle.");
|
|
|
|
}
|
2019-09-16 18:38:55 -04:00
|
|
|
FreeFileHandle(handle);
|
2016-12-11 16:57:50 -05:00
|
|
|
//Returns handle instead of 0 (needed by Naruto: Ultimate Ninja 2)
|
|
|
|
result = handle;
|
2012-05-26 18:37:09 +00:00
|
|
|
}
|
|
|
|
catch(const std::exception& except)
|
|
|
|
{
|
2018-05-24 12:59:15 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s: Error occured while trying to close file : %s\r\n", __FUNCTION__, except.what());
|
2012-05-26 18:37:09 +00:00
|
|
|
}
|
|
|
|
return result;
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CIoman::Read(uint32 handle, uint32 size, void* buffer)
|
|
|
|
{
|
2014-08-07 02:34:03 -04:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Read(handle = %d, size = 0x%X, buffer = ptr);\r\n", handle, size);
|
|
|
|
|
2012-05-26 18:37:09 +00:00
|
|
|
uint32 result = 0xFFFFFFFF;
|
2019-09-16 18:38:55 -04:00
|
|
|
assert(!IsUserDeviceFileHandle(handle));
|
2012-05-26 18:37:09 +00:00
|
|
|
try
|
|
|
|
{
|
2018-04-09 09:41:12 -04:00
|
|
|
auto stream = GetFileStream(handle);
|
2018-02-06 19:03:31 -05:00
|
|
|
if(stream->IsEOF())
|
|
|
|
{
|
|
|
|
result = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result = static_cast<uint32>(stream->Read(buffer, size));
|
|
|
|
}
|
2012-05-26 18:37:09 +00:00
|
|
|
}
|
|
|
|
catch(const std::exception& except)
|
|
|
|
{
|
2018-05-24 12:59:15 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s: Error occured while trying to read file : %s\r\n", __FUNCTION__, except.what());
|
2012-05-26 18:37:09 +00:00
|
|
|
}
|
|
|
|
return result;
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2014-08-02 21:18:07 -04:00
|
|
|
uint32 CIoman::Write(uint32 handle, uint32 size, const void* buffer)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2014-08-07 02:34:03 -04:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Write(handle = %d, size = 0x%X, buffer = ptr);\r\n", handle, size);
|
|
|
|
|
2012-05-26 18:37:09 +00:00
|
|
|
uint32 result = 0xFFFFFFFF;
|
2019-09-16 18:38:55 -04:00
|
|
|
assert(!IsUserDeviceFileHandle(handle));
|
2012-05-26 18:37:09 +00:00
|
|
|
try
|
|
|
|
{
|
2018-04-09 09:41:12 -04:00
|
|
|
auto stream = GetFileStream(handle);
|
2020-07-06 16:03:35 -04:00
|
|
|
if(!stream)
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Failed to obtain file stream.");
|
|
|
|
}
|
2012-05-26 18:37:09 +00:00
|
|
|
result = static_cast<uint32>(stream->Write(buffer, size));
|
2014-08-02 21:18:07 -04:00
|
|
|
if((handle == FID_STDOUT) || (handle == FID_STDERR))
|
|
|
|
{
|
|
|
|
//Force flusing stdout and stderr
|
|
|
|
stream->Flush();
|
|
|
|
}
|
2012-05-26 18:37:09 +00:00
|
|
|
}
|
|
|
|
catch(const std::exception& except)
|
|
|
|
{
|
2014-08-02 21:18:07 -04:00
|
|
|
if((handle != FID_STDOUT) && (handle != FID_STDERR))
|
|
|
|
{
|
2018-05-24 12:59:15 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s: Error occured while trying to write file : %s\r\n", __FUNCTION__, except.what());
|
2014-08-02 21:18:07 -04:00
|
|
|
}
|
2012-05-26 18:37:09 +00:00
|
|
|
}
|
|
|
|
return result;
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2021-01-06 08:26:18 -05:00
|
|
|
uint32 CIoman::Seek(uint32 handle, int32 position, uint32 whence)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2021-01-06 08:26:18 -05:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Seek(handle = %d, position = %d, whence = %d);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
handle, position, whence);
|
2014-08-07 02:34:03 -04:00
|
|
|
|
2021-01-06 10:54:25 -05:00
|
|
|
uint32 result = -1U;
|
2019-09-16 18:38:55 -04:00
|
|
|
assert(!IsUserDeviceFileHandle(handle));
|
2012-05-26 18:37:09 +00:00
|
|
|
try
|
|
|
|
{
|
2018-04-09 09:41:12 -04:00
|
|
|
auto stream = GetFileStream(handle);
|
2021-01-06 10:54:25 -05:00
|
|
|
auto direction = ConvertWhence(whence);
|
|
|
|
stream->Seek(position, direction);
|
2012-05-26 18:37:09 +00:00
|
|
|
result = static_cast<uint32>(stream->Tell());
|
|
|
|
}
|
|
|
|
catch(const std::exception& except)
|
|
|
|
{
|
2018-05-24 12:59:15 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s: Error occured while trying to seek file : %s\r\n", __FUNCTION__, except.what());
|
2012-05-26 18:37:09 +00:00
|
|
|
}
|
|
|
|
return result;
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2020-04-23 17:00:09 +02:00
|
|
|
int32 CIoman::Mkdir(const char* path)
|
|
|
|
{
|
2021-01-05 17:12:08 -05:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Mkdir(path = '%s');\r\n", path);
|
2020-04-23 17:00:09 +02:00
|
|
|
try
|
|
|
|
{
|
2021-01-05 17:12:08 -05:00
|
|
|
auto pathInfo = SplitPath(path);
|
|
|
|
auto deviceIterator = m_devices.find(pathInfo.deviceName);
|
|
|
|
if(deviceIterator == m_devices.end())
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Device not found.");
|
|
|
|
}
|
|
|
|
|
2021-01-06 11:06:44 -05:00
|
|
|
deviceIterator->second->MakeDirectory(pathInfo.devicePath.c_str());
|
2020-04-23 17:00:09 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2021-01-05 17:12:08 -05:00
|
|
|
catch(const std::exception& except)
|
2020-04-23 17:00:09 +02:00
|
|
|
{
|
2021-01-05 17:12:08 -05:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s: Error occured while trying to create directory : %s\r\n", __FUNCTION__, except.what());
|
2020-04-23 17:00:09 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-20 19:05:24 -04:00
|
|
|
int32 CIoman::Dopen(const char* path)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Dopen(path = '%s');\r\n",
|
|
|
|
path);
|
|
|
|
int32 handle = -1;
|
|
|
|
try
|
|
|
|
{
|
2018-09-20 19:19:25 -04:00
|
|
|
auto pathInfo = SplitPath(path);
|
|
|
|
auto deviceIterator = m_devices.find(pathInfo.deviceName);
|
2018-09-20 19:05:24 -04:00
|
|
|
if(deviceIterator == m_devices.end())
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Device not found.");
|
|
|
|
}
|
2018-09-20 19:19:25 -04:00
|
|
|
auto directory = deviceIterator->second->GetDirectory(pathInfo.devicePath.c_str());
|
2018-09-20 19:05:24 -04:00
|
|
|
handle = m_nextFileHandle++;
|
2022-02-25 17:32:56 -05:00
|
|
|
m_directories[handle] = std::move(directory);
|
2018-09-20 19:05:24 -04:00
|
|
|
}
|
|
|
|
catch(const std::exception& except)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s: Error occured while trying to open directory : %s\r\n", __FUNCTION__, except.what());
|
|
|
|
}
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 CIoman::Dclose(uint32 handle)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Dclose(handle = %d);\r\n",
|
|
|
|
handle);
|
|
|
|
|
|
|
|
auto directoryIterator = m_directories.find(handle);
|
|
|
|
if(directoryIterator == std::end(m_directories))
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_directories.erase(directoryIterator);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-13 12:01:17 -04:00
|
|
|
int32 CIoman::Dread(uint32 handle, Ioman::DIRENTRY* dirEntry)
|
2018-09-20 19:05:24 -04:00
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Dread(handle = %d, entry = ptr);\r\n",
|
|
|
|
handle);
|
|
|
|
|
|
|
|
auto directoryIterator = m_directories.find(handle);
|
|
|
|
if(directoryIterator == std::end(m_directories))
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto& directory = directoryIterator->second;
|
2022-02-25 17:32:56 -05:00
|
|
|
if(directory->IsDone())
|
2018-09-20 19:05:24 -04:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-02-25 17:32:56 -05:00
|
|
|
directory->ReadEntry(dirEntry);
|
2018-09-20 19:05:24 -04:00
|
|
|
|
|
|
|
return strlen(dirEntry->name);
|
|
|
|
}
|
|
|
|
|
2019-09-13 12:01:17 -04:00
|
|
|
uint32 CIoman::GetStat(const char* path, Ioman::STAT* stat)
|
2015-12-29 17:42:02 -05:00
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "GetStat(path = '%s', stat = ptr);\r\n", path);
|
|
|
|
|
2023-02-27 15:09:34 -05:00
|
|
|
try
|
2023-01-05 20:07:15 -05:00
|
|
|
{
|
2023-02-27 15:09:34 -05:00
|
|
|
//Try with device's built-in GetStat
|
|
|
|
auto pathInfo = SplitPath(path);
|
|
|
|
auto deviceIterator = m_devices.find(pathInfo.deviceName);
|
|
|
|
if(deviceIterator != m_devices.end())
|
2023-01-05 20:07:15 -05:00
|
|
|
{
|
2023-02-27 15:09:34 -05:00
|
|
|
bool succeeded = false;
|
|
|
|
if(deviceIterator->second->TryGetStat(pathInfo.devicePath.c_str(), succeeded, *stat))
|
|
|
|
{
|
|
|
|
return succeeded ? 0 : -1;
|
|
|
|
}
|
2023-01-05 20:07:15 -05:00
|
|
|
}
|
|
|
|
}
|
2023-02-27 15:09:34 -05:00
|
|
|
catch(const std::exception& except)
|
|
|
|
{
|
|
|
|
//Warn, but carry on even if failed this
|
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s: Error occured while trying device's GetStat for '%s'. : %s\r\n",
|
|
|
|
__FUNCTION__, path, except.what());
|
|
|
|
}
|
2023-01-06 12:26:39 -05:00
|
|
|
|
2021-01-08 10:44:40 -05:00
|
|
|
//Try with a directory
|
2015-12-29 17:42:02 -05:00
|
|
|
{
|
2021-01-08 10:44:40 -05:00
|
|
|
int32 fd = Dopen(path);
|
2018-09-20 19:18:55 -04:00
|
|
|
if(fd >= 0)
|
|
|
|
{
|
2021-01-08 10:44:40 -05:00
|
|
|
Dclose(fd);
|
2019-09-13 12:01:17 -04:00
|
|
|
memset(stat, 0, sizeof(Ioman::STAT));
|
2022-02-25 17:32:56 -05:00
|
|
|
stat->mode = Ioman::STAT_MODE_DIR;
|
2018-09-20 19:18:55 -04:00
|
|
|
return 0;
|
|
|
|
}
|
2015-12-29 17:42:02 -05:00
|
|
|
}
|
2018-09-20 19:18:55 -04:00
|
|
|
|
2021-01-08 10:44:40 -05:00
|
|
|
//Try with a file
|
2018-09-20 19:18:55 -04:00
|
|
|
{
|
2021-01-08 10:44:40 -05:00
|
|
|
int32 fd = Open(Ioman::CDevice::OPEN_FLAG_RDONLY, path);
|
2018-09-20 19:18:55 -04:00
|
|
|
if(fd >= 0)
|
|
|
|
{
|
2021-01-08 10:44:40 -05:00
|
|
|
uint32 size = Seek(fd, 0, SEEK_DIR_END);
|
|
|
|
Close(fd);
|
2019-09-13 12:01:17 -04:00
|
|
|
memset(stat, 0, sizeof(Ioman::STAT));
|
2022-02-25 17:32:56 -05:00
|
|
|
stat->mode = Ioman::STAT_MODE_FILE;
|
2021-01-08 10:44:40 -05:00
|
|
|
stat->loSize = size;
|
2018-09-20 19:18:55 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2015-12-29 17:42:02 -05:00
|
|
|
}
|
|
|
|
|
2024-08-09 17:05:21 -04:00
|
|
|
int32 CIoman::ChStat(const char* path, Ioman::STAT* stat, uint32 statMask)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_CHSTAT "(path = '%s', stat = ptr, statMask = 0x%08X);\r\n",
|
|
|
|
path, statMask);
|
|
|
|
return GetStat(path, stat);
|
|
|
|
}
|
|
|
|
|
2019-09-16 18:38:55 -04:00
|
|
|
int32 CIoman::AddDrv(CMIPS& context)
|
2012-05-29 01:08:09 +00:00
|
|
|
{
|
2019-09-16 18:38:55 -04:00
|
|
|
auto devicePtr = context.m_State.nGPR[CMIPS::A0].nV0;
|
|
|
|
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_ADDDRV "(devicePtr = 0x%08X);\r\n",
|
|
|
|
devicePtr);
|
|
|
|
|
|
|
|
auto device = reinterpret_cast<const Ioman::DEVICE*>(m_ram + devicePtr);
|
|
|
|
auto deviceName = device->namePtr ? reinterpret_cast<const char*>(m_ram + device->namePtr) : nullptr;
|
2023-05-02 08:56:25 -04:00
|
|
|
FRAMEWORK_MAYBE_UNUSED auto deviceDesc = device->descPtr ? reinterpret_cast<const char*>(m_ram + device->descPtr) : nullptr;
|
2019-09-16 18:38:55 -04:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Requested registration of device '%s'.\r\n", deviceName);
|
2024-10-16 17:38:30 -04:00
|
|
|
if(!deviceName)
|
2019-09-16 18:38:55 -04:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2024-10-16 17:38:30 -04:00
|
|
|
|
|
|
|
//We only allow "cdfs" & "dev9x" for now
|
|
|
|
static std::set<std::string> allowedDevices = {"cdfs", "dev9x"};
|
|
|
|
if(allowedDevices.count(deviceName))
|
|
|
|
{
|
|
|
|
m_userDevices.insert(std::make_pair(deviceName, devicePtr));
|
|
|
|
InvokeUserDeviceMethod(context, devicePtr, offsetof(Ioman::DEVICEOPS, initPtr), devicePtr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//We will report to "cdrom_stm" that registration succeeded, but we don't actually
|
|
|
|
//add it to our device list.
|
|
|
|
static std::set<std::string> silentDevices = {"cdrom_stm"};
|
|
|
|
if(silentDevices.count(deviceName))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//If we get here, we failed.
|
|
|
|
return -1;
|
2012-05-29 01:08:09 +00:00
|
|
|
}
|
|
|
|
|
2016-12-09 09:43:29 -05:00
|
|
|
uint32 CIoman::DelDrv(uint32 drvNamePtr)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2016-12-09 09:43:29 -05:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_DELDRV "(drvNamePtr = %s);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
PrintStringParameter(m_ram, drvNamePtr).c_str());
|
2012-05-26 18:37:09 +00:00
|
|
|
return -1;
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2024-08-12 18:10:33 -04:00
|
|
|
int32 CIoman::Rename(const char* srcPath, const char* dstPath)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_RENAME "(srcPath = '%s', dstPath = '%s');\r\n",
|
|
|
|
srcPath, dstPath);
|
|
|
|
int32 result = -1;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto srcPathInfo = SplitPath(srcPath);
|
|
|
|
auto dstPathInfo = SplitPath(dstPath);
|
|
|
|
if(srcPathInfo.deviceName != dstPathInfo.deviceName)
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Renaming files across devices not supported.");
|
|
|
|
}
|
|
|
|
auto deviceIterator = m_devices.find(srcPathInfo.deviceName);
|
|
|
|
if(deviceIterator == m_devices.end())
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Device not found.");
|
|
|
|
}
|
|
|
|
deviceIterator->second->Rename(srcPathInfo.devicePath.c_str(), dstPathInfo.devicePath.c_str());
|
|
|
|
}
|
|
|
|
catch(const std::exception& except)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s: Error occured while trying to rename file '%s' to '%s'\r\n",
|
|
|
|
__FUNCTION__, srcPath, dstPath, except.what());
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-03-04 20:35:23 -05:00
|
|
|
int32 CIoman::DevCtlVirtual(CMIPS& context)
|
|
|
|
{
|
|
|
|
uint32 deviceNamePtr = context.m_State.nGPR[CMIPS::A0].nV0;
|
|
|
|
uint32 commandId = context.m_State.nGPR[CMIPS::A1].nV0;
|
|
|
|
uint32 inputPtr = context.m_State.nGPR[CMIPS::A2].nV0;
|
|
|
|
uint32 inputSize = context.m_State.nGPR[CMIPS::A3].nV0;
|
|
|
|
uint32 outputPtr = context.m_pMemoryMap->GetWord(context.m_State.nGPR[CMIPS::SP].nV0 + 0x10);
|
|
|
|
uint32 outputSize = context.m_pMemoryMap->GetWord(context.m_State.nGPR[CMIPS::SP].nV0 + 0x14);
|
|
|
|
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_DEVCTL "(deviceName = %s, cmd = 0x%08X, input = 0x%08X, inputSize = 0x%08X, output = 0x%08X, outputSize = 0x%08X);\r\n",
|
|
|
|
PrintStringParameter(m_ram, deviceNamePtr).c_str(), commandId, inputPtr, inputSize, outputPtr, outputSize);
|
2021-03-07 18:22:55 -05:00
|
|
|
|
2021-03-04 20:35:23 -05:00
|
|
|
auto deviceName = reinterpret_cast<const char*>(m_ram + deviceNamePtr);
|
|
|
|
auto input = reinterpret_cast<const uint32*>(m_ram + inputPtr);
|
|
|
|
auto output = reinterpret_cast<uint32*>(m_ram + outputPtr);
|
2021-03-07 18:22:55 -05:00
|
|
|
|
2021-03-04 20:35:23 -05:00
|
|
|
return DevCtl(deviceName, commandId, input, inputSize, output, outputSize);
|
|
|
|
}
|
|
|
|
|
2021-01-05 17:19:49 -05:00
|
|
|
int32 CIoman::Mount(const char* fsName, const char* devicePath)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_MOUNT "(fsName = '%s', devicePath = '%s');\r\n",
|
2021-01-08 18:30:28 -05:00
|
|
|
fsName, devicePath);
|
|
|
|
|
2021-01-05 17:19:49 -05:00
|
|
|
auto pathInfo = SplitPath(devicePath);
|
|
|
|
auto deviceIterator = m_devices.find(pathInfo.deviceName);
|
|
|
|
if(deviceIterator == m_devices.end())
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto device = deviceIterator->second;
|
|
|
|
uint32 result = 0;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto mountedDeviceName = std::string(fsName);
|
|
|
|
//Strip any colons we might have in the string
|
|
|
|
mountedDeviceName.erase(std::remove(mountedDeviceName.begin(), mountedDeviceName.end(), ':'), mountedDeviceName.end());
|
|
|
|
assert(m_devices.find(mountedDeviceName) == std::end(m_devices));
|
2023-01-11 10:39:32 -05:00
|
|
|
assert(m_mountedDevices.find(mountedDeviceName) == std::end(m_mountedDevices));
|
2021-01-05 17:19:49 -05:00
|
|
|
|
2023-01-03 21:18:18 -05:00
|
|
|
auto mountedDevice = device->Mount(pathInfo.devicePath.c_str());
|
2021-01-05 17:19:49 -05:00
|
|
|
m_devices[mountedDeviceName] = mountedDevice;
|
2023-01-11 10:39:32 -05:00
|
|
|
m_mountedDevices[mountedDeviceName] = devicePath;
|
2021-01-05 17:19:49 -05:00
|
|
|
}
|
|
|
|
catch(const std::exception& except)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s: Error occurred while trying to mount : %s : %s\r\n", __FUNCTION__, devicePath, except.what());
|
|
|
|
result = -1;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 CIoman::Umount(const char* deviceName)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_UMOUNT "(deviceName = '%s');\r\n", deviceName);
|
|
|
|
|
|
|
|
auto mountedDeviceName = std::string(deviceName);
|
|
|
|
//Strip any colons we might have in the string
|
|
|
|
mountedDeviceName.erase(std::remove(mountedDeviceName.begin(), mountedDeviceName.end(), ':'), mountedDeviceName.end());
|
2021-01-08 18:30:28 -05:00
|
|
|
|
2021-01-05 17:19:49 -05:00
|
|
|
auto deviceIterator = m_devices.find(mountedDeviceName);
|
|
|
|
if(deviceIterator == std::end(m_devices))
|
|
|
|
{
|
|
|
|
//Device not found
|
|
|
|
return -1;
|
|
|
|
}
|
2021-01-08 18:30:28 -05:00
|
|
|
|
2021-01-05 17:19:49 -05:00
|
|
|
//We maybe need to make sure we don't have outstanding fds?
|
|
|
|
m_devices.erase(deviceIterator);
|
2023-01-12 16:27:14 -05:00
|
|
|
|
2023-01-11 10:39:32 -05:00
|
|
|
{
|
|
|
|
auto mountedDeviceIterator = m_mountedDevices.find(mountedDeviceName);
|
|
|
|
assert(mountedDeviceIterator != std::end(m_mountedDevices));
|
|
|
|
m_mountedDevices.erase(mountedDeviceIterator);
|
|
|
|
}
|
2021-01-08 18:30:28 -05:00
|
|
|
|
2021-01-05 17:19:49 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-01-06 10:54:25 -05:00
|
|
|
uint64 CIoman::Seek64(uint32 handle, int64 position, uint32 whence)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_SEEK64 "(handle = %d, position = %ld, whence = %d);\r\n",
|
2021-01-08 18:30:28 -05:00
|
|
|
handle, position, whence);
|
2021-01-06 10:54:25 -05:00
|
|
|
|
|
|
|
uint64 result = -1ULL;
|
|
|
|
assert(!IsUserDeviceFileHandle(handle));
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto stream = GetFileStream(handle);
|
|
|
|
auto direction = ConvertWhence(whence);
|
|
|
|
stream->Seek(position, direction);
|
|
|
|
result = stream->Tell();
|
|
|
|
}
|
|
|
|
catch(const std::exception& except)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s: Error occured while trying to seek file : %s\r\n", __FUNCTION__, except.what());
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-03-04 20:33:00 -05:00
|
|
|
int32 CIoman::DevCtl(const char* deviceName, uint32 command, const uint32* input, uint32 inputSize, uint32* output, uint32 outputSize)
|
|
|
|
{
|
|
|
|
uint32 result = 0;
|
|
|
|
switch(command)
|
|
|
|
{
|
2021-03-08 20:02:14 -05:00
|
|
|
case DEVCTL_CDVD_READCLOCK:
|
|
|
|
assert(inputSize == 0);
|
|
|
|
assert(outputSize == 8);
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "CdReadClock();\r\n");
|
|
|
|
break;
|
2021-03-04 20:33:00 -05:00
|
|
|
case DEVCTL_CDVD_GETERROR:
|
|
|
|
assert(outputSize == 4);
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "CdGetError();\r\n");
|
|
|
|
output[0] = 0; //No error
|
|
|
|
break;
|
2023-03-14 14:28:06 -04:00
|
|
|
case DEVCTL_CDVD_STATUS:
|
|
|
|
//Used by Star Soldier
|
|
|
|
assert(outputSize == 4);
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "CdStatus();\r\n");
|
|
|
|
output[0] = 10; //CDVD_STATUS_PAUSED
|
|
|
|
break;
|
2021-03-04 20:33:00 -05:00
|
|
|
case DEVCTL_CDVD_DISKREADY:
|
|
|
|
assert(inputSize == 4);
|
|
|
|
assert(outputSize == 4);
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "CdDiskReady(%d);\r\n", input[0]);
|
|
|
|
output[0] = 2; //Disk ready
|
|
|
|
break;
|
|
|
|
case DEVCTL_HDD_STATUS:
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "HddStatus();\r\n");
|
|
|
|
break;
|
2022-01-31 16:33:24 -05:00
|
|
|
case DEVCTL_HDD_MAXSECTOR:
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "HddMaxSector();\r\n");
|
|
|
|
result = 0x400000; //Max num of sectors per partition
|
|
|
|
break;
|
2021-03-04 20:33:00 -05:00
|
|
|
case DEVCTL_HDD_TOTALSECTOR:
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "HddTotalSector();\r\n");
|
|
|
|
result = 0x400000; //Number of sectors
|
|
|
|
break;
|
|
|
|
case DEVCTL_HDD_FREESECTOR:
|
|
|
|
assert(outputSize == 4);
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "HddFreeSector();\r\n");
|
|
|
|
output[0] = 0x400000; //Number of sectors
|
|
|
|
break;
|
|
|
|
case DEVCTL_PFS_ZONESIZE:
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "PfsZoneSize();\r\n");
|
|
|
|
result = 0x1000000;
|
|
|
|
break;
|
|
|
|
case DEVCTL_PFS_ZONEFREE:
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "PfsZoneFree();\r\n");
|
|
|
|
result = 0x10;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "DevCtl -> Unknown(deviceName = '%s', cmd = 0x%08X);\r\n", deviceName, command);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-09-16 18:38:55 -04:00
|
|
|
int32 CIoman::PreOpen(uint32 flags, const char* path)
|
|
|
|
{
|
|
|
|
int32 handle = AllocateFileHandle();
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto& file = m_files[handle];
|
|
|
|
file.path = path;
|
|
|
|
file.flags = flags;
|
|
|
|
|
|
|
|
auto pathInfo = SplitPath(path);
|
|
|
|
auto deviceIterator = m_devices.find(pathInfo.deviceName);
|
|
|
|
auto userDeviceIterator = m_userDevices.find(pathInfo.deviceName);
|
|
|
|
if(deviceIterator != m_devices.end())
|
|
|
|
{
|
|
|
|
file.stream = deviceIterator->second->GetFile(flags, pathInfo.devicePath.c_str());
|
|
|
|
if(!file.stream)
|
|
|
|
{
|
2020-11-06 22:06:01 +01:00
|
|
|
throw FileNotFoundException();
|
2019-09-16 18:38:55 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(userDeviceIterator != m_userDevices.end())
|
|
|
|
{
|
|
|
|
auto sysmem = m_bios.GetSysmem();
|
|
|
|
file.descPtr = sysmem->AllocateMemory(sizeof(Ioman::DEVICEFILE), 0, 0);
|
|
|
|
assert(file.descPtr != 0);
|
|
|
|
auto desc = reinterpret_cast<Ioman::DEVICEFILE*>(m_ram + file.descPtr);
|
|
|
|
desc->devicePtr = userDeviceIterator->second;
|
|
|
|
desc->privateData = 0;
|
|
|
|
desc->unit = 0;
|
|
|
|
desc->mode = flags;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Unknown device.");
|
|
|
|
}
|
|
|
|
}
|
2020-11-06 22:06:01 +01:00
|
|
|
catch(const CIoman::FileNotFoundException& except)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s: Error occurred while trying to open not existing file : %s\r\n", __FUNCTION__, path);
|
|
|
|
FreeFileHandle(handle);
|
|
|
|
|
|
|
|
return -ERROR_ENOENT;
|
|
|
|
}
|
2019-09-16 18:38:55 -04:00
|
|
|
catch(const std::exception& except)
|
|
|
|
{
|
2020-11-06 22:06:01 +01:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s: Error occurred while trying to open file : %s : %s\r\n", __FUNCTION__, path, except.what());
|
2019-09-16 18:38:55 -04:00
|
|
|
FreeFileHandle(handle);
|
2020-11-06 22:06:01 +01:00
|
|
|
|
2019-09-16 18:38:55 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
2021-01-06 10:54:25 -05:00
|
|
|
Framework::STREAM_SEEK_DIRECTION CIoman::ConvertWhence(uint32 whence)
|
|
|
|
{
|
|
|
|
switch(whence)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
[[fallthrough]];
|
|
|
|
case SEEK_DIR_SET:
|
|
|
|
return Framework::STREAM_SEEK_SET;
|
|
|
|
case SEEK_DIR_CUR:
|
|
|
|
return Framework::STREAM_SEEK_CUR;
|
|
|
|
case SEEK_DIR_END:
|
|
|
|
return Framework::STREAM_SEEK_END;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-16 18:38:55 -04:00
|
|
|
bool CIoman::IsUserDeviceFileHandle(int32 fileHandle) const
|
|
|
|
{
|
2019-09-21 22:36:41 -04:00
|
|
|
auto fileIterator = m_files.find(fileHandle);
|
|
|
|
if(fileIterator == std::end(m_files)) return false;
|
2019-09-16 18:38:55 -04:00
|
|
|
return GetUserDeviceFileDescPtr(fileHandle) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CIoman::GetUserDeviceFileDescPtr(int32 fileHandle) const
|
|
|
|
{
|
|
|
|
auto fileIterator = m_files.find(fileHandle);
|
2019-09-21 22:36:41 -04:00
|
|
|
assert(fileIterator != std::end(m_files));
|
2019-09-16 18:38:55 -04:00
|
|
|
const auto& file = fileIterator->second;
|
|
|
|
assert(!((file.descPtr != 0) && file.stream));
|
|
|
|
return file.descPtr;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 CIoman::OpenVirtual(CMIPS& context)
|
|
|
|
{
|
|
|
|
uint32 pathPtr = context.m_State.nGPR[CMIPS::A0].nV0;
|
|
|
|
uint32 flags = context.m_State.nGPR[CMIPS::A1].nV0;
|
|
|
|
|
|
|
|
auto path = reinterpret_cast<const char*>(m_ram + pathPtr);
|
|
|
|
|
2021-01-11 10:58:21 -05:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "OpenVirtual(flags = 0x%08X, path = '%s');\r\n", flags, path);
|
|
|
|
|
2019-09-16 18:38:55 -04:00
|
|
|
int32 handle = PreOpen(flags, path);
|
|
|
|
if(handle < 0)
|
|
|
|
{
|
|
|
|
//PreOpen failed, bail
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(IsUserDeviceFileHandle(handle))
|
|
|
|
{
|
|
|
|
PrepareOpenThunk();
|
|
|
|
|
|
|
|
auto devicePath = strchr(path, ':');
|
|
|
|
assert(devicePath);
|
|
|
|
auto devicePathPos = static_cast<uint32>(devicePath - path);
|
|
|
|
uint32 descPtr = GetUserDeviceFileDescPtr(handle);
|
|
|
|
auto desc = reinterpret_cast<Ioman::DEVICEFILE*>(m_ram + descPtr);
|
|
|
|
auto device = reinterpret_cast<Ioman::DEVICE*>(m_ram + desc->devicePtr);
|
|
|
|
auto ops = reinterpret_cast<Ioman::DEVICEOPS*>(m_ram + device->opsPtr);
|
|
|
|
|
|
|
|
context.m_State.nPC = m_openThunkPtr;
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0 = descPtr;
|
|
|
|
context.m_State.nGPR[CMIPS::A1].nV0 = pathPtr + devicePathPos + 1;
|
|
|
|
context.m_State.nGPR[CMIPS::A2].nV0 = flags;
|
|
|
|
context.m_State.nGPR[CMIPS::A3].nV0 = ops->openPtr;
|
|
|
|
context.m_State.nGPR[CMIPS::T0].nV0 = handle;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 CIoman::CloseVirtual(CMIPS& context)
|
|
|
|
{
|
|
|
|
int32 handle = context.m_State.nGPR[CMIPS::A0].nV0;
|
|
|
|
|
2021-01-11 10:58:21 -05:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "CloseVirtual(handle = %d);\r\n", handle);
|
|
|
|
|
2019-09-16 18:38:55 -04:00
|
|
|
auto fileIterator = m_files.find(handle);
|
|
|
|
if(fileIterator == std::end(m_files))
|
|
|
|
{
|
2019-09-18 13:25:37 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s : Provided invalid fd %d.\r\n",
|
|
|
|
__FUNCTION__, handle);
|
2019-09-16 18:38:55 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(IsUserDeviceFileHandle(handle))
|
|
|
|
{
|
|
|
|
//TODO: Free file handle
|
|
|
|
uint32 descPtr = GetUserDeviceFileDescPtr(handle);
|
|
|
|
auto desc = reinterpret_cast<Ioman::DEVICEFILE*>(m_ram + descPtr);
|
|
|
|
InvokeUserDeviceMethod(context, desc->devicePtr,
|
2019-09-18 13:25:37 -04:00
|
|
|
offsetof(Ioman::DEVICEOPS, closePtr),
|
|
|
|
descPtr);
|
2019-09-16 18:38:55 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return Close(handle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 CIoman::ReadVirtual(CMIPS& context)
|
|
|
|
{
|
|
|
|
int32 handle = context.m_State.nGPR[CMIPS::A0].nV0;
|
|
|
|
uint32 bufferPtr = context.m_State.nGPR[CMIPS::A1].nV0;
|
|
|
|
uint32 count = context.m_State.nGPR[CMIPS::A2].nV0;
|
|
|
|
|
2021-01-11 10:58:21 -05:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "ReadVirtual(handle = %d, size = 0x%X, buffer = ptr);\r\n", handle, count);
|
|
|
|
|
2019-09-16 18:38:55 -04:00
|
|
|
auto fileIterator = m_files.find(handle);
|
|
|
|
if(fileIterator == std::end(m_files))
|
|
|
|
{
|
2019-09-18 13:25:37 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s : Provided invalid fd %d.\r\n",
|
|
|
|
__FUNCTION__, handle);
|
2019-09-16 18:38:55 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(IsUserDeviceFileHandle(handle))
|
|
|
|
{
|
|
|
|
uint32 descPtr = GetUserDeviceFileDescPtr(handle);
|
|
|
|
auto desc = reinterpret_cast<Ioman::DEVICEFILE*>(m_ram + descPtr);
|
|
|
|
InvokeUserDeviceMethod(context, desc->devicePtr,
|
2019-09-18 13:25:37 -04:00
|
|
|
offsetof(Ioman::DEVICEOPS, readPtr),
|
|
|
|
descPtr, bufferPtr, count);
|
2019-09-16 18:38:55 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return Read(handle, count, m_ram + bufferPtr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-22 19:20:34 -05:00
|
|
|
int32 CIoman::WriteVirtual(CMIPS& context)
|
|
|
|
{
|
|
|
|
int32 handle = context.m_State.nGPR[CMIPS::A0].nV0;
|
|
|
|
uint32 bufferPtr = context.m_State.nGPR[CMIPS::A1].nV0;
|
|
|
|
uint32 count = context.m_State.nGPR[CMIPS::A2].nV0;
|
|
|
|
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "WriteVirtual(handle = %d, size = 0x%X, buffer = ptr);\r\n", handle, count);
|
|
|
|
|
|
|
|
auto fileIterator = m_files.find(handle);
|
|
|
|
if(fileIterator == std::end(m_files))
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s : Provided invalid fd %d.\r\n",
|
2021-02-19 17:28:10 -05:00
|
|
|
__FUNCTION__, handle);
|
2021-01-22 19:20:34 -05:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(IsUserDeviceFileHandle(handle))
|
|
|
|
{
|
|
|
|
uint32 descPtr = GetUserDeviceFileDescPtr(handle);
|
|
|
|
auto desc = reinterpret_cast<Ioman::DEVICEFILE*>(m_ram + descPtr);
|
|
|
|
InvokeUserDeviceMethod(context, desc->devicePtr,
|
2021-02-19 17:28:10 -05:00
|
|
|
offsetof(Ioman::DEVICEOPS, writePtr),
|
|
|
|
descPtr, bufferPtr, count);
|
2021-01-22 19:20:34 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return Write(handle, count, m_ram + bufferPtr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-16 18:38:55 -04:00
|
|
|
int32 CIoman::SeekVirtual(CMIPS& context)
|
|
|
|
{
|
|
|
|
int32 handle = context.m_State.nGPR[CMIPS::A0].nV0;
|
|
|
|
uint32 position = context.m_State.nGPR[CMIPS::A1].nV0;
|
|
|
|
uint32 whence = context.m_State.nGPR[CMIPS::A2].nV0;
|
|
|
|
|
2021-01-11 10:58:21 -05:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "SeekVirtual(handle = %d, position = %d, whence = %d);\r\n",
|
|
|
|
handle, position, whence);
|
|
|
|
|
2019-09-16 18:38:55 -04:00
|
|
|
auto fileIterator = m_files.find(handle);
|
|
|
|
if(fileIterator == std::end(m_files))
|
|
|
|
{
|
2019-09-18 13:25:37 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s : Provided invalid fd %d.\r\n",
|
|
|
|
__FUNCTION__, handle);
|
2019-09-16 18:38:55 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(IsUserDeviceFileHandle(handle))
|
|
|
|
{
|
|
|
|
uint32 descPtr = GetUserDeviceFileDescPtr(handle);
|
|
|
|
auto desc = reinterpret_cast<Ioman::DEVICEFILE*>(m_ram + descPtr);
|
|
|
|
InvokeUserDeviceMethod(context, desc->devicePtr,
|
2019-09-18 13:25:37 -04:00
|
|
|
offsetof(Ioman::DEVICEOPS, lseekPtr),
|
|
|
|
descPtr, position, whence);
|
2019-09-16 18:38:55 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return Seek(handle, position, whence);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CIoman::InvokeUserDeviceMethod(CMIPS& context, uint32 devicePtr, size_t opOffset, uint32 arg0, uint32 arg1, uint32 arg2)
|
|
|
|
{
|
|
|
|
auto device = reinterpret_cast<Ioman::DEVICE*>(m_ram + devicePtr);
|
|
|
|
auto opAddr = *reinterpret_cast<uint32*>(m_ram + device->opsPtr + opOffset);
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0 = arg0;
|
|
|
|
context.m_State.nGPR[CMIPS::A1].nV0 = arg1;
|
|
|
|
context.m_State.nGPR[CMIPS::A2].nV0 = arg2;
|
|
|
|
context.m_State.nPC = opAddr;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 CIoman::AllocateFileHandle()
|
|
|
|
{
|
|
|
|
uint32 handle = m_nextFileHandle++;
|
|
|
|
assert(m_files.find(handle) == std::end(m_files));
|
|
|
|
m_files[handle] = FileInfo();
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CIoman::FreeFileHandle(uint32 handle)
|
|
|
|
{
|
|
|
|
assert(m_files.find(handle) != std::end(m_files));
|
|
|
|
m_files.erase(handle);
|
|
|
|
}
|
|
|
|
|
2019-08-01 12:54:55 -04:00
|
|
|
uint32 CIoman::GetFileMode(uint32 handle) const
|
|
|
|
{
|
|
|
|
auto file(m_files.find(handle));
|
|
|
|
if(file == std::end(m_files))
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Invalid file handle.");
|
|
|
|
}
|
|
|
|
return file->second.flags;
|
|
|
|
}
|
|
|
|
|
2012-05-26 18:37:09 +00:00
|
|
|
Framework::CStream* CIoman::GetFileStream(uint32 handle)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2012-05-26 18:37:09 +00:00
|
|
|
auto file(m_files.find(handle));
|
|
|
|
if(file == std::end(m_files))
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Invalid file handle.");
|
|
|
|
}
|
2019-02-06 20:18:27 -05:00
|
|
|
return file->second.stream;
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2015-04-10 00:07:32 -04:00
|
|
|
void CIoman::SetFileStream(uint32 handle, Framework::CStream* stream)
|
|
|
|
{
|
2019-10-15 13:18:46 -04:00
|
|
|
m_files.erase(handle);
|
2019-02-06 20:18:27 -05:00
|
|
|
m_files[handle] = {stream};
|
2015-04-10 00:07:32 -04:00
|
|
|
}
|
|
|
|
|
2008-01-15 20:27:44 +00:00
|
|
|
//IOP Invoke
|
|
|
|
void CIoman::Invoke(CMIPS& context, unsigned int functionId)
|
|
|
|
{
|
2012-05-26 18:37:09 +00:00
|
|
|
switch(functionId)
|
|
|
|
{
|
|
|
|
case 4:
|
2019-09-16 18:38:55 -04:00
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(OpenVirtual(context));
|
2012-05-26 18:37:09 +00:00
|
|
|
break;
|
|
|
|
case 5:
|
2019-09-16 18:38:55 -04:00
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(CloseVirtual(context));
|
2012-05-26 18:37:09 +00:00
|
|
|
break;
|
|
|
|
case 6:
|
2019-09-16 18:38:55 -04:00
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(ReadVirtual(context));
|
2012-05-26 18:37:09 +00:00
|
|
|
break;
|
2021-01-22 19:20:34 -05:00
|
|
|
case 7:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(WriteVirtual(context));
|
|
|
|
break;
|
2012-05-26 18:37:09 +00:00
|
|
|
case 8:
|
2019-09-16 18:38:55 -04:00
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(SeekVirtual(context));
|
2012-05-26 18:37:09 +00:00
|
|
|
break;
|
2022-03-10 13:44:20 +01:00
|
|
|
case 11:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(Mkdir(
|
|
|
|
reinterpret_cast<char*>(&m_ram[context.m_State.nGPR[CMIPS::A0].nV[0]])));
|
|
|
|
break;
|
|
|
|
case 13:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(Dopen(
|
|
|
|
reinterpret_cast<char*>(&m_ram[context.m_State.nGPR[CMIPS::A0].nV[0]])));
|
|
|
|
break;
|
|
|
|
case 14:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(Dclose(
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0));
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(Dread(
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0,
|
|
|
|
reinterpret_cast<Ioman::DIRENTRY*>(&m_ram[context.m_State.nGPR[CMIPS::A1].nV[0]])));
|
|
|
|
break;
|
2016-07-09 21:20:52 -04:00
|
|
|
case 16:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(GetStat(
|
2018-04-30 21:01:23 +01:00
|
|
|
reinterpret_cast<char*>(&m_ram[context.m_State.nGPR[CMIPS::A0].nV[0]]),
|
2019-09-13 12:01:17 -04:00
|
|
|
reinterpret_cast<Ioman::STAT*>(&m_ram[context.m_State.nGPR[CMIPS::A1].nV[0]])));
|
2016-07-09 21:20:52 -04:00
|
|
|
break;
|
2024-08-09 17:05:21 -04:00
|
|
|
case 17:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = ChStat(
|
|
|
|
reinterpret_cast<const char*>(&m_ram[context.m_State.nGPR[CMIPS::A0].nV[0]]),
|
|
|
|
reinterpret_cast<Ioman::STAT*>(&m_ram[context.m_State.nGPR[CMIPS::A1].nV[0]]),
|
|
|
|
context.m_State.nGPR[CMIPS::A2].nV[0]);
|
|
|
|
break;
|
2012-05-29 01:08:09 +00:00
|
|
|
case 20:
|
2019-09-16 18:38:55 -04:00
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(AddDrv(context));
|
2012-05-29 01:08:09 +00:00
|
|
|
break;
|
2012-05-26 18:37:09 +00:00
|
|
|
case 21:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(DelDrv(
|
2018-04-30 21:01:23 +01:00
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0));
|
2012-05-26 18:37:09 +00:00
|
|
|
break;
|
2024-08-12 18:10:33 -04:00
|
|
|
case 25:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = Rename(
|
|
|
|
reinterpret_cast<const char*>(&m_ram[context.m_State.nGPR[CMIPS::A0].nV[0]]),
|
|
|
|
reinterpret_cast<const char*>(&m_ram[context.m_State.nGPR[CMIPS::A1].nV[0]]));
|
|
|
|
break;
|
2021-03-04 20:35:23 -05:00
|
|
|
case 31:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = DevCtlVirtual(context);
|
|
|
|
break;
|
2012-05-26 18:37:09 +00:00
|
|
|
default:
|
2018-05-24 12:59:15 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "%s(%08X): Unknown function (%d) called.\r\n", __FUNCTION__, context.m_State.nPC, functionId);
|
2012-05-26 18:37:09 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2020-09-22 17:20:14 -04:00
|
|
|
void CIoman::SaveState(Framework::CZipArchiveWriter& archive) const
|
2019-09-17 12:38:18 -04:00
|
|
|
{
|
2023-01-11 10:39:32 -05:00
|
|
|
SaveMountedDevicesState(archive);
|
2019-09-17 12:38:18 -04:00
|
|
|
SaveFilesState(archive);
|
|
|
|
SaveUserDevicesState(archive);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CIoman::LoadState(Framework::CZipArchiveReader& archive)
|
|
|
|
{
|
2023-01-11 10:39:32 -05:00
|
|
|
LoadMountedDevicesState(archive);
|
2019-09-17 12:38:18 -04:00
|
|
|
LoadFilesState(archive);
|
|
|
|
LoadUserDevicesState(archive);
|
|
|
|
}
|
|
|
|
|
2020-09-22 17:20:14 -04:00
|
|
|
void CIoman::SaveFilesState(Framework::CZipArchiveWriter& archive) const
|
2019-02-06 20:19:22 -05:00
|
|
|
{
|
2023-07-23 17:22:18 -04:00
|
|
|
auto fileStateFile = std::make_unique<CXmlStateFile>(STATE_FILES_FILENAME, STATE_FILES_FILESNODE);
|
2019-02-06 20:19:22 -05:00
|
|
|
auto filesStateNode = fileStateFile->GetRoot();
|
|
|
|
|
|
|
|
for(const auto& filePair : m_files)
|
|
|
|
{
|
|
|
|
if(filePair.first == FID_STDOUT) continue;
|
|
|
|
if(filePair.first == FID_STDERR) continue;
|
|
|
|
|
|
|
|
const auto& file = filePair.second;
|
|
|
|
|
2023-11-14 17:42:31 -05:00
|
|
|
auto fileStateNode = std::make_unique<Framework::Xml::CNode>(STATE_FILES_FILENODE, true);
|
2019-02-06 20:19:22 -05:00
|
|
|
fileStateNode->InsertAttribute(Framework::Xml::CreateAttributeIntValue(STATE_FILES_FILENODE_IDATTRIBUTE, filePair.first));
|
|
|
|
fileStateNode->InsertAttribute(Framework::Xml::CreateAttributeIntValue(STATE_FILES_FILENODE_FLAGSATTRIBUTE, file.flags));
|
2019-09-17 12:38:18 -04:00
|
|
|
fileStateNode->InsertAttribute(Framework::Xml::CreateAttributeIntValue(STATE_FILES_FILENODE_DESCPTRATTRIBUTE, file.descPtr));
|
2023-11-28 10:57:52 -05:00
|
|
|
fileStateNode->InsertAttribute(Framework::Xml::CreateAttributeInt64Value(STATE_FILES_FILENODE_POSITIONATTRIBUTE, file.stream->Tell()));
|
2019-02-06 20:19:22 -05:00
|
|
|
fileStateNode->InsertAttribute(Framework::Xml::CreateAttributeStringValue(STATE_FILES_FILENODE_PATHATTRIBUTE, file.path.c_str()));
|
2023-11-14 17:42:31 -05:00
|
|
|
filesStateNode->InsertNode(std::move(fileStateNode));
|
2019-02-06 20:19:22 -05:00
|
|
|
}
|
|
|
|
|
2023-07-23 17:22:18 -04:00
|
|
|
archive.InsertFile(std::move(fileStateFile));
|
2019-02-06 20:19:22 -05:00
|
|
|
}
|
|
|
|
|
2020-09-22 17:20:14 -04:00
|
|
|
void CIoman::SaveUserDevicesState(Framework::CZipArchiveWriter& archive) const
|
2019-09-17 12:38:18 -04:00
|
|
|
{
|
2023-07-23 17:22:18 -04:00
|
|
|
auto deviceStateFile = std::make_unique<CXmlStateFile>(STATE_USERDEVICES_FILENAME, STATE_USERDEVICES_DEVICESNODE);
|
2019-09-17 12:38:18 -04:00
|
|
|
auto devicesStateNode = deviceStateFile->GetRoot();
|
|
|
|
|
|
|
|
for(const auto& devicePair : m_userDevices)
|
|
|
|
{
|
2023-11-14 17:42:31 -05:00
|
|
|
auto deviceStateNode = std::make_unique<Framework::Xml::CNode>(STATE_USERDEVICES_DEVICENODE, true);
|
2019-09-17 12:38:18 -04:00
|
|
|
deviceStateNode->InsertAttribute(Framework::Xml::CreateAttributeStringValue(STATE_USERDEVICES_DEVICENODE_NAMEATTRIBUTE, devicePair.first.c_str()));
|
|
|
|
deviceStateNode->InsertAttribute(Framework::Xml::CreateAttributeIntValue(STATE_USERDEVICES_DEVICENODE_DESCPTRATTRIBUTE, devicePair.second));
|
2023-11-14 17:42:31 -05:00
|
|
|
devicesStateNode->InsertNode(std::move(deviceStateNode));
|
2019-09-17 12:38:18 -04:00
|
|
|
}
|
|
|
|
|
2023-07-23 17:22:18 -04:00
|
|
|
archive.InsertFile(std::move(deviceStateFile));
|
2019-09-17 12:38:18 -04:00
|
|
|
}
|
|
|
|
|
2023-01-11 10:39:32 -05:00
|
|
|
void CIoman::SaveMountedDevicesState(Framework::CZipArchiveWriter& archive) const
|
|
|
|
{
|
2023-07-23 17:22:18 -04:00
|
|
|
auto deviceStateFile = std::make_unique<CXmlStateFile>(STATE_MOUNTEDDEVICES_FILENAME, STATE_MOUNTEDDEVICES_DEVICESNODE);
|
2023-01-11 10:39:32 -05:00
|
|
|
auto devicesStateNode = deviceStateFile->GetRoot();
|
|
|
|
|
|
|
|
for(const auto& devicePair : m_mountedDevices)
|
|
|
|
{
|
2023-11-14 17:42:31 -05:00
|
|
|
auto deviceStateNode = std::make_unique<Framework::Xml::CNode>(STATE_MOUNTEDDEVICES_DEVICENODE, true);
|
2023-01-11 10:39:32 -05:00
|
|
|
deviceStateNode->InsertAttribute(Framework::Xml::CreateAttributeStringValue(STATE_MOUNTEDDEVICES_DEVICENODE_NAMEATTRIBUTE, devicePair.first.c_str()));
|
|
|
|
deviceStateNode->InsertAttribute(Framework::Xml::CreateAttributeStringValue(STATE_MOUNTEDDEVICES_DEVICENODE_PATHATTRIBUTE, devicePair.second.c_str()));
|
2023-11-14 17:42:31 -05:00
|
|
|
devicesStateNode->InsertNode(std::move(deviceStateNode));
|
2023-01-11 10:39:32 -05:00
|
|
|
}
|
|
|
|
|
2023-07-23 17:22:18 -04:00
|
|
|
archive.InsertFile(std::move(deviceStateFile));
|
2023-01-11 10:39:32 -05:00
|
|
|
}
|
|
|
|
|
2019-09-17 12:38:18 -04:00
|
|
|
void CIoman::LoadFilesState(Framework::CZipArchiveReader& archive)
|
2019-02-06 20:19:22 -05:00
|
|
|
{
|
|
|
|
std::experimental::erase_if(m_files,
|
2019-02-11 18:45:16 -05:00
|
|
|
[](const FileMapType::value_type& filePair) {
|
|
|
|
return (filePair.first != FID_STDOUT) && (filePair.first != FID_STDERR);
|
|
|
|
});
|
2019-02-06 20:19:22 -05:00
|
|
|
|
|
|
|
auto fileStateFile = CXmlStateFile(*archive.BeginReadFile(STATE_FILES_FILENAME));
|
|
|
|
auto fileStateNode = fileStateFile.GetRoot();
|
|
|
|
|
2019-09-17 12:38:18 -04:00
|
|
|
int32 maxFileId = FID_STDERR;
|
2019-02-06 20:19:22 -05:00
|
|
|
auto fileNodes = fileStateNode->SelectNodes(STATE_FILES_FILESNODE "/" STATE_FILES_FILENODE);
|
|
|
|
for(auto fileNode : fileNodes)
|
|
|
|
{
|
2019-09-17 12:38:18 -04:00
|
|
|
int32 id = 0, flags = 0, descPtr = 0;
|
2023-11-28 10:57:52 -05:00
|
|
|
int64 position = 0;
|
2019-02-06 20:19:22 -05:00
|
|
|
std::string path;
|
|
|
|
if(!Framework::Xml::GetAttributeIntValue(fileNode, STATE_FILES_FILENODE_IDATTRIBUTE, &id)) break;
|
|
|
|
if(!Framework::Xml::GetAttributeStringValue(fileNode, STATE_FILES_FILENODE_PATHATTRIBUTE, &path)) break;
|
|
|
|
if(!Framework::Xml::GetAttributeIntValue(fileNode, STATE_FILES_FILENODE_FLAGSATTRIBUTE, &flags)) break;
|
2019-09-17 12:38:18 -04:00
|
|
|
if(!Framework::Xml::GetAttributeIntValue(fileNode, STATE_FILES_FILENODE_DESCPTRATTRIBUTE, &descPtr)) break;
|
2023-11-28 10:57:52 -05:00
|
|
|
if(!Framework::Xml::GetAttributeInt64Value(fileNode, STATE_FILES_FILENODE_POSITIONATTRIBUTE, &position)) break;
|
2019-02-06 20:19:22 -05:00
|
|
|
|
2019-09-17 12:38:18 -04:00
|
|
|
FileInfo fileInfo;
|
2019-02-06 20:19:22 -05:00
|
|
|
fileInfo.flags = flags;
|
|
|
|
fileInfo.path = path;
|
2019-09-17 12:38:18 -04:00
|
|
|
fileInfo.descPtr = descPtr;
|
|
|
|
fileInfo.stream = (descPtr == 0) ? OpenInternal(flags, path.c_str()) : nullptr;
|
2023-11-28 10:57:52 -05:00
|
|
|
fileInfo.stream->Seek(position, Framework::STREAM_SEEK_SET);
|
2019-02-06 20:19:22 -05:00
|
|
|
m_files[id] = std::move(fileInfo);
|
|
|
|
|
|
|
|
maxFileId = std::max(maxFileId, id);
|
|
|
|
}
|
|
|
|
m_nextFileHandle = maxFileId + 1;
|
|
|
|
}
|
2019-09-17 12:38:18 -04:00
|
|
|
|
|
|
|
void CIoman::LoadUserDevicesState(Framework::CZipArchiveReader& archive)
|
|
|
|
{
|
|
|
|
m_userDevices.clear();
|
|
|
|
|
|
|
|
auto deviceStateFile = CXmlStateFile(*archive.BeginReadFile(STATE_USERDEVICES_FILENAME));
|
|
|
|
auto deviceStateNode = deviceStateFile.GetRoot();
|
|
|
|
|
|
|
|
auto deviceNodes = deviceStateNode->SelectNodes(STATE_USERDEVICES_DEVICESNODE "/" STATE_USERDEVICES_DEVICENODE);
|
|
|
|
for(auto deviceNode : deviceNodes)
|
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
int32 descPtr = 0;
|
|
|
|
if(!Framework::Xml::GetAttributeStringValue(deviceNode, STATE_USERDEVICES_DEVICENODE_NAMEATTRIBUTE, &name)) break;
|
|
|
|
if(!Framework::Xml::GetAttributeIntValue(deviceNode, STATE_USERDEVICES_DEVICENODE_DESCPTRATTRIBUTE, &descPtr)) break;
|
|
|
|
|
|
|
|
m_userDevices[name] = descPtr;
|
|
|
|
}
|
|
|
|
}
|
2023-01-11 10:39:32 -05:00
|
|
|
|
|
|
|
void CIoman::LoadMountedDevicesState(Framework::CZipArchiveReader& archive)
|
|
|
|
{
|
|
|
|
std::experimental::erase_if(m_devices,
|
2023-01-12 16:27:14 -05:00
|
|
|
[this](const auto& devicePair) {
|
|
|
|
return (m_mountedDevices.find(devicePair.first) != std::end(m_mountedDevices));
|
|
|
|
});
|
2023-01-11 10:39:32 -05:00
|
|
|
m_mountedDevices.clear();
|
|
|
|
|
|
|
|
auto deviceStateFile = CXmlStateFile(*archive.BeginReadFile(STATE_MOUNTEDDEVICES_FILENAME));
|
|
|
|
auto deviceStateNode = deviceStateFile.GetRoot();
|
|
|
|
|
|
|
|
auto deviceNodes = deviceStateNode->SelectNodes(STATE_MOUNTEDDEVICES_DEVICESNODE "/" STATE_MOUNTEDDEVICES_DEVICENODE);
|
|
|
|
for(auto deviceNode : deviceNodes)
|
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
std::string path;
|
|
|
|
if(!Framework::Xml::GetAttributeStringValue(deviceNode, STATE_MOUNTEDDEVICES_DEVICENODE_NAMEATTRIBUTE, &name)) break;
|
|
|
|
if(!Framework::Xml::GetAttributeStringValue(deviceNode, STATE_MOUNTEDDEVICES_DEVICENODE_PATHATTRIBUTE, &path)) break;
|
2023-01-12 16:27:14 -05:00
|
|
|
|
2023-01-11 10:39:32 -05:00
|
|
|
Mount(name.c_str(), path.c_str());
|
|
|
|
}
|
|
|
|
}
|