IOS/ES: Implement DeleteTitleContent properly
Just like DeleteTitle, Using CNANDContentManager is overkill, inefficient and useless. And it results in a few failures in situations where a delete should just always work. But here it gets bonus points, because it manages to actually use the TMD for deleting contents, when IOS does none of that and just deletes files ending with .app in the title content directory. :)
This commit is contained in:
parent
12801fd722
commit
bacf52384f
|
@ -55,6 +55,8 @@ public:
|
||||||
ReturnCode Close(u32 fd) override;
|
ReturnCode Close(u32 fd) override;
|
||||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
||||||
|
|
||||||
|
ReturnCode DeleteTitleContent(u64 title_id) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
|
|
@ -376,20 +376,29 @@ IPCCommandResult ES::DeleteTicket(const IOCtlVRequest& request)
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return GetDefaultReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnCode ES::DeleteTitleContent(u64 title_id) const
|
||||||
|
{
|
||||||
|
if (!CanDeleteTitle(title_id))
|
||||||
|
return ES_EINVAL;
|
||||||
|
|
||||||
|
const std::string content_dir = Common::GetTitleContentPath(title_id, Common::FROM_SESSION_ROOT);
|
||||||
|
if (!File::IsDirectory(content_dir))
|
||||||
|
return FS_ENOENT;
|
||||||
|
|
||||||
|
for (const auto& file : File::ScanDirectoryTree(content_dir, false).children)
|
||||||
|
{
|
||||||
|
if (file.virtualName.size() == 12 && file.virtualName.compare(8, 4, ".app") == 0)
|
||||||
|
File::Delete(file.physicalName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IPC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
IPCCommandResult ES::DeleteTitleContent(const IOCtlVRequest& request)
|
IPCCommandResult ES::DeleteTitleContent(const IOCtlVRequest& request)
|
||||||
{
|
{
|
||||||
if (!request.HasNumberOfValidVectors(1, 0))
|
if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(u64))
|
||||||
return GetDefaultReply(ES_EINVAL);
|
return GetDefaultReply(ES_EINVAL);
|
||||||
|
return GetDefaultReply(DeleteTitleContent(Memory::Read_U64(request.in_vectors[0].address)));
|
||||||
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
|
|
||||||
INFO_LOG(IOS_ES, "IOCTL_ES_DELETETITLECONTENT: title: %08x/%08x", (u32)(TitleID >> 32),
|
|
||||||
(u32)TitleID);
|
|
||||||
|
|
||||||
// Presumably return -1017 when title not installed TODO verify
|
|
||||||
if (!DiscIO::CNANDContentManager::Access().RemoveTitle(TitleID, Common::FROM_SESSION_ROOT))
|
|
||||||
return GetDefaultReply(ES_EINVAL);
|
|
||||||
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IPCCommandResult ES::ExportTitleInit(Context& context, const IOCtlVRequest& request)
|
IPCCommandResult ES::ExportTitleInit(Context& context, const IOCtlVRequest& request)
|
||||||
|
|
|
@ -241,40 +241,11 @@ const CNANDContentLoader& CNANDContentManager::GetNANDLoader(u64 title_id,
|
||||||
return GetNANDLoader(path);
|
return GetNANDLoader(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CNANDContentManager::RemoveTitle(u64 title_id, Common::FromWhichRoot from)
|
|
||||||
{
|
|
||||||
auto& loader = GetNANDLoader(title_id, from);
|
|
||||||
if (!loader.IsValid())
|
|
||||||
return false;
|
|
||||||
loader.RemoveTitle();
|
|
||||||
return GetNANDLoader(title_id, from).IsValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CNANDContentManager::ClearCache()
|
void CNANDContentManager::ClearCache()
|
||||||
{
|
{
|
||||||
m_map.clear();
|
m_map.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNANDContentLoader::RemoveTitle() const
|
|
||||||
{
|
|
||||||
const u64 title_id = m_tmd.GetTitleId();
|
|
||||||
INFO_LOG(DISCIO, "RemoveTitle %016" PRIx64, title_id);
|
|
||||||
if (IsValid())
|
|
||||||
{
|
|
||||||
// remove TMD?
|
|
||||||
for (const auto& content : m_Content)
|
|
||||||
{
|
|
||||||
if (!content.m_metadata.IsShared())
|
|
||||||
{
|
|
||||||
std::string path = StringFromFormat("%s/%08x.app", m_Path.c_str(), content.m_metadata.id);
|
|
||||||
INFO_LOG(DISCIO, "Delete %s", path.c_str());
|
|
||||||
File::Delete(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CNANDContentManager::Access().ClearCache(); // deletes 'this'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 CNANDContentManager::Install_WiiWAD(const std::string& filename)
|
u64 CNANDContentManager::Install_WiiWAD(const std::string& filename)
|
||||||
{
|
{
|
||||||
if (filename.find(".wad") == std::string::npos)
|
if (filename.find(".wad") == std::string::npos)
|
||||||
|
|
|
@ -79,7 +79,6 @@ public:
|
||||||
~CNANDContentLoader();
|
~CNANDContentLoader();
|
||||||
|
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
void RemoveTitle() const;
|
|
||||||
const SNANDContent* GetContentByID(u32 id) const;
|
const SNANDContent* GetContentByID(u32 id) const;
|
||||||
const SNANDContent* GetContentByIndex(int index) const;
|
const SNANDContent* GetContentByIndex(int index) const;
|
||||||
const IOS::ES::TMDReader& GetTMD() const { return m_tmd; }
|
const IOS::ES::TMDReader& GetTMD() const { return m_tmd; }
|
||||||
|
@ -111,7 +110,6 @@ public:
|
||||||
|
|
||||||
const CNANDContentLoader& GetNANDLoader(const std::string& content_path);
|
const CNANDContentLoader& GetNANDLoader(const std::string& content_path);
|
||||||
const CNANDContentLoader& GetNANDLoader(u64 title_id, Common::FromWhichRoot from);
|
const CNANDContentLoader& GetNANDLoader(u64 title_id, Common::FromWhichRoot from);
|
||||||
bool RemoveTitle(u64 title_id, Common::FromWhichRoot from);
|
|
||||||
void ClearCache();
|
void ClearCache();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include "Common/NandPaths.h"
|
#include "Common/NandPaths.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/HW/WiiSaveCrypted.h"
|
#include "Core/HW/WiiSaveCrypted.h"
|
||||||
|
#include "Core/IOS/ES/ES.h"
|
||||||
|
#include "Core/IOS/IOS.h"
|
||||||
#include "DiscIO/Blob.h"
|
#include "DiscIO/Blob.h"
|
||||||
#include "DiscIO/Enums.h"
|
#include "DiscIO/Enums.h"
|
||||||
#include "DiscIO/NANDContentLoader.h"
|
#include "DiscIO/NANDContentLoader.h"
|
||||||
|
@ -324,9 +326,8 @@ bool GameFile::Install()
|
||||||
bool GameFile::Uninstall()
|
bool GameFile::Uninstall()
|
||||||
{
|
{
|
||||||
_assert_(m_platform == DiscIO::Platform::WII_WAD);
|
_assert_(m_platform == DiscIO::Platform::WII_WAD);
|
||||||
|
IOS::HLE::Kernel ios;
|
||||||
return DiscIO::CNANDContentManager::Access().RemoveTitle(m_title_id,
|
return ios.GetES()->DeleteTitleContent(m_title_id) == IOS::HLE::IPC_SUCCESS;
|
||||||
Common::FROM_CONFIGURED_ROOT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameFile::ExportWiiSave()
|
bool GameFile::ExportWiiSave()
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "Core/HW/Wiimote.h"
|
#include "Core/HW/Wiimote.h"
|
||||||
#include "Core/Host.h"
|
#include "Core/Host.h"
|
||||||
#include "Core/HotkeyManager.h"
|
#include "Core/HotkeyManager.h"
|
||||||
|
#include "Core/IOS/ES/ES.h"
|
||||||
#include "Core/IOS/IOS.h"
|
#include "Core/IOS/IOS.h"
|
||||||
#include "Core/IOS/STM/STM.h"
|
#include "Core/IOS/STM/STM.h"
|
||||||
#include "Core/IOS/USB/Bluetooth/BTEmu.h"
|
#include "Core/IOS/USB/Bluetooth/BTEmu.h"
|
||||||
|
@ -1228,7 +1229,8 @@ void CFrame::OnUninstallWAD(wxCommandEvent&)
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 title_id = file->GetTitleID();
|
u64 title_id = file->GetTitleID();
|
||||||
if (!DiscIO::CNANDContentManager::Access().RemoveTitle(title_id, Common::FROM_CONFIGURED_ROOT))
|
IOS::HLE::Kernel ios;
|
||||||
|
if (ios.GetES()->DeleteTitleContent(title_id) < 0)
|
||||||
{
|
{
|
||||||
PanicAlertT("Failed to remove this title from the NAND.");
|
PanicAlertT("Failed to remove this title from the NAND.");
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in New Issue