Merge pull request #5930 from delroth/wfs

Fix Dragon Quest X offline mode on Dolphin
This commit is contained in:
Pierre Bourdon 2017-08-15 22:40:56 +02:00 committed by GitHub
commit 9b79e0ac72
15 changed files with 396 additions and 25 deletions

View File

@ -58,6 +58,35 @@ std::string GetTMDFileName(u64 _titleID, FromWhichRoot from)
return GetTitleContentPath(_titleID, from) + "title.tmd";
}
bool IsTitlePath(const std::string& path, FromWhichRoot from, u64* title_id)
{
std::string expected_prefix = RootUserPath(from) + "/title/";
if (!StringBeginsWith(path, expected_prefix))
{
return false;
}
// Try to find a title ID in the remaining path.
std::string subdirectory = path.substr(expected_prefix.size());
std::vector<std::string> components = SplitString(subdirectory, '/');
if (components.size() < 2)
{
return false;
}
u32 title_id_high, title_id_low;
if (!AsciiToHex(components[0], title_id_high) || !AsciiToHex(components[1], title_id_low))
{
return false;
}
if (title_id != nullptr)
{
*title_id = (static_cast<u64>(title_id_high) << 32) | title_id_low;
}
return true;
}
std::string EscapeFileName(const std::string& filename)
{
// Prevent paths from containing special names like ., .., ..., ...., and so on

View File

@ -29,6 +29,9 @@ std::string GetTitleDataPath(u64 _titleID, FromWhichRoot from);
std::string GetTitleContentPath(u64 _titleID, FromWhichRoot from);
std::string GetTMDFileName(u64 _titleID, FromWhichRoot from);
// Returns whether a path is within an installed title's directory.
bool IsTitlePath(const std::string& path, FromWhichRoot from, u64* title_id = nullptr);
// Escapes characters that are invalid or have special meanings in the host file system
std::string EscapeFileName(const std::string& filename);
// Escapes characters that are invalid or have special meanings in the host file system

View File

@ -186,6 +186,7 @@ set(SRCS
IOS/USB/OH0/OH0.cpp
IOS/USB/OH0/OH0Device.cpp
IOS/USB/USB_HID/HIDv4.cpp
IOS/USB/USB_HID/HIDv5.cpp
IOS/USB/USB_VEN/VEN.cpp
IOS/USB/USBV0.cpp
IOS/USB/USBV4.cpp

View File

@ -221,6 +221,7 @@
<ClCompile Include="IOS\USB\OH0\OH0.cpp" />
<ClCompile Include="IOS\USB\OH0\OH0Device.cpp" />
<ClCompile Include="IOS\USB\USB_HID\HIDv4.cpp" />
<ClCompile Include="IOS\USB\USB_HID\HIDv5.cpp" />
<ClCompile Include="IOS\USB\USB_VEN\VEN.cpp" />
<ClCompile Include="IOS\USB\USBV0.cpp" />
<ClCompile Include="IOS\USB\USBV4.cpp" />
@ -468,6 +469,7 @@
<ClInclude Include="IOS\USB\OH0\OH0.h" />
<ClInclude Include="IOS\USB\OH0\OH0Device.h" />
<ClInclude Include="IOS\USB\USB_HID\HIDv4.h" />
<ClInclude Include="IOS\USB\USB_HID\HIDv5.h" />
<ClInclude Include="IOS\USB\USB_VEN\VEN.h" />
<ClInclude Include="IOS\USB\USBV0.h" />
<ClInclude Include="IOS\USB\USBV4.h" />

View File

@ -826,6 +826,9 @@
<ClCompile Include="IOS\USB\USB_HID\HIDv4.cpp">
<Filter>IOS\USB</Filter>
</ClCompile>
<ClCompile Include="IOS\USB\USB_HID\HIDv5.cpp">
<Filter>IOS\USB</Filter>
</ClCompile>
<ClCompile Include="IOS\USB\USB_VEN\VEN.cpp">
<Filter>IOS\USB</Filter>
</ClCompile>
@ -1469,6 +1472,9 @@
<ClInclude Include="IOS\USB\USB_HID\HIDv4.h">
<Filter>IOS\USB</Filter>
</ClInclude>
<ClInclude Include="IOS\USB\USB_HID\HIDv5.h">
<Filter>IOS\USB</Filter>
</ClInclude>
<ClInclude Include="IOS\USB\USB_VEN\VEN.h">
<Filter>IOS\USB</Filter>
</ClInclude>

View File

@ -165,15 +165,24 @@ IPCCommandResult ES::GetTitleDirectory(const IOCtlVRequest& request)
return GetDefaultReply(IPC_SUCCESS);
}
IPCCommandResult ES::GetTitleID(const IOCtlVRequest& request)
ReturnCode ES::GetTitleId(u64* title_id) const
{
if (!s_title_context.active)
return ES_EINVAL;
*title_id = s_title_context.tmd.GetTitleId();
return IPC_SUCCESS;
}
IPCCommandResult ES::GetTitleId(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1))
return GetDefaultReply(ES_EINVAL);
if (!s_title_context.active)
return GetDefaultReply(ES_EINVAL);
u64 title_id;
const ReturnCode ret = GetTitleId(&title_id);
if (ret != IPC_SUCCESS)
return GetDefaultReply(ret);
const u64 title_id = s_title_context.tmd.GetTitleId();
Memory::Write_U64(title_id, request.io_vectors[0].address);
INFO_LOG(IOS_ES, "IOCTL_ES_GETTITLEID: %08x/%08x", static_cast<u32>(title_id >> 32),
static_cast<u32>(title_id));
@ -421,7 +430,7 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
case IOCTL_ES_GETTITLEDIR:
return GetTitleDirectory(request);
case IOCTL_ES_GETTITLEID:
return GetTitleID(request);
return GetTitleId(request);
case IOCTL_ES_SETUID:
return SetUID(context->uid, request);
case IOCTL_ES_DIVERIFY:

View File

@ -127,6 +127,7 @@ public:
ReturnCode DeleteContent(u64 title_id, u32 content_id) const;
ReturnCode GetDeviceId(u32* device_id) const;
ReturnCode GetTitleId(u64* device_id) const;
// Views
ReturnCode GetV0TicketFromView(const u8* ticket_view, u8* ticket) const;
@ -243,7 +244,7 @@ private:
// Misc
IPCCommandResult SetUID(u32 uid, const IOCtlVRequest& request);
IPCCommandResult GetTitleDirectory(const IOCtlVRequest& request);
IPCCommandResult GetTitleID(const IOCtlVRequest& request);
IPCCommandResult GetTitleId(const IOCtlVRequest& request);
IPCCommandResult GetConsumption(const IOCtlVRequest& request);
IPCCommandResult Launch(const IOCtlVRequest& request);
IPCCommandResult LaunchBC(const IOCtlVRequest& request);

View File

@ -21,6 +21,8 @@
#include "Common/NandPaths.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/SystemTimers.h"
#include "Core/IOS/ES/ES.h"
#include "Core/IOS/ES/Formats.h"
#include "Core/IOS/FS/FileIO.h"
namespace IOS
@ -326,6 +328,18 @@ IPCCommandResult FS::GetAttribute(const IOCtlRequest& request)
u8 OtherPerm = 0x3; // read/write
u8 Attributes = 0x00; // no attributes
// Hack: if the path that is being accessed is within an installed title directory, get the
// UID/GID from the installed title TMD.
u64 title_id;
if (IsTitlePath(Filename, Common::FROM_SESSION_ROOT, &title_id))
{
IOS::ES::TMDReader tmd = GetIOS()->GetES()->FindInstalledTMD(title_id);
if (tmd.IsValid())
{
GroupID = tmd.GetGroupId();
}
}
if (File::IsDirectory(Filename))
{
INFO_LOG(IOS_FILEIO, "FS: GET_ATTR Directory %s - all permission flags are set",

View File

@ -47,6 +47,7 @@
#include "Core/IOS/USB/OH0/OH0.h"
#include "Core/IOS/USB/OH0/OH0Device.h"
#include "Core/IOS/USB/USB_HID/HIDv4.h"
#include "Core/IOS/USB/USB_HID/HIDv5.h"
#include "Core/IOS/USB/USB_KBD.h"
#include "Core/IOS/USB/USB_VEN/VEN.h"
#include "Core/IOS/WFS/WFSI.h"
@ -361,7 +362,10 @@ void Kernel::AddStaticDevices()
AddDevice(std::make_unique<Device::USB_KBD>(*this, "/dev/usb/kbd"));
AddDevice(std::make_unique<Device::SDIOSlot0>(*this, "/dev/sdio/slot0"));
AddDevice(std::make_unique<Device::Stub>(*this, "/dev/sdio/slot1"));
AddDevice(std::make_unique<Device::USB_HIDv4>(*this, "/dev/usb/hid"));
if (GetVersion() == 59)
AddDevice(std::make_unique<Device::USB_HIDv5>(*this, "/dev/usb/hid"));
else
AddDevice(std::make_unique<Device::USB_HIDv4>(*this, "/dev/usb/hid"));
AddDevice(std::make_unique<Device::OH0>(*this, "/dev/usb/oh0"));
AddDevice(std::make_unique<Device::Stub>(*this, "/dev/usb/oh1"));
AddDevice(std::make_unique<Device::USB_VEN>(*this, "/dev/usb/ven"));

View File

@ -0,0 +1,63 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/IOS/USB/USB_HID/HIDv5.h"
#include <string>
#include "Core/HW/Memmap.h"
#include "Core/IOS/Device.h"
#include "Core/IOS/USB/Common.h"
#include "Core/IOS/USB/USBV5.h"
namespace IOS
{
namespace HLE
{
namespace Device
{
USB_HIDv5::USB_HIDv5(Kernel& ios, const std::string& device_name) : USBHost(ios, device_name)
{
}
USB_HIDv5::~USB_HIDv5()
{
StopThreads();
}
IPCCommandResult USB_HIDv5::IOCtl(const IOCtlRequest& request)
{
request.Log(GetDeviceName(), LogTypes::IOS_USB);
switch (request.request)
{
case USB::IOCTL_USBV5_GETVERSION:
Memory::Write_U32(VERSION, request.buffer_out);
return GetDefaultReply(IPC_SUCCESS);
case USB::IOCTL_USBV5_SHUTDOWN:
if (m_hanging_request)
{
IOCtlRequest hanging_request{m_hanging_request};
m_ios.EnqueueIPCReply(hanging_request, IPC_SUCCESS);
}
return GetDefaultReply(IPC_SUCCESS);
case USB::IOCTL_USBV5_GETDEVICECHANGE:
if (m_devicechange_replied)
{
m_hanging_request = request.address;
return GetNoReply();
}
else
{
m_devicechange_replied = true;
return GetDefaultReply(IPC_SUCCESS);
}
default:
request.DumpUnknown(GetDeviceName(), LogTypes::IOS_USB);
return GetDefaultReply(IPC_SUCCESS);
}
}
} // namespace Device
} // namespace HLE
} // namespace IOS

View File

@ -0,0 +1,37 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <string>
#include "Common/CommonTypes.h"
#include "Core/IOS/IOS.h"
#include "Core/IOS/USB/Host.h"
namespace IOS
{
namespace HLE
{
namespace Device
{
// Stub implementation that only gets DQX to boot.
class USB_HIDv5 : public USBHost
{
public:
USB_HIDv5(Kernel& ios, const std::string& device_name);
~USB_HIDv5() override;
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
private:
static constexpr u32 VERSION = 0x50001;
u32 m_hanging_request = 0;
bool m_devicechange_replied = false;
};
} // namespace Device
} // namespace HLE
} // namespace IOS

View File

@ -15,6 +15,7 @@
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Core/HW/Memmap.h"
#include "Core/IOS/ES/ES.h"
#include "Core/IOS/ES/Formats.h"
#include "Core/IOS/WFS/WFSSRV.h"
#include "DiscIO/NANDContentLoader.h"
@ -101,7 +102,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
constexpr u32 MAX_TMD_SIZE = 0x4000;
if (tmd_size > MAX_TMD_SIZE)
{
ERROR_LOG(IOS, "IOCTL_WFSI_INIT: TMD size too large (%d)", tmd_size);
ERROR_LOG(IOS, "IOCTL_WFSI_PREPARE_DEVICE: TMD size too large (%d)", tmd_size);
return_error_code = IPC_EINVAL;
break;
}
@ -215,9 +216,23 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
break;
case IOCTL_WFSI_INIT:
// Nothing to do.
{
INFO_LOG(IOS, "IOCTL_WFSI_INIT");
if (GetIOS()->GetES()->GetTitleId(&m_title_id) < 0)
{
ERROR_LOG(IOS, "IOCTL_WFSI_INIT: Could not get title id.");
return_error_code = IPC_EINVAL;
break;
}
m_title_id_str = StringFromFormat(
"%c%c%c%c", static_cast<char>(m_title_id >> 24), static_cast<char>(m_title_id >> 16),
static_cast<char>(m_title_id >> 8), static_cast<char>(m_title_id));
IOS::ES::TMDReader tmd = GetIOS()->GetES()->FindInstalledTMD(m_title_id);
m_group_id = tmd.GetGroupId();
m_group_id_str = StringFromFormat("%c%c", m_group_id >> 8, m_group_id & 0xFF);
break;
}
case IOCTL_WFSI_SET_DEVICE_NAME:
INFO_LOG(IOS, "IOCTL_WFSI_SET_DEVICE_NAME");
@ -227,14 +242,55 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
case IOCTL_WFSI_APPLY_TITLE_PROFILE:
INFO_LOG(IOS, "IOCTL_WFSI_APPLY_TITLE_PROFILE");
m_base_extract_path = StringFromFormat(
"/vol/%s/_install/%c%c%c%c/content", m_device_name.c_str(),
static_cast<char>(m_tmd.GetTitleId() >> 24), static_cast<char>(m_tmd.GetTitleId() >> 16),
static_cast<char>(m_tmd.GetTitleId() >> 8), static_cast<char>(m_tmd.GetTitleId()));
m_base_extract_path = StringFromFormat("/vol/%s/_install/%s/content", m_device_name.c_str(),
m_title_id_str.c_str());
File::CreateFullPath(WFS::NativePath(m_base_extract_path));
break;
case IOCTL_WFSI_LOAD_DOL:
{
std::string path = StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(),
m_group_id_str.c_str(), m_title_id_str.c_str());
u32 dol_addr = Memory::Read_U32(request.buffer_in + 0x18);
u32 max_dol_size = Memory::Read_U32(request.buffer_in + 0x14);
u16 dol_extension_id = Memory::Read_U16(request.buffer_in + 0x1e);
if (dol_extension_id == 0)
{
path += "/default.dol";
}
else
{
path += StringFromFormat("/extension%d.dol", dol_extension_id);
}
INFO_LOG(IOS, "IOCTL_WFSI_LOAD_DOL: loading %s at address %08x (size %d)", path.c_str(),
dol_addr, max_dol_size);
File::IOFile fp(WFS::NativePath(path), "rb");
if (!fp)
{
WARN_LOG(IOS, "IOCTL_WFSI_LOAD_DOL: no such file or directory: %s", path.c_str());
return_error_code = WFSI_ENOENT;
break;
}
u32 real_dol_size = fp.GetSize();
if (dol_addr == 0)
{
// Write the expected size to the size parameter, in the input.
Memory::Write_U32(real_dol_size, request.buffer_in + 0x14);
}
else
{
fp.ReadBytes(Memory::GetPointer(dol_addr), max_dol_size);
}
Memory::Write_U32(real_dol_size, request.buffer_out);
break;
}
default:
// TODO(wfs): Should be returning an error. However until we have
// everything properly stubbed it's easier to simulate the methods

View File

@ -52,9 +52,18 @@ private:
IOS::ES::TMDReader m_tmd;
std::string m_base_extract_path;
u64 m_title_id;
std::string m_title_id_str;
u16 m_group_id;
std::string m_group_id_str;
ARCUnpacker m_arc_unpacker;
enum
{
WFSI_ENOENT = -12000,
};
enum
{
IOCTL_WFSI_PREPARE_DEVICE = 0x02,
@ -74,6 +83,8 @@ private:
IOCTL_WFSI_FINALIZE_PROFILE = 0x88,
IOCTL_WFSI_APPLY_TITLE_PROFILE = 0x89,
IOCTL_WFSI_LOAD_DOL = 0x90,
};
};
} // namespace Device

View File

@ -4,6 +4,7 @@
#include "Core/IOS/WFS/WFSSRV.h"
#include <cinttypes>
#include <string>
#include <vector>
@ -44,6 +45,27 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
INFO_LOG(IOS, "IOCTL_WFS_INIT");
break;
case IOCTL_WFS_UNKNOWN_8:
// TODO(wfs): Figure out what this actually does.
INFO_LOG(IOS, "IOCTL_WFS_UNKNOWN_8");
Memory::Write_U8(7, request.buffer_out);
Memory::CopyToEmu(request.buffer_out + 1, "msc01\x00\x00\x00", 8);
break;
case IOCTL_WFS_SHUTDOWN:
INFO_LOG(IOS, "IOCTL_WFS_SHUTDOWN");
// Close all hanging attach/detach ioctls with an appropriate error code.
for (auto address : m_hanging)
{
IOCtlRequest hanging_request{address};
Memory::Write_U32(0x80000000, hanging_request.buffer_out);
Memory::Write_U32(0, hanging_request.buffer_out + 4);
Memory::Write_U32(0, hanging_request.buffer_out + 8);
m_ios.EnqueueIPCReply(hanging_request, 0);
}
break;
case IOCTL_WFS_DEVICE_INFO:
INFO_LOG(IOS, "IOCTL_WFS_DEVICE_INFO");
Memory::Write_U64(16ull << 30, request.buffer_out); // 16GB storage.
@ -68,11 +90,16 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
case IOCTL_WFS_ATTACH_DETACH:
INFO_LOG(IOS, "IOCTL_WFS_ATTACH_DETACH(%u)", request.request);
Memory::Write_U32(1, request.buffer_out);
Memory::Write_U32(0, request.buffer_out + 4);
Memory::Write_U32(0, request.buffer_out + 8);
// Leave hanging, but we need to acknowledge the request at shutdown time.
m_hanging.push_back(request.address);
return GetNoReply();
case IOCTL_WFS_FLUSH:
// Nothing to do.
INFO_LOG(IOS, "IOCTL_WFS_FLUSH: doing nothing");
break;
// TODO(wfs): Globbing is not really implemented, we just fake the one case
// (listing /vol/*) which is required to get the installer to work.
case IOCTL_WFS_GLOB_START:
@ -83,7 +110,7 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
case IOCTL_WFS_GLOB_NEXT:
INFO_LOG(IOS, "IOCTL_WFS_GLOB_NEXT(%u)", request.request);
return_error_code = WFS_EEMPTY;
return_error_code = WFS_ENOENT;
break;
case IOCTL_WFS_GLOB_END:
@ -91,12 +118,32 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
Memory::Memset(request.buffer_out, 0, request.buffer_out_size);
break;
case IOCTL_WFS_SET_HOMEDIR:
m_home_directory =
Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in));
INFO_LOG(IOS, "IOCTL_WFS_SET_HOMEDIR: %s", m_home_directory.c_str());
break;
case IOCTL_WFS_CHDIR:
m_current_directory =
Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in));
INFO_LOG(IOS, "IOCTL_WFS_CHDIR: %s", m_current_directory.c_str());
break;
case IOCTL_WFS_GET_HOMEDIR:
INFO_LOG(IOS, "IOCTL_WFS_GET_HOMEDIR: %s", m_home_directory.c_str());
Memory::Write_U16(static_cast<u16>(m_home_directory.size()), request.buffer_out);
Memory::CopyToEmu(request.buffer_out + 2, m_home_directory.data(), m_home_directory.size());
break;
case IOCTL_WFS_OPEN:
{
u32 mode = Memory::Read_U32(request.buffer_in);
u16 path_len = Memory::Read_U16(request.buffer_in + 0x20);
std::string path = Memory::GetString(request.buffer_in + 0x22, path_len);
path = NormalizePath(path);
u16 fd = GetNewFileDescriptor();
FileDescriptor* fd_obj = &m_fds[fd];
fd_obj->in_use = true;
@ -108,7 +155,7 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
{
ERROR_LOG(IOS, "IOCTL_WFS_OPEN(%s, %d): error opening file", path.c_str(), mode);
ReleaseFileDescriptor(fd);
return_error_code = -1; // TODO(wfs): proper error code.
return_error_code = WFS_ENOENT;
break;
}
@ -117,6 +164,28 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
break;
}
case IOCTL_WFS_GET_SIZE:
{
u16 fd = Memory::Read_U16(request.buffer_in);
FileDescriptor* fd_obj = FindFileDescriptor(fd);
if (fd_obj == nullptr)
{
ERROR_LOG(IOS, "IOCTL_WFS_GET_SIZE: invalid file descriptor %d", fd);
return_error_code = WFS_EBADFD;
break;
}
u64 size = fd_obj->file.GetSize();
u32 truncated_size = static_cast<u32>(size);
INFO_LOG(IOS, "IOCTL_WFS_GET_SIZE(%d) -> %d", fd, truncated_size);
if (size != truncated_size)
{
ERROR_LOG(IOS, "IOCTL_WFS_GET_SIZE: file %d too large (%" PRIu64 ")", fd, size);
}
Memory::Write_U32(truncated_size, request.buffer_out);
break;
}
case IOCTL_WFS_CLOSE:
{
u16 fd = Memory::Read_U16(request.buffer_in + 0x4);
@ -126,26 +195,39 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
}
case IOCTL_WFS_READ:
case IOCTL_WFS_READ_ABSOLUTE:
{
u32 addr = Memory::Read_U32(request.buffer_in);
u32 position = Memory::Read_U32(request.buffer_in + 4); // Only for absolute.
u16 fd = Memory::Read_U16(request.buffer_in + 0xC);
u32 size = Memory::Read_U32(request.buffer_in + 8);
bool absolute = request.request == IOCTL_WFS_READ_ABSOLUTE;
FileDescriptor* fd_obj = FindFileDescriptor(fd);
if (fd_obj == nullptr)
{
ERROR_LOG(IOS, "IOCTL_WFS_READ: invalid file descriptor %d", fd);
return_error_code = -1; // TODO(wfs): proper error code.
return_error_code = WFS_EBADFD;
break;
}
size_t read_bytes;
if (!fd_obj->file.ReadArray(Memory::GetPointer(addr), size, &read_bytes))
u64 previous_position = fd_obj->file.Tell();
if (absolute)
{
return_error_code = -1; // TODO(wfs): proper error code.
break;
fd_obj->file.Seek(position, SEEK_SET);
}
size_t read_bytes;
fd_obj->file.ReadArray(Memory::GetPointer(addr), size, &read_bytes);
// TODO(wfs): Handle read errors.
if (absolute)
{
fd_obj->file.Seek(previous_position, SEEK_SET);
}
else
{
fd_obj->position += read_bytes;
}
fd_obj->position += read_bytes;
INFO_LOG(IOS, "IOCTL_WFS_READ: read %zd bytes from FD %d (%s)", read_bytes, fd,
fd_obj->path.c_str());
@ -164,6 +246,42 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
return GetDefaultReply(return_error_code);
}
std::string WFSSRV::NormalizePath(const std::string& path) const
{
std::string expanded;
if (!path.empty() && path[0] == '~')
{
expanded = m_home_directory + "/" + path.substr(1);
}
else if (path.empty() || path[0] != '/')
{
expanded = m_current_directory + "/" + path;
}
else
{
expanded = path;
}
std::vector<std::string> components = SplitString(expanded, '/');
std::vector<std::string> normalized_components;
for (const auto& component : components)
{
if (component.empty() || component == ".")
{
continue;
}
else if (component == ".." && !normalized_components.empty())
{
normalized_components.pop_back();
}
else
{
normalized_components.push_back(component);
}
}
return "/" + JoinStrings(normalized_components, "/");
}
WFSSRV::FileDescriptor* WFSSRV::FindFileDescriptor(u16 fd)
{
if (fd >= m_fds.size() || !m_fds[fd].in_use)

View File

@ -35,12 +35,22 @@ private:
// WFS device name, e.g. msc01/msc02.
std::string m_device_name;
// Home / current directories.
std::string m_home_directory;
std::string m_current_directory;
std::string NormalizePath(const std::string& path) const;
enum
{
IOCTL_WFS_INIT = 0x02,
IOCTL_WFS_SHUTDOWN = 0x03,
IOCTL_WFS_DEVICE_INFO = 0x04,
IOCTL_WFS_GET_DEVICE_NAME = 0x05,
IOCTL_WFS_UNMOUNT_VOLUME = 0x06,
IOCTL_WFS_UNKNOWN_8 = 0x08,
IOCTL_WFS_FLUSH = 0x0a,
IOCTL_WFS_MKDIR = 0x0c,
IOCTL_WFS_GLOB_START = 0x0d,
IOCTL_WFS_GLOB_NEXT = 0x0e,
IOCTL_WFS_GLOB_END = 0x0f,
@ -51,16 +61,19 @@ private:
IOCTL_WFS_DELETE = 0x15,
IOCTL_WFS_GET_ATTRIBUTES = 0x17,
IOCTL_WFS_OPEN = 0x1A,
IOCTL_WFS_GET_SIZE = 0x1B,
IOCTL_WFS_CLOSE = 0x1E,
IOCTL_WFS_READ = 0x20,
IOCTL_WFS_WRITE = 0x22,
IOCTL_WFS_ATTACH_DETACH = 0x2d,
IOCTL_WFS_ATTACH_DETACH_2 = 0x2e,
IOCTL_WFS_READ_ABSOLUTE = 0x48,
};
enum
{
WFS_EEMPTY = -10028, // Directory is empty of iteration completed.
WFS_EBADFD = -10026, // Invalid file descriptor.
WFS_ENOENT = -10028, // No such file or directory.
};
struct FileDescriptor
@ -78,6 +91,10 @@ private:
FileDescriptor* FindFileDescriptor(u16 fd);
u16 GetNewFileDescriptor();
void ReleaseFileDescriptor(u16 fd);
// List of addresses of IPC requests left hanging that need closing at
// shutdown time.
std::vector<u32> m_hanging;
};
} // namespace Device
} // namespace HLE