mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-04-22 12:34:47 +00:00
ncm: improve meta-db accuracy
This commit is contained in:
parent
dea664be3a
commit
a9953fc805
4 changed files with 108 additions and 37 deletions
|
@ -22,14 +22,16 @@ namespace ams::ncm {
|
|||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
/* Find the meta key. */
|
||||
ContentMetaKeyValueStore::Entry *entry = nullptr;
|
||||
R_TRY(this->FindContentMetaKeyValue(std::addressof(entry), key));
|
||||
const auto stored_key = entry->GetKey();
|
||||
const auto it = this->kvs->lower_bound(key);
|
||||
R_UNLESS(it != this->kvs->end(), ncm::ResultContentMetaNotFound());
|
||||
R_UNLESS(it->GetKey().id == key.id, ncm::ResultContentMetaNotFound());
|
||||
|
||||
const auto found_key = it->GetKey();
|
||||
|
||||
/* Create a reader for this content meta. */
|
||||
const void *meta;
|
||||
size_t meta_size;
|
||||
R_TRY(this->GetContentMetaPointer(&meta, &meta_size, stored_key));
|
||||
R_TRY(this->GetContentMetaPointer(&meta, &meta_size, found_key));
|
||||
|
||||
ContentMetaReader reader(meta, meta_size);
|
||||
|
||||
|
@ -79,12 +81,25 @@ namespace ams::ncm {
|
|||
|
||||
Result ContentMetaDatabaseImpl::Get(sf::Out<u64> out_size, const ContentMetaKey &key, sf::OutBuffer out_value) {
|
||||
R_TRY(this->EnsureEnabled());
|
||||
return this->kvs->Get(out_size.GetPointer(), out_value.GetPointer(), out_value.GetSize(), key);
|
||||
|
||||
/* Get the entry from our key-value store. */
|
||||
size_t size;
|
||||
R_TRY_CATCH(this->kvs->Get(std::addressof(size), out_value.GetPointer(), out_value.GetSize(), key)) {
|
||||
R_CONVERT(kvdb::ResultKeyNotFound, ncm::ResultContentMetaNotFound())
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
out_size.SetValue(size);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseImpl::Remove(const ContentMetaKey &key) {
|
||||
R_TRY(this->EnsureEnabled());
|
||||
return this->kvs->Remove(key);
|
||||
|
||||
R_TRY_CATCH(this->kvs->Remove(key)) {
|
||||
R_CONVERT(kvdb::ResultKeyNotFound, ncm::ResultContentMetaNotFound())
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ContentMetaDatabaseImpl::GetContentIdByType(sf::Out<ContentId> out_content_id, const ContentMetaKey &key, ContentType type) {
|
||||
|
@ -121,7 +136,7 @@ namespace ams::ncm {
|
|||
|
||||
/* Iterate over all entries. */
|
||||
for (auto entry = this->kvs->begin(); entry != this->kvs->end(); entry++) {
|
||||
ContentMetaKey key = entry->GetKey();
|
||||
const ContentMetaKey key = entry->GetKey();
|
||||
|
||||
/* Check if this entry matches the given filters. */
|
||||
if (!((meta_type == ContentMetaType::Unknown || key.type == meta_type) && (min <= key.id && key.id <= max) && (install_type == ContentInstallType::Unknown || key.install_type == install_type))) {
|
||||
|
@ -129,7 +144,7 @@ namespace ams::ncm {
|
|||
}
|
||||
|
||||
/* If application id is present, check if it matches the filter. */
|
||||
if (application_id != InvalidProgramId) {
|
||||
if (application_id != InvalidApplicationId) {
|
||||
/* Obtain the content meta for the key. */
|
||||
const void *meta;
|
||||
size_t meta_size;
|
||||
|
@ -169,10 +184,10 @@ namespace ams::ncm {
|
|||
|
||||
/* Iterate over all entries. */
|
||||
for (auto entry = this->kvs->begin(); entry != this->kvs->end(); entry++) {
|
||||
ContentMetaKey key = entry->GetKey();
|
||||
const ContentMetaKey key = entry->GetKey();
|
||||
|
||||
/* Check if this entry matches the given filters. */
|
||||
if (!((type == ContentMetaType::Unknown || key.type == type))) {
|
||||
if (!(type == ContentMetaType::Unknown || key.type == type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -250,10 +265,14 @@ namespace ams::ncm {
|
|||
ContentMetaReader reader(meta, meta_size);
|
||||
|
||||
/* Obtain the required system version. */
|
||||
if (key.type == ContentMetaType::Application) {
|
||||
out_version.SetValue(reader.GetExtendedHeader<ApplicationMetaExtendedHeader>()->required_system_version);
|
||||
} else {
|
||||
out_version.SetValue(reader.GetExtendedHeader<PatchMetaExtendedHeader>()->required_system_version);
|
||||
switch (key.type) {
|
||||
case ContentMetaType::Application:
|
||||
out_version.SetValue(reader.GetExtendedHeader<ApplicationMetaExtendedHeader>()->required_system_version);
|
||||
break;
|
||||
case ContentMetaType::Patch:
|
||||
out_version.SetValue(reader.GetExtendedHeader<PatchMetaExtendedHeader>()->required_system_version);
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
|
@ -333,14 +352,15 @@ namespace ams::ncm {
|
|||
/* Create a reader. */
|
||||
ContentMetaReader reader(meta, meta_size);
|
||||
|
||||
/* Optimistically suppose that we will find the content. */
|
||||
out.SetValue(true);
|
||||
|
||||
/* Check if any content infos contain a matching id. */
|
||||
for (size_t i = 0; i < reader.GetContentCount(); i++) {
|
||||
if (content_id == reader.GetContentInfo(i)->GetId()) {
|
||||
out.SetValue(true);
|
||||
return ResultSuccess();
|
||||
}
|
||||
R_SUCCEED_IF(content_id == reader.GetContentInfo(i)->GetId());
|
||||
}
|
||||
|
||||
/* We didn't find a content info. */
|
||||
out.SetValue(false);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
@ -395,13 +415,16 @@ namespace ams::ncm {
|
|||
|
||||
/* Get the required version. */
|
||||
u32 required_version;
|
||||
if (key.type == ContentMetaType::Application && hos::GetVersion() >= hos::Version_900) {
|
||||
/* As of 9.0.0, applications can be dependent on a specific base application version. */
|
||||
required_version = reader.GetExtendedHeader<ApplicationMetaExtendedHeader>()->required_application_version;
|
||||
} else if (key.type == ContentMetaType::AddOnContent) {
|
||||
required_version = reader.GetExtendedHeader<AddOnContentMetaExtendedHeader>()->required_application_version;
|
||||
} else {
|
||||
return ncm::ResultInvalidContentMetaKey();
|
||||
switch (key.type) {
|
||||
case ContentMetaType::AddOnContent:
|
||||
required_version = reader.GetExtendedHeader<AddOnContentMetaExtendedHeader>()->required_application_version;
|
||||
break;
|
||||
case ContentMetaType::Application:
|
||||
/* As of 9.0.0, applications can be dependent on a specific base application version. */
|
||||
AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_900);
|
||||
required_version = reader.GetExtendedHeader<ApplicationMetaExtendedHeader>()->required_application_version;
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
out_version.SetValue(required_version);
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace ams::ncm {
|
|||
using ContentMetaKeyValueStore = ams::kvdb::MemoryKeyValueStore<ContentMetaKey>;
|
||||
protected:
|
||||
ContentMetaKeyValueStore *kvs;
|
||||
char mount_name[16];
|
||||
char mount_name[fs::MountNameLengthMax + 1];
|
||||
bool disabled;
|
||||
protected:
|
||||
ContentMetaDatabaseImplBase(ContentMetaKeyValueStore *kvs) : kvs(kvs), disabled(false) { /* ... */ }
|
||||
|
@ -40,14 +40,6 @@ namespace ams::ncm {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result FindContentMetaKeyValue(ContentMetaKeyValueStore::Entry **out_entry, const ContentMetaKey &key) const {
|
||||
const auto it = this->kvs->lower_bound(key);
|
||||
R_UNLESS(it != this->kvs->end(), ncm::ResultContentMetaNotFound());
|
||||
R_UNLESS(it->GetKey().id == key.id, ncm::ResultContentMetaNotFound());
|
||||
*out_entry = it;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetContentMetaSize(size_t *out, const ContentMetaKey &key) const {
|
||||
R_TRY_CATCH(this->kvs->GetValueSize(out, key)) {
|
||||
R_CONVERT(kvdb::ResultKeyNotFound, ncm::ResultContentMetaNotFound())
|
||||
|
|
|
@ -18,26 +18,80 @@
|
|||
|
||||
namespace ams::ncm {
|
||||
|
||||
Result OnMemoryContentMetaDatabaseImpl::GetLatestContentMetaKey(sf::Out<ContentMetaKey> out_key, u64 id) {
|
||||
Result ContentMetaDatabaseImpl::GetLatestKeyImpl(ContentMetaKey *out_key, u64 id) const {
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
std::optional<ContentMetaKey> found_key;
|
||||
std::optional<ContentMetaKey> found_key = std::nullopt;
|
||||
|
||||
/* Find the last key with the desired program id. */
|
||||
for (auto entry = this->kvs->lower_bound(ContentMetaKey::Make(id, 0, ContentMetaType::Unknown)); entry != this->kvs->end(); entry++) {
|
||||
for (auto entry = this->kvs->lower_bound(ContentMetaKey::MakeUnknownType(id, 0)); entry != this->kvs->end(); entry++) {
|
||||
/* No further entries will match the program id, discontinue. */
|
||||
if (entry->GetKey().id != id) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* On memory content database is interested in all keys. */
|
||||
found_key = entry->GetKey();
|
||||
}
|
||||
|
||||
/* Check if the key is absent. */
|
||||
R_UNLESS(found_key, ncm::ResultContentMetaNotFound());
|
||||
|
||||
*out_key = *found_key;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result OnMemoryContentMetaDatabaseImpl::List(sf::Out<s32> out_entries_total, sf::Out<s32> out_entries_written, const sf::OutArray<ContentMetaKey> &out_info, ContentMetaType meta_type, ApplicationId application_id, u64 min, u64 max, ContentInstallType install_type) {
|
||||
/* NOTE: This function is *almost* identical to the ContentMetaDatabaseImpl equivalent. */
|
||||
/* The only difference is that the min max comparison is exclusive for OnMemoryContentMetaDatabaseImpl, */
|
||||
/* but inclusive for ContentMetaDatabaseImpl. This may or may not be a Nintendo bug? */
|
||||
R_TRY(this->EnsureEnabled());
|
||||
|
||||
size_t entries_total = 0;
|
||||
size_t entries_written = 0;
|
||||
|
||||
/* Iterate over all entries. */
|
||||
for (auto entry = this->kvs->begin(); entry != this->kvs->end(); entry++) {
|
||||
const ContentMetaKey key = entry->GetKey();
|
||||
|
||||
/* Check if this entry matches the given filters. */
|
||||
if (!((meta_type == ContentMetaType::Unknown || key.type == meta_type) && (min < key.id && key.id < max) && (install_type == ContentInstallType::Unknown || key.install_type == install_type))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If application id is present, check if it matches the filter. */
|
||||
if (application_id != InvalidApplicationId) {
|
||||
/* Obtain the content meta for the key. */
|
||||
const void *meta;
|
||||
size_t meta_size;
|
||||
R_TRY(this->GetContentMetaPointer(&meta, &meta_size, key));
|
||||
|
||||
/* Create a reader. */
|
||||
ContentMetaReader reader(meta, meta_size);
|
||||
|
||||
/* Ensure application id matches, if present. */
|
||||
if (const auto entry_application_id = reader.GetApplicationId(key); entry_application_id && application_id != *entry_application_id) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the entry to the output buffer. */
|
||||
if (entries_written < out_info.GetSize()) {
|
||||
out_info[entries_written++] = key;
|
||||
}
|
||||
entries_total++;
|
||||
}
|
||||
|
||||
out_entries_total.SetValue(entries_total);
|
||||
out_entries_written.SetValue(entries_written);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result OnMemoryContentMetaDatabaseImpl::GetLatestContentMetaKey(sf::Out<ContentMetaKey> out_key, u64 id) {
|
||||
R_TRY(this->EnsureEnabled());
|
||||
return this->GetLatestKeyImpl(out_key.GetPointer(), id);
|
||||
}
|
||||
|
||||
Result OnMemoryContentMetaDatabaseImpl::LookupOrphanContent(const sf::OutArray<bool> &out_orphaned, const sf::InArray<ContentId> &content_ids) {
|
||||
return ResultInvalidContentMetaDatabase();
|
||||
}
|
||||
|
|
|
@ -22,8 +22,10 @@ namespace ams::ncm {
|
|||
class OnMemoryContentMetaDatabaseImpl : public ContentMetaDatabaseImpl {
|
||||
public:
|
||||
OnMemoryContentMetaDatabaseImpl(ams::kvdb::MemoryKeyValueStore<ContentMetaKey> *kvs) : ContentMetaDatabaseImpl(kvs) { /* ... */ }
|
||||
Result GetLatestKeyImpl(ContentMetaKey *out_key, u64 id) const;
|
||||
public:
|
||||
/* Actual commands. */
|
||||
virtual Result List(sf::Out<s32> out_entries_total, sf::Out<s32> out_entries_written, const sf::OutArray<ContentMetaKey> &out_info, ContentMetaType meta_type, ApplicationId application_id, u64 min, u64 max, ContentInstallType install_type) override;
|
||||
virtual Result GetLatestContentMetaKey(sf::Out<ContentMetaKey> out_key, u64 id) override;
|
||||
virtual Result LookupOrphanContent(const sf::OutArray<bool> &out_orphaned, const sf::InArray<ContentId> &content_ids) override;
|
||||
virtual Result Commit() override;
|
||||
|
|
Loading…
Add table
Reference in a new issue