mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 11:26:56 +02:00
Support mountable-content DLC (addcont with real content) (#1581)
Support mountable-content DLC (addcont) and fix PlayGo chunk count query
This commit is contained in:
@@ -25,6 +25,9 @@
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <atomic>
|
||||
#include <cinttypes>
|
||||
#include <iterator>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
@@ -176,6 +179,14 @@ static int GetHostPathStat(const std::filesystem::path& host_path, LibKernel::Fi
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Mounts can appear after a failed lookup (e.g. additional content), so forget negative results.
|
||||
void InvalidateFailedResolves() {
|
||||
std::scoped_lock lock(g_mutex);
|
||||
for (auto it = g_resolved_paths.begin(); it != g_resolved_paths.end();) {
|
||||
it = it->second.result != OK ? g_resolved_paths.erase(it) : std::next(it);
|
||||
}
|
||||
}
|
||||
|
||||
static int ResolveOnePath(const char* guest_path, uint32_t* id, uint64_t* size) {
|
||||
if (guest_path == nullptr || guest_path[0] == '\0') {
|
||||
return LibKernel::KERNEL_ERROR_EINVAL;
|
||||
@@ -225,6 +236,10 @@ static int ResolveOnePath(const char* guest_path, uint32_t* id, uint64_t* size)
|
||||
log_missing = true;
|
||||
}
|
||||
}
|
||||
if (!log_missing && info.result == OK && path.starts_with("/addcont")) {
|
||||
LOGF("\tAPR resolve: %s -> %s (%" PRIu64 " bytes)\n", guest_path,
|
||||
Common::PathToString(info.host_path).c_str(), info.file_size);
|
||||
}
|
||||
if (log_missing) {
|
||||
LOGF("\tAPR resolve missing path: %s -> %s\n", guest_path, Common::PathToString(info.host_path).c_str());
|
||||
}
|
||||
@@ -1181,6 +1196,13 @@ static int ExecuteCommand(const CommandBufferState::Command& entry) {
|
||||
uint64_t bytes_read = 0;
|
||||
auto result = ReadHostFileToGuest(host_path, command.file_offset, command.destination,
|
||||
command.size, &bytes_read);
|
||||
static std::atomic<uint32_t> s_logged_dlc_reads {0};
|
||||
if (host_path.filename() == "re_dlc_000.pak" && s_logged_dlc_reads.fetch_add(1) < 32) {
|
||||
LOGF("\tAPR read dlc: id=0x%08" PRIx32 ", offset=0x%016" PRIx64 ", size=0x%016" PRIx64
|
||||
", read=0x%016" PRIx64 ", result=0x%08" PRIx32 "\n",
|
||||
command.file_id, command.file_offset, command.size, bytes_read,
|
||||
static_cast<uint32_t>(result));
|
||||
}
|
||||
if (result != OK) {
|
||||
LOGF("\tAPR submit read failed: id=0x%08" PRIx32 ", result=0x%08" PRIx32 ", path=%s\n",
|
||||
command.file_id, static_cast<uint32_t>(result), Common::PathToString(host_path).c_str());
|
||||
|
||||
@@ -22,13 +22,16 @@
|
||||
|
||||
namespace Libs {
|
||||
|
||||
namespace AprShared {
|
||||
void InvalidateFailedResolves();
|
||||
}
|
||||
|
||||
LIB_VERSION("AppContent", 1, "AppContentUtil", 1, 1);
|
||||
|
||||
namespace AppContent {
|
||||
|
||||
constexpr uint32_t APP_CONTENT_APPPARAM_SKU_FLAG_FULL = 3;
|
||||
constexpr int APP_CONTENT_ERROR_PARAMETER = -2133262334; /* 0x80D90002 */
|
||||
constexpr int APP_CONTENT_ERROR_BUSY = -2133262333; /* 0x80D90003 */
|
||||
constexpr int APP_CONTENT_ERROR_NOT_MOUNTED = -2133262332; /* 0x80D90004 */
|
||||
constexpr int APP_CONTENT_ERROR_NOT_FOUND = -2133262331; /* 0x80D90005 */
|
||||
constexpr int APP_CONTENT_ERROR_MOUNT_FULL = -2133262330; /* 0x80D90006 */
|
||||
@@ -207,7 +210,10 @@ int KYTY_SYSV_ABI AppContentAddcontMount(uint32_t servic
|
||||
|
||||
for (const auto& m: g_addcont_mounts) {
|
||||
if (m.label == entry->entitlement_label) {
|
||||
return APP_CONTENT_ERROR_BUSY;
|
||||
const auto guest_point = m.point.substr(0, m.point.size() - 1);
|
||||
std::strncpy(mount_point->data, guest_point.c_str(), sizeof(mount_point->data) - 1);
|
||||
LOGF("\t already mounted %s\n", guest_point.c_str());
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +238,15 @@ int KYTY_SYSV_ABI AppContentAddcontMount(uint32_t servic
|
||||
LOGF("\t mounted %s -> %s\n", mount.point.c_str(),
|
||||
Common::PathToString(entry->mount_dir).c_str());
|
||||
|
||||
std::strncpy(mount_point->data, mount.point.c_str(), sizeof(mount_point->data) - 1);
|
||||
AprShared::InvalidateFailedResolves();
|
||||
|
||||
// Titles scan /download0/pdlc for downloaded content; it must exist even when empty.
|
||||
if (const auto pdlc = LibKernel::FileSystem::GetRealFilename("/download0/pdlc"); !pdlc.empty()) {
|
||||
std::filesystem::create_directories(pdlc, ec);
|
||||
}
|
||||
|
||||
const auto guest_point = mount.point.substr(0, mount.point.size() - 1);
|
||||
std::strncpy(mount_point->data, guest_point.c_str(), sizeof(mount_point->data) - 1);
|
||||
g_addcont_mounts.push_back(std::move(mount));
|
||||
|
||||
return OK;
|
||||
@@ -251,8 +265,8 @@ int KYTY_SYSV_ABI AppContentAddcontUnmount(const AppContentMountPoint* mount_poi
|
||||
return APP_CONTENT_ERROR_NOT_MOUNTED;
|
||||
}
|
||||
|
||||
const std::string point(mount_point->data,
|
||||
strnlen(mount_point->data, sizeof(mount_point->data)));
|
||||
const std::string point = Common::FixDirectorySlash(
|
||||
std::string_view(mount_point->data, strnlen(mount_point->data, sizeof(mount_point->data))));
|
||||
|
||||
std::lock_guard lock(g_addcont_mutex);
|
||||
|
||||
@@ -263,6 +277,7 @@ int KYTY_SYSV_ABI AppContentAddcontUnmount(const AppContentMountPoint* mount_poi
|
||||
}
|
||||
LibKernel::FileSystem::Umount(point);
|
||||
g_addcont_mounts.erase(it);
|
||||
AprShared::InvalidateFailedResolves();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -221,11 +221,17 @@ int KYTY_SYSV_ABI PlayGoGetChunkId(int handle, uint16_t* out_chunk_id_list,
|
||||
if (out_entries == nullptr) {
|
||||
return PLAYGO_ERROR_BAD_POINTER;
|
||||
}
|
||||
if (number_of_entries != 0 && out_chunk_id_list == nullptr) {
|
||||
return PLAYGO_ERROR_BAD_POINTER;
|
||||
if (out_chunk_id_list != nullptr && number_of_entries == 0) {
|
||||
return PLAYGO_ERROR_BAD_SIZE;
|
||||
}
|
||||
ensure_chunks_loaded();
|
||||
|
||||
// A null output buffer asks for the total chunk count.
|
||||
if (out_chunk_id_list == nullptr) {
|
||||
*out_entries = g_chunks_num;
|
||||
return OK;
|
||||
}
|
||||
|
||||
const uint32_t entries = std::min(number_of_entries, g_chunks_num);
|
||||
for (uint32_t i = 0; i < entries; i++) {
|
||||
out_chunk_id_list[i] = static_cast<uint16_t>(i);
|
||||
|
||||
Reference in New Issue
Block a user