From 8330f23d20870c3e540efea99fcfc48324df4ab6 Mon Sep 17 00:00:00 2001 From: Adubbz Date: Thu, 26 Sep 2019 11:52:51 +1000 Subject: [PATCH] Updated ncm to new libnx ipc (#331) * Updated to new libnx ipc * Improved docs * Added firmware req comments * Improved ncmContentMetaDatabaseGetContentIdByType * Fix ncmContentMetaDatabaseGetContentIdByTypeAndIdOffset --- nx/include/switch/services/ncm.h | 232 ++++-- nx/source/services/ncm.c | 1315 +++++++++--------------------- 2 files changed, 540 insertions(+), 1007 deletions(-) diff --git a/nx/include/switch/services/ncm.h b/nx/include/switch/services/ncm.h index c237e858..3f352d8c 100644 --- a/nx/include/switch/services/ncm.h +++ b/nx/include/switch/services/ncm.h @@ -1,7 +1,7 @@ /** * @file ncm.h * @brief Content Manager (ncm) service IPC wrapper. - * @author zhuowei & Adubbz + * @author Adubbz & zhuowei * @copyright libnx Authors */ #pragma once @@ -9,112 +9,190 @@ #include "../services/fs.h" #include "../services/sm.h" +/// ContentStorage +typedef struct { + Service s; ///< IContentStorage +} NcmContentStorage; + +/// ContentMetaDatabase +typedef struct { + Service s; ///< IContentMetaDatabase +} NcmContentMetaDatabase; + /// ContentType typedef enum { - NcmContentType_CNMT = 0, ///< CNMT - NcmContentType_Program = 1, ///< Program - NcmContentType_Data = 2, ///< Data - NcmContentType_Icon = 3, ///< Icon - NcmContentType_Doc = 4, ///< Doc - NcmContentType_Info = 5, ///< Info + NcmContentType_Meta = 0, ///< Meta + NcmContentType_Program = 1, ///< Program + NcmContentType_Data = 2, ///< Data + NcmContentType_Control = 3, ///< Control + NcmContentType_HtmlDocument = 4, ///< HtmlDocument + NcmContentType_LegalInformation = 5, ///< LegalInformation + NcmContentType_DeltaFragment = 6, ///< DeltaFragment } NcmContentType; /// ContentMetaType typedef enum { - NcmContentMetaType_SystemProgram = 0x01, ///< SystemProgram - NcmContentMetaType_SystemData = 0x02, ///< SystemData - NcmContentMetaType_SystemUpdate = 0x03, ///< SystemUpdate - NcmContentMetaType_BootImagePackage = 0x04, ///< BootImagePackage - NcmContentMetaType_BootImagePackageSafe = 0x05, ///< BootImagePackageSafe - NcmContentMetaType_Application = 0x80, ///< Application - NcmContentMetaType_Patch = 0x81, ///< Patch - NcmContentMetaType_AddOnContent = 0x82, ///< AddOnContent - NcmContentMetaType_Delta = 0x83, ///< Delta + NcmContentMetaType_Unknown = 0x0, ///< Unknown + NcmContentMetaType_SystemProgram = 0x1, ///< SystemProgram + NcmContentMetaType_SystemData = 0x2, ///< SystemData + NcmContentMetaType_SystemUpdate = 0x3, ///< SystemUpdate + NcmContentMetaType_BootImagePackage = 0x4, ///< BootImagePackage + NcmContentMetaType_BootImagePackageSafe = 0x5, ///< BootImagePackageSafe + NcmContentMetaType_Application = 0x80, ///< Application + NcmContentMetaType_Patch = 0x81, ///< Patch + NcmContentMetaType_AddOnContent = 0x82, ///< AddOnContent + NcmContentMetaType_Delta = 0x83, ///< Delta } NcmContentMetaType; /// ContentMetaAttribute typedef enum { - NcmContentMetaAttribute_Exfat = (1 << 0), ///< Exfat - NcmContentMetaAttribute_Rebootless = (1 << 1), ///< Rebootless + NcmContentMetaAttribute_None = 0, ///< None + NcmContentMetaAttribute_IncludesExFatDriver = BIT(0), ///< IncludesExFatDriver + NcmContentMetaAttribute_Rebootless = BIT(1), ///< Rebootless } NcmContentMetaAttribute; -/// NcmContentStorage -typedef struct { - Service s; ///< IContentStorage -} NcmContentStorage; - -/// NcmContentMetaDatabase -typedef struct { - Service s; ///< IContentMetaDatabase -} NcmContentMetaDatabase; +/// ContentInstallType +typedef enum { + NcmContentInstallType_Full = 0, ///< Full + NcmContentInstallType_FragmentOnly = 1, ///< FragmentOnly + NcmContentInstallType_Unknown = 7, ///< Unknown +} NcmContentInstallType; /// NcaId typedef struct { - u8 c[0x10]; ///< Id + u8 c[0x10]; ///< Id } NcmNcaId; -/// MetaRecord +/// ContentMetaKey typedef struct { - u64 titleId; ///< titleID. - u32 version; ///< Title version. - u8 type; ///< Type. - u8 flags; ///< Flags. - u8 padding[2]; ///< Padding. -} NcmMetaRecord; - -/// ContentRecord -typedef struct { - NcmNcaId ncaId; ///< \ref NcmNcaId - u8 size[0x6]; ///< Content size. - u8 type; ///< Type. - u8 padding; ///< Padding. -} NcmContentRecord; - -/// ContentMetaRecordsHeader -typedef struct { - u16 numExtraBytes; ///< Size of optional struct that comes after this one. - u16 numContentRecords; ///< Number of NcmContentRecord entries after the extra bytes. - u16 numMetaRecords; ///< Number of NcmMetaRecord entries that come after the NcmContentRecords. - u16 padding; ///< Always zero. -} NcmContentMetaRecordsHeader; + u64 title_id; ///< Title id. + u32 version; ///< Title version. + NcmContentMetaType type; ///< \ref NcmContentMetaType + NcmContentInstallType install_type; ///< \ref NcmContentInstallType + u8 padding[2]; ///< Padding. +} NcmContentMetaKey; /// ApplicationContentMetaKey typedef struct { - NcmMetaRecord metaRecord; ///< \ref NcmMetaRecord - u64 baseTitleId; ///< Base titleID. + NcmContentMetaKey key; ///< \ref NcmContentMetaKey + u64 application_id; ///< Title id of an application. } NcmApplicationContentMetaKey; +/// ContentInfo +typedef struct { + NcmNcaId content_id; ///< \ref NcmNcaId + u8 size[0x6]; ///< Content size. + NcmContentType content_type; ///< \ref NcmContentType. + u8 id_offset; ///< Offset of this content. Unused by most applications. +} NcmContentInfo; + +/// Used by system updates. They share the exact same struct as NcmContentMetaKey +typedef NcmContentMetaKey NcmContentMetaInfo; + +/// ContentMetaHeader +typedef struct { + u16 extended_header_size; ///< Size of optional struct that comes after this one. + u16 content_count; ///< Number of NcmContentInfos after the extra bytes. + u16 content_meta_count; ///< Number of NcmContentMetaInfos that come after the NcmContentInfos. + NcmContentMetaAttribute attributes; ///< Usually None (0). + FsStorageId storage_id; ///< Usually None (0). +} NcmContentMetaHeader; + +/// ApplicationMetaExtendedHeader +typedef struct { + u64 patch_id; ///< Title id of this application's patch. + u32 required_system_version; ///< Firmware version required by this application. + u32 padding; ///< Padding. +} NcmApplicationMetaExtendedHeader; + +/// PatchMetaExtendedHeader +typedef struct { + u64 application_id; ///< Title id of this patch's corresponding application. + u32 required_system_version; ///< Firmware version required by this patch. + u32 extended_data_size; ///< Size of the extended data following the NcmContentInfos. + u8 reserved[0x8]; ///< Unused. +} NcmPatchMetaExtendedHeader; + +/// AddOnContentMetaExtendedHeader +typedef struct { + u64 application_id; ///< Title id of this add-on-content's corresponding application. + u32 required_application_version; ///< Version of the application required by this add-on-content. + u32 padding; ///< Padding. +} NcmAddOnContentMetaExtendedHeader; + +/// SystemUpdateMetaExtendedHeader +typedef struct { + u32 extended_data_size; ///< Size of the extended data after NcmContentInfos and NcmContentMetaInfos. +} NcmSystemUpdateMetaExtendedHeader; + Result ncmInitialize(void); void ncmExit(void); Service* ncmGetServiceSession(void); -Result ncmOpenContentStorage(FsStorageId storage, NcmContentStorage* out); -Result ncmOpenContentMetaDatabase(FsStorageId storage, NcmContentMetaDatabase* out); +Result ncmCreateContentStorage(FsStorageId storage_id); +Result ncmCreateContentMetaDatabase(FsStorageId storage_id); +Result ncmVerifyContentStorage(FsStorageId storage_id); +Result ncmVerifyContentMetaDatabase(FsStorageId storage_id); +Result ncmOpenContentStorage(NcmContentStorage* out_content_storage, FsStorageId storage_id); +Result ncmOpenContentMetaDatabase(NcmContentMetaDatabase* out_content_meta_database, FsStorageId storage_id); +Result ncmCloseContentStorageForcibly(FsStorageId storage_id); ///< [1.0.0] +Result ncmCloseContentMetaDatabaseForcibly(FsStorageId storage_id); ///< [1.0.0] +Result ncmCleanupContentMetaDatabase(FsStorageId storage_id); +Result ncmActivateContentStorage(FsStorageId storage_id); ///< [2.0.0+] +Result ncmInactivateContentStorage(FsStorageId storage_id); ///< [2.0.0+] +Result ncmActivateContentMetaDatabase(FsStorageId storage_id); ///< [2.0.0+] +Result ncmInactivateContentMetaDatabase(FsStorageId storage_id); ///< [2.0.0+] +Result ncmInvalidateRightsIdCache(void); ///< [9.0.0+] -Result ncmContentStorageGeneratePlaceHolderId(NcmContentStorage* cs, NcmNcaId* outputId); -Result ncmContentStorageCreatePlaceHolder(NcmContentStorage* cs, const NcmNcaId* registeredId, const NcmNcaId* placeholderId, u64 size); -Result ncmContentStorageDeletePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholderId); -Result ncmContentStorageWritePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholderId, u64 offset, const void* srcData, size_t srcDataSize); -Result ncmContentStorageRegister(NcmContentStorage* cs, const NcmNcaId* registeredId, const NcmNcaId* placeholderId); -Result ncmContentStorageDelete(NcmContentStorage* cs, const NcmNcaId* registeredId); -Result ncmContentStorageHas(NcmContentStorage* cs, const NcmNcaId* ncaId, bool* out); -Result ncmContentStorageGetPath(NcmContentStorage* cs, const NcmNcaId* ncaId, char* out, size_t outSize); -Result ncmContentStorageGetPlaceHolderPath(NcmContentStorage* cs, const NcmNcaId* ncaId, char* out, size_t outSize); +void ncmContentStorageClose(NcmContentStorage* cs); +Result ncmContentStorageGeneratePlaceHolderId(NcmContentStorage* cs, NcmNcaId* out_id); +Result ncmContentStorageCreatePlaceHolder(NcmContentStorage* cs, const NcmNcaId* content_id, const NcmNcaId* placeholder_id, u64 size); +Result ncmContentStorageDeletePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholder_id); +Result ncmContentStorageHasPlaceHolder(NcmContentStorage* cs, bool* out, const NcmNcaId* placeholder_id); +Result ncmContentStorageWritePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholder_id, u64 offset, const void* data, size_t data_size); +Result ncmContentStorageRegister(NcmContentStorage* cs, const NcmNcaId* content_id, const NcmNcaId* placeholder_id); +Result ncmContentStorageDelete(NcmContentStorage* cs, const NcmNcaId* content_id); +Result ncmContentStorageHas(NcmContentStorage* cs, bool* out, const NcmNcaId* content_id); +Result ncmContentStorageGetPath(NcmContentStorage* cs, char* out_path, size_t out_size, const NcmNcaId* content_id); +Result ncmContentStorageGetPlaceHolderPath(NcmContentStorage* cs, const char* out_path, size_t out_size, const NcmNcaId* placeholder_id); Result ncmContentStorageCleanupAllPlaceHolder(NcmContentStorage* cs); -Result ncmContentStorageGetSize(NcmContentStorage* cs, const NcmNcaId* ncaId, u64* out); +Result ncmContentStorageListPlaceHolder(NcmContentStorage* cs, NcmNcaId* out_ids, size_t out_ids_size, u32* out_count); +Result ncmContentStorageGetContentCount(NcmContentStorage* cs, u32* out_count); +Result ncmContentStorageListContentId(NcmContentStorage* cs, NcmNcaId* out_ids, size_t out_ids_size, u32* out_count, u32 start_offset); +Result ncmContentStorageGetSizeFromContentId(NcmContentStorage* cs, u64* out_size, const NcmNcaId* content_id); Result ncmContentStorageDisableForcibly(NcmContentStorage* cs); -Result ncmContentStorageReadContentIdFile(NcmContentStorage* cs, const NcmNcaId* ncaId, u64 offset, void* outBuf, size_t bufSize); -Result ncmContentStorageGetRightsIdFromContentId(NcmContentStorage* cs, const NcmNcaId* ncaId, FsRightsId* rightsIdOut, u32* keyGenerationOut); +Result ncmContentStorageRevertToPlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholder_id, const NcmNcaId* old_content_id, const NcmNcaId* new_content_id); ///< [2.0.0+] +Result ncmContentStorageSetPlaceHolderSize(NcmContentStorage* cs, const NcmNcaId* placeholder_id, u64 size); ///< [2.0.0+] +Result ncmContentStorageReadContentIdFile(NcmContentStorage* cs, void* out_data, size_t out_data_size, const NcmNcaId* content_id, u64 offset); ///< [2.0.0+] +Result ncmContentStorageGetRightsIdFromPlaceHolderId(NcmContentStorage* cs, FsRightsId* out_rights_id, u32* out_key_generation, const NcmNcaId* placeholder_id); ///< [2.0.0+] +Result ncmContentStorageGetRightsIdFromContentId(NcmContentStorage* cs, FsRightsId* out_rights_id, u32* out_key_generation, const NcmNcaId* content_id); ///< [2.0.0+] +Result ncmContentStorageWriteContentForDebug(NcmContentStorage* cs, const NcmNcaId* content_id, u64 offset, const void* data, size_t data_size); ///< [2.0.0+] +Result ncmContentStorageGetFreeSpaceSize(NcmContentStorage* cs, u64* out_size); ///< [2.0.0+] +Result ncmContentStorageGetTotalSpaceSize(NcmContentStorage* cs, u64* out_size); ///< [2.0.0+] +Result ncmContentStorageFlushPlaceHolder(NcmContentStorage* cs); ///< [3.0.0+] +Result ncmContentStorageGetSizeFromPlaceHolderId(NcmContentStorage* cs, u64* out_size, const NcmNcaId* placeholder_id); ///< [4.0.0+] +Result ncmContentStorageRepairInvalidFileAttribute(NcmContentStorage* cs); ///< [4.0.0+] +Result ncmContentStorageGetRightsIdFromPlaceHolderIdWithCache(NcmContentStorage* cs, FsRightsId* out_rights_id, u32* out_key_generation, const NcmNcaId* placeholder_id, const NcmNcaId* cache_content_id); ///< [8.0.0+] -Result ncmContentMetaDatabaseSet(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u64 inDataSize, const NcmContentMetaRecordsHeader* srcRecordsData); -Result ncmContentMetaDatabaseGet(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u64 outDataSize, NcmContentMetaRecordsHeader* outRecordsData, u64* sizeRead); -Result ncmContentMetaDatabaseRemove(NcmContentMetaDatabase* db, const NcmMetaRecord *record); -Result ncmContentMetaDatabaseGetContentIdByType(NcmContentMetaDatabase* db, NcmContentType contentType, const NcmMetaRecord* record, NcmNcaId* out); -Result ncmContentMetaDatabaseListContentInfo(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u32 index, NcmContentRecord* contentRecordsOut, size_t contentRecordsBufSize, u32* numEntriesRead); -Result ncmContentMetaDatabaseList(NcmContentMetaDatabase* db, u32 titleType, u64 titleIdExact, u64 titleIdLow, u64 titleIdHigh, NcmMetaRecord* metaRecordsOut, size_t metaRecordsBufSize, u32* numEntriesWritten, u32* numEntriesTotal); -Result ncmContentMetaDatabaseGetLatestContentMetaKey(NcmContentMetaDatabase* db, u64 titleId, NcmMetaRecord* out); -Result ncmContentMetaDatabaseListApplication(NcmContentMetaDatabase* db, u8 filter, NcmApplicationContentMetaKey* outBuf, size_t outBufSize, u32* numEntriesWritten, u32* numEntriesTotal); -Result ncmContentMetaDatabaseHas(NcmContentMetaDatabase* db, const NcmMetaRecord* record, bool* out); +void ncmContentMetaDatabaseClose(NcmContentMetaDatabase* db); +Result ncmContentMetaDatabaseSet(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, const void* data, u64 data_size); +Result ncmContentMetaDatabaseGet(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, u64* out_size, void* out_data, u64 out_data_size); +Result ncmContentMetaDatabaseRemove(NcmContentMetaDatabase* db, const NcmContentMetaKey *key); +Result ncmContentMetaDatabaseGetContentIdByType(NcmContentMetaDatabase* db, NcmNcaId* out_content_id, const NcmContentMetaKey* key, NcmContentType type); +Result ncmContentMetaDatabaseListContentInfo(NcmContentMetaDatabase* db, u32* out_entries_written, NcmContentInfo* out_info, size_t out_info_size, const NcmContentMetaKey* key, u32 start_index); +Result ncmContentMetaDatabaseList(NcmContentMetaDatabase* db, u32* out_entries_total, u32* out_entries_written, NcmContentMetaKey* out_keys, size_t out_keys_size, NcmContentMetaType meta_type, u64 application_title_id, u64 title_id_min, u64 title_id_max, NcmContentInstallType install_type); +Result ncmContentMetaDatabaseGetLatestContentMetaKey(NcmContentMetaDatabase* db, NcmContentMetaKey* out_key, u64 title_id); +Result ncmContentMetaDatabaseListApplication(NcmContentMetaDatabase* db, u32* out_entries_total, u32* out_entries_written, NcmApplicationContentMetaKey* out_keys, size_t out_keys_size, NcmContentMetaType meta_type); +Result ncmContentMetaDatabaseHas(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* key); +Result ncmContentMetaDatabaseHasAll(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* keys, size_t keys_size); +Result ncmContentMetaDatabaseGetSize(NcmContentMetaDatabase* db, u64* out_size, const NcmContentMetaKey* key); +Result ncmContentMetaDatabaseGetRequiredSystemVersion(NcmContentMetaDatabase* db, u64* out_version, const NcmContentMetaKey* key); +Result ncmContentMetaDatabaseGetPatchId(NcmContentMetaDatabase* db, u64* out_patch_id, const NcmContentMetaKey* key); Result ncmContentMetaDatabaseDisableForcibly(NcmContentMetaDatabase* db); +Result ncmContentMetaDatabaseLookupOrphanContent(NcmContentMetaDatabase* db, bool* out_orphaned, size_t out_orphaned_size, const NcmNcaId* content_ids, size_t content_ids_size); Result ncmContentMetaDatabaseCommit(NcmContentMetaDatabase* db); -Result ncmContentMetaDatabaseGetAttributes(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u8* out); +Result ncmContentMetaDatabaseHasContent(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* key, const NcmNcaId* content_id); +Result ncmContentMetaDatabaseListContentMetaInfo(NcmContentMetaDatabase* db, u32* out_entries_written, void* out_meta_info, size_t out_meta_info_size, const NcmContentMetaKey* key, u32 start_index); +Result ncmContentMetaDatabaseGetAttributes(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, u8* out); +Result ncmContentMetaDatabaseGetRequiredApplicationVersion(NcmContentMetaDatabase* db, u64* out_version, const NcmContentMetaKey* key); ///< [2.0.0+] +Result ncmContentMetaDatabaseGetContentIdByTypeAndIdOffset(NcmContentMetaDatabase* db, NcmNcaId* out_content_id, const NcmContentMetaKey* key, NcmContentType type, u8 id_offset); ///< [5.0.0+] diff --git a/nx/source/services/ncm.c b/nx/source/services/ncm.c index 217c1ebb..6d164e29 100644 --- a/nx/source/services/ncm.c +++ b/nx/source/services/ncm.c @@ -1,1029 +1,484 @@ +#define NX_SERVICE_ASSUME_NON_DOMAIN #include +#include "service_guard.h" +#include "runtime/hosversion.h" #include "services/ncm.h" -#include "arm/atomics.h" static Service g_ncmSrv; -static u64 g_ncmRefCnt; -Result ncmInitialize(void) { - atomicIncrement64(&g_ncmRefCnt); - - if (serviceIsActive(&g_ncmSrv)) - return 0; +NX_GENERATE_SERVICE_GUARD(ncm); +Result _ncmInitialize(void) { return smGetService(&g_ncmSrv, "ncm"); } -void ncmExit(void) { - if (atomicDecrement64(&g_ncmRefCnt) == 0) { - serviceClose(&g_ncmSrv); - } +void _ncmCleanup(void) { + serviceClose(&g_ncmSrv); } Service* ncmGetServiceSession(void) { return &g_ncmSrv; } -Result ncmOpenContentStorage(FsStorageId storage, NcmContentStorage* out) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - u32 storage_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 4; - raw->storage_id = (u32)storage; - - Result rc = serviceIpcDispatch(&g_ncmSrv); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - serviceCreate(&out->s, r.Handles[0]); - } - } - - return rc; +static Result _ncmGetInterfaceInU8(Service* srv_out, u32 cmd_id, u8 inval) { + return serviceDispatchIn(&g_ncmSrv, cmd_id, inval, + .out_num_objects = 1, + .out_objects = srv_out, + ); } -Result ncmOpenContentMetaDatabase(FsStorageId storage, NcmContentMetaDatabase* out) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - u32 storage_id; // Actually u8 - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 5; - raw->storage_id = (u32)storage; - - Result rc = serviceIpcDispatch(&g_ncmSrv); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - serviceCreate(&out->s, r.Handles[0]); - } - } - - return rc; +static Result _ncmCmdNoIo(Service* srv, u32 cmd_id) { + return serviceDispatch(srv, cmd_id); } -Result ncmContentStorageGeneratePlaceHolderId(NcmContentStorage* cs, NcmNcaId* outputId) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 0; - - Result rc = serviceIpcDispatch(&cs->s); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - NcmNcaId outputId; - } *resp = r.Raw; - - rc = resp->result; - if (R_SUCCEEDED(rc)) { - memcpy(outputId, &resp->outputId, sizeof(NcmNcaId)); - } - } - - return rc; +static Result _ncmCmdNoInOutU64(Service* srv, u32 cmd_id, u64* outval) { + return serviceDispatchOut(srv, cmd_id, *outval); } -Result ncmContentStorageCreatePlaceHolder(NcmContentStorage* cs, const NcmNcaId* registeredId, const NcmNcaId* placeholderId, u64 size) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - NcmNcaId registeredId; - NcmNcaId placeholderId; +static Result _ncmCmdOutNcaId(Service* srv, u32 cmd_id, NcmNcaId* outval) { + return serviceDispatchOut(srv, cmd_id, *outval); +} + +static Result _ncmCmdInU8(Service* srv, u32 cmd_id, u8 inval) { + return serviceDispatchIn(srv, cmd_id, inval); +} + +static Result _ncmCmdInNcaId(Service* srv, u32 cmd_id, const NcmNcaId* inval) { + return serviceDispatchIn(srv, cmd_id, *inval); +} + +static Result _ncmCmdInNcaIdOutU64(Service* srv, u32 cmd_id, const NcmNcaId* inval, u64* outval) { + return serviceDispatchInOut(srv, cmd_id, *inval, *outval); +} + +Result ncmCreateContentStorage(FsStorageId storage_id) { + return _ncmCmdInU8(&g_ncmSrv, 0, storage_id); +} + +Result ncmCreateContentMetaDatabase(FsStorageId storage_id) { + return _ncmCmdInU8(&g_ncmSrv, 1, storage_id); +} + +Result ncmVerifyContentStorage(FsStorageId storage_id) { + return _ncmCmdInU8(&g_ncmSrv, 2, storage_id); +} + +Result ncmVerifyContentMetaDatabase(FsStorageId storage_id) { + return _ncmCmdInU8(&g_ncmSrv, 3, storage_id); +} + +Result ncmOpenContentStorage(NcmContentStorage* out_content_storage, FsStorageId storage_id) { + return _ncmGetInterfaceInU8(&out_content_storage->s, 4, storage_id); +} + +Result ncmOpenContentMetaDatabase(NcmContentMetaDatabase* out_content_meta_database, FsStorageId storage_id) { + return _ncmGetInterfaceInU8(&out_content_meta_database->s, 5, storage_id); +} + +Result ncmCloseContentStorageForcibly(FsStorageId storage_id) { + if (hosversionAtLeast(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _ncmCmdInU8(&g_ncmSrv, 6, storage_id); +} + +Result ncmCloseContentMetaDatabaseForcibly(FsStorageId storage_id) { + if (hosversionAtLeast(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _ncmCmdInU8(&g_ncmSrv, 7, storage_id); +} + +Result ncmCleanupContentMetaDatabase(FsStorageId storage_id) { + return _ncmCmdInU8(&g_ncmSrv, 8, storage_id); +} + +Result ncmActivateContentStorage(FsStorageId storage_id) { + if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _ncmCmdInU8(&g_ncmSrv, 9, storage_id); +} + +Result ncmInactivateContentStorage(FsStorageId storage_id) { + if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _ncmCmdInU8(&g_ncmSrv, 10, storage_id); +} + +Result ncmActivateContentMetaDatabase(FsStorageId storage_id) { + if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _ncmCmdInU8(&g_ncmSrv, 11, storage_id); +} + +Result ncmInactivateContentMetaDatabase(FsStorageId storage_id) { + if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _ncmCmdInU8(&g_ncmSrv, 12, storage_id); +} + +Result ncmInvalidateRightsIdCache(void) { + if (hosversionBefore(9,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _ncmCmdNoIo(&g_ncmSrv, 13); +} + +void ncmContentStorageClose(NcmContentStorage* cs) { + serviceClose(&cs->s); +} + +Result ncmContentStorageGeneratePlaceHolderId(NcmContentStorage* cs, NcmNcaId* out_id) { + return _ncmCmdOutNcaId(&cs->s, 0, out_id); +} + +Result ncmContentStorageCreatePlaceHolder(NcmContentStorage* cs, const NcmNcaId* content_id, const NcmNcaId* placeholder_id, u64 size) { + const struct { + NcmNcaId content_id; + NcmNcaId placeholder_id; u64 size; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - raw->magic = SFCI_MAGIC; - raw->cmd_id = 1; - memcpy(&raw->registeredId, registeredId, sizeof(NcmNcaId)); - memcpy(&raw->placeholderId, placeholderId, sizeof(NcmNcaId)); - raw->size = size; - - Result rc = serviceIpcDispatch(&cs->s); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - } - - return rc; + } in = { *content_id, *placeholder_id, size }; + return serviceDispatchIn(&cs->s, 1, in); } -Result ncmContentStorageDeletePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholderId) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - NcmNcaId placeholderId; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - raw->magic = SFCI_MAGIC; - raw->cmd_id = 2; - memcpy(&raw->placeholderId, placeholderId, sizeof(NcmNcaId)); - - Result rc = serviceIpcDispatch(&cs->s); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - } - - return rc; +Result ncmContentStorageDeletePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholder_id) { + return _ncmCmdInNcaId(&cs->s, 2, placeholder_id); } -Result ncmContentStorageWritePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholderId, u64 offset, const void* srcData, size_t srcDataSize) { - IpcCommand c; - ipcInitialize(&c); - ipcAddSendBuffer(&c, srcData, srcDataSize, BufferType_Normal); - - struct { - u64 magic; - u64 cmd_id; - NcmNcaId placeholderId; +Result ncmContentStorageHasPlaceHolder(NcmContentStorage* cs, bool* out, const NcmNcaId* placeholder_id) { + return serviceDispatchInOut(&cs->s, 3, *placeholder_id, *out); +} + +Result ncmContentStorageWritePlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholder_id, u64 offset, const void* data, size_t data_size) { + const struct { + NcmNcaId placeholder_id; u64 offset; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - raw->magic = SFCI_MAGIC; - raw->cmd_id = 4; - memcpy(&raw->placeholderId, placeholderId, sizeof(NcmNcaId)); - raw->offset = offset; - - Result rc = serviceIpcDispatch(&cs->s); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - } - - return rc; + } in = { *placeholder_id, offset }; + return serviceDispatchIn(&cs->s, 4, in, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { data, data_size } }, + ); } -Result ncmContentStorageRegister(NcmContentStorage* cs, const NcmNcaId* registeredId, const NcmNcaId* placeholderId) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - NcmNcaId registeredId; - NcmNcaId placeholderId; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - raw->magic = SFCI_MAGIC; - raw->cmd_id = 5; - memcpy(&raw->registeredId, registeredId, sizeof(NcmNcaId)); - memcpy(&raw->placeholderId, placeholderId, sizeof(NcmNcaId)); - - Result rc = serviceIpcDispatch(&cs->s); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - } - - return rc; +Result ncmContentStorageRegister(NcmContentStorage* cs, const NcmNcaId* content_id, const NcmNcaId* placeholder_id) { + const struct { + NcmNcaId content_id; + NcmNcaId placeholder_id; + } in = { *content_id, *placeholder_id }; + return serviceDispatchIn(&cs->s, 5, in); } -Result ncmContentStorageDelete(NcmContentStorage* cs, const NcmNcaId* registeredId) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - NcmNcaId registeredId; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - raw->magic = SFCI_MAGIC; - raw->cmd_id = 6; - memcpy(&raw->registeredId, registeredId, sizeof(NcmNcaId)); - - Result rc = serviceIpcDispatch(&cs->s); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - } - - return rc; +Result ncmContentStorageDelete(NcmContentStorage* cs, const NcmNcaId* content_id) { + return _ncmCmdInNcaId(&cs->s, 6, content_id); } -Result ncmContentStorageHas(NcmContentStorage* cs, const NcmNcaId* ncaId, bool* out) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - NcmNcaId nca_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - raw->magic = SFCI_MAGIC; - raw->cmd_id = 7; - memcpy(&raw->nca_id, ncaId, sizeof(NcmNcaId)); - - Result rc = serviceIpcDispatch(&cs->s); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - bool out; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - if (out) *out = resp->out; - } - } - - return rc; +Result ncmContentStorageHas(NcmContentStorage* cs, bool* out, const NcmNcaId* content_id) { + return serviceDispatchInOut(&cs->s, 7, *content_id, *out); } -Result ncmContentStorageGetPath(NcmContentStorage* cs, const NcmNcaId* ncaId, char* out, size_t outSize) { - char out_path[FS_MAX_PATH-1] = {0}; - IpcCommand c; - ipcInitialize(&c); - ipcAddRecvStatic(&c, out_path, FS_MAX_PATH-1, 0); - - struct { - u64 magic; - u64 cmd_id; - NcmNcaId nca_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - raw->magic = SFCI_MAGIC; - raw->cmd_id = 8; - memcpy(&raw->nca_id, ncaId, sizeof(NcmNcaId)); - - Result rc = serviceIpcDispatch(&cs->s); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - if (outSize > FS_MAX_PATH-1) outSize = FS_MAX_PATH-1; - strncpy(out, out_path, outSize); - } - } - - return rc; +Result ncmContentStorageGetPath(NcmContentStorage* cs, char* out_path, size_t out_size, const NcmNcaId* content_id) { + return serviceDispatchIn(&cs->s, 8, *content_id, + .buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out }, + .buffers = { { out_path, out_size } }, + ); } -Result ncmContentStorageGetPlaceHolderPath(NcmContentStorage* cs, const NcmNcaId* ncaId, char* out, size_t outSize) { - char out_path[FS_MAX_PATH-1] = {0}; - IpcCommand c; - ipcInitialize(&c); - ipcAddRecvStatic(&c, out_path, FS_MAX_PATH-1, 0); - - struct { - u64 magic; - u64 cmd_id; - NcmNcaId nca_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - raw->magic = SFCI_MAGIC; - raw->cmd_id = 9; - memcpy(&raw->nca_id, ncaId, sizeof(NcmNcaId)); - - Result rc = serviceIpcDispatch(&cs->s); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - if (outSize > FS_MAX_PATH-1) outSize = FS_MAX_PATH-1; - strncpy(out, out_path, outSize); - } - } - - return rc; +Result ncmContentStorageGetPlaceHolderPath(NcmContentStorage* cs, const char* out_path, size_t out_size, const NcmNcaId* placeholder_id) { + return serviceDispatchIn(&cs->s, 9, *placeholder_id, + .buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out }, + .buffers = { { out_path, out_size } }, + ); } Result ncmContentStorageCleanupAllPlaceHolder(NcmContentStorage* cs) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - raw->magic = SFCI_MAGIC; - raw->cmd_id = 10; - - Result rc = serviceIpcDispatch(&cs->s); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - } - - return rc; + return _ncmCmdNoIo(&cs->s, 10); } -Result ncmContentStorageGetSize(NcmContentStorage* cs, const NcmNcaId* ncaId, u64* out) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - NcmNcaId nca_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - raw->magic = SFCI_MAGIC; - raw->cmd_id = 14; - memcpy(&raw->nca_id, ncaId, sizeof(NcmNcaId)); - - Result rc = serviceIpcDispatch(&cs->s); +Result ncmContentStorageListPlaceHolder(NcmContentStorage* cs, NcmNcaId* out_ids, size_t out_ids_size, u32* out_count) { + return serviceDispatchOut(&cs->s, 11, out_count, *out_count, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { out_ids, out_ids_size } }, + ); +} - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); +Result ncmContentStorageGetContentCount(NcmContentStorage* cs, u32* out_count) { + return serviceDispatchOut(&cs->s, 12, *out_count); +} - struct { - u64 magic; - u64 result; - u64 size; - } *resp = r.Raw; +Result ncmContentStorageListContentId(NcmContentStorage* cs, NcmNcaId* out_ids, size_t out_ids_size, u32* out_count, u32 start_offset) { + return serviceDispatchInOut(&cs->s, 13, start_offset, *out_count, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { out_ids, out_ids_size } }, + ); +} - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - *out = resp->size; - } - } - - return rc; +Result ncmContentStorageGetSizeFromContentId(NcmContentStorage* cs, u64* out_size, const NcmNcaId* content_id) { + return _ncmCmdInNcaIdOutU64(&cs->s, 14, content_id, out_size); } Result ncmContentStorageDisableForcibly(NcmContentStorage* cs) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - raw->magic = SFCI_MAGIC; - raw->cmd_id = 15; - - Result rc = serviceIpcDispatch(&cs->s); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - } - - return rc; + return _ncmCmdNoIo(&cs->s, 15); } -Result ncmContentStorageReadContentIdFile(NcmContentStorage* cs, const NcmNcaId* ncaId, u64 offset, void* outBuf, size_t bufSize) { - IpcCommand c; - ipcInitialize(&c); - ipcAddRecvBuffer(&c, outBuf, bufSize, BufferType_Normal); - - struct { - u64 magic; - u64 cmd_id; - NcmNcaId nca_id; +Result ncmContentStorageRevertToPlaceHolder(NcmContentStorage* cs, const NcmNcaId* placeholder_id, const NcmNcaId* old_content_id, const NcmNcaId* new_content_id) { + if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + NcmNcaId old_content_id; + NcmNcaId new_content_id; + NcmNcaId placeholder_id; + } in = { *old_content_id, *new_content_id, *placeholder_id }; + return serviceDispatchIn(&cs->s, 16, in); +} + +Result ncmContentStorageSetPlaceHolderSize(NcmContentStorage* cs, const NcmNcaId* placeholder_id, u64 size) { + if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + NcmNcaId placeholder_id; + u64 size; + } in = { *placeholder_id, size }; + return serviceDispatchIn(&cs->s, 17, in); +} + +Result ncmContentStorageReadContentIdFile(NcmContentStorage* cs, void* out_data, size_t out_data_size, const NcmNcaId* content_id, u64 offset) { + if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + NcmNcaId content_id; u64 offset; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - raw->magic = SFCI_MAGIC; - raw->cmd_id = 18; - memcpy(&raw->nca_id, ncaId, sizeof(NcmNcaId)); - raw->offset = offset; - - Result rc = serviceIpcDispatch(&cs->s); + } in = { *content_id, offset }; + return serviceDispatchIn(&cs->s, 18, in, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { out_data, out_data_size } }, + ); +} +Result ncmContentStorageGetRightsIdFromPlaceHolderId(NcmContentStorage* cs, FsRightsId* out_rights_id, u32* out_key_generation, const NcmNcaId* placeholder_id) { + if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + struct { + FsRightsId rights_id; + u32 key_generation; + } out; + Result rc = serviceDispatchInOut(&cs->s, 19, *placeholder_id, out); if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; + if (out_rights_id) *out_rights_id = out.rights_id; + if (out_key_generation) *out_key_generation = out.key_generation; } - return rc; } -Result ncmContentStorageGetRightsIdFromContentId(NcmContentStorage* cs, const NcmNcaId* ncaId, FsRightsId* rightsIdOut, u32* keyGenerationOut) { - IpcCommand c; - ipcInitialize(&c); - +Result ncmContentStorageGetRightsIdFromContentId(NcmContentStorage* cs, FsRightsId* out_rights_id, u32* out_key_generation, const NcmNcaId* content_id) { + if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); struct { - u64 magic; - u64 cmd_id; - NcmNcaId nca_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 20; - memcpy(&raw->nca_id, ncaId, sizeof(NcmNcaId)); - - Result rc = serviceIpcDispatch(&cs->s); + FsRightsId rights_id; + u32 key_generation; + } out; + Result rc = serviceDispatchInOut(&cs->s, 20, *content_id, out); if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - FsRightsId rights_id; - u32 key_generation; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - if (rightsIdOut) memcpy(rightsIdOut, &resp->rights_id, sizeof(FsRightsId)); - if (keyGenerationOut) *keyGenerationOut = resp->key_generation; - } + if (out_rights_id) *out_rights_id = out.rights_id; + if (out_key_generation) *out_key_generation = out.key_generation; } - return rc; } -Result ncmContentMetaDatabaseSet(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u64 inDataSize, const NcmContentMetaRecordsHeader* srcRecordsData) { - IpcCommand c; - ipcInitialize(&c); - ipcAddSendBuffer(&c, srcRecordsData, inDataSize, BufferType_Normal); +Result ncmContentStorageWriteContentForDebug(NcmContentStorage* cs, const NcmNcaId* content_id, u64 offset, const void* data, size_t data_size) { + if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + NcmNcaId content_id; + u64 offset; + } in = { *content_id, offset }; + return serviceDispatchIn(&cs->s, 21, in, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { data, data_size } }, + ); +} +Result ncmContentStorageGetFreeSpaceSize(NcmContentStorage* cs, u64* out_size) { + if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _ncmCmdNoInOutU64(&cs->s, 22, out_size); +} + +Result ncmContentStorageGetTotalSpaceSize(NcmContentStorage* cs, u64* out_size) { + if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _ncmCmdNoInOutU64(&cs->s, 23, out_size); +} + +Result ncmContentStorageFlushPlaceHolder(NcmContentStorage* cs) { + if (hosversionBefore(3,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _ncmCmdNoIo(&cs->s, 24); +} + +Result ncmContentStorageGetSizeFromPlaceHolderId(NcmContentStorage* cs, u64* out_size, const NcmNcaId* placeholder_id) { + if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _ncmCmdInNcaIdOutU64(&cs->s, 25, placeholder_id, out_size); +} + +Result ncmContentStorageRepairInvalidFileAttribute(NcmContentStorage* cs) { + if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return _ncmCmdNoIo(&cs->s, 26); +} + +Result ncmContentStorageGetRightsIdFromPlaceHolderIdWithCache(NcmContentStorage* cs, FsRightsId* out_rights_id, u32* out_key_generation, const NcmNcaId* placeholder_id, const NcmNcaId* cache_content_id) { + if (hosversionBefore(8,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + NcmNcaId cache_content_id; + NcmNcaId placeholder_id; + } in = { *cache_content_id, *placeholder_id }; struct { - u64 magic; - u64 cmd_id; - NcmMetaRecord meta_record; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 0; - memcpy(&raw->meta_record, record, sizeof(NcmMetaRecord)); - - Result rc = serviceIpcDispatch(&db->s); + FsRightsId rights_id; + u32 key_generation; + } out; + Result rc = serviceDispatchInOut(&cs->s, 27, in, out); if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; + if (out_rights_id) *out_rights_id = out.rights_id; + if (out_key_generation) *out_key_generation = out.key_generation; } - return rc; } -Result ncmContentMetaDatabaseGet(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u64 outDataSize, NcmContentMetaRecordsHeader* outRecordsData, u64* sizeRead) { - IpcCommand c; - ipcInitialize(&c); - ipcAddRecvBuffer(&c, outRecordsData, outDataSize, BufferType_Normal); - - struct { - u64 magic; - u64 cmd_id; - NcmMetaRecord meta_record; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 1; - memcpy(&raw->meta_record, record, sizeof(NcmMetaRecord)); - - Result rc = serviceIpcDispatch(&db->s); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u64 size_read; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - if (sizeRead) *sizeRead = resp->size_read; - } - } - - return rc; +void ncmContentMetaDatabaseClose(NcmContentMetaDatabase* db) { + serviceClose(&db->s); } -Result ncmContentMetaDatabaseRemove(NcmContentMetaDatabase* db, const NcmMetaRecord *record) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - NcmMetaRecord meta_record; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 2; - memcpy(&raw->meta_record, record, sizeof(NcmMetaRecord)); - - Result rc = serviceIpcDispatch(&db->s); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - } - - return rc; +Result ncmContentMetaDatabaseSet(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, const void* data, u64 data_size) { + return serviceDispatchIn(&db->s, 0, *key, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { data, data_size } }, + ); } -Result ncmContentMetaDatabaseGetContentIdByType(NcmContentMetaDatabase* db, NcmContentType contentType, const NcmMetaRecord* record, NcmNcaId* out) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - u32 content_type; - u32 padding; - NcmMetaRecord meta_record; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 3; - raw->content_type = contentType; - raw->padding = 0; - memcpy(&raw->meta_record, record, sizeof(NcmMetaRecord)); - - Result rc = serviceIpcDispatch(&db->s); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - NcmNcaId nca_id; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - memcpy(out, &resp->nca_id, sizeof(NcmNcaId)); - } - } - - return rc; +Result ncmContentMetaDatabaseGet(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, u64* out_size, void* out_data, u64 out_data_size) { + return serviceDispatchInOut(&db->s, 1, *key, *out_size, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { out_data, out_data_size } }, + ); } -Result ncmContentMetaDatabaseListContentInfo(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u32 index, NcmContentRecord* contentRecordsOut, size_t contentRecordsBufSize, u32* numEntriesRead) { - IpcCommand c; - ipcInitialize(&c); - ipcAddRecvBuffer(&c, contentRecordsOut, contentRecordsBufSize, BufferType_Normal); - - struct { - u64 magic; - u64 cmd_id; - u32 index; - NcmMetaRecord meta_record; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 4; - raw->index = index; - memcpy(&raw->meta_record, record, sizeof(NcmMetaRecord)); - - Result rc = serviceIpcDispatch(&db->s); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 entries_read; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - if (numEntriesRead) *numEntriesRead = resp->entries_read; - } - } - - return rc; +Result ncmContentMetaDatabaseRemove(NcmContentMetaDatabase* db, const NcmContentMetaKey *key) { + return serviceDispatchIn(&db->s, 2, *key); } -Result ncmContentMetaDatabaseList(NcmContentMetaDatabase* db, u32 titleType, u64 titleIdExact, u64 titleIdLow, u64 titleIdHigh, NcmMetaRecord* metaRecordsOut, size_t metaRecordsBufSize, u32* numEntriesWritten, u32* numEntriesTotal) { - IpcCommand c; - ipcInitialize(&c); - ipcAddRecvBuffer(&c, metaRecordsOut, metaRecordsBufSize, BufferType_Normal); - - struct { - u64 magic; - u64 cmd_id; - u32 titleType; - u64 titleIdExact; - u64 titleIdLow; - u64 titleIdHigh; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 5; - raw->titleType = titleType; - raw->titleIdExact = titleIdExact; - raw->titleIdLow = titleIdLow; - raw->titleIdHigh = titleIdHigh; - - Result rc = serviceIpcDispatch(&db->s); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 numEntriesTotal; - u32 numEntriesWritten; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - if (numEntriesTotal) - *numEntriesTotal = resp->numEntriesTotal; - if (numEntriesWritten) - *numEntriesWritten = resp->numEntriesWritten; - } - } - - return rc; +Result ncmContentMetaDatabaseGetContentIdByType(NcmContentMetaDatabase* db, NcmNcaId* out_content_id, const NcmContentMetaKey* key, NcmContentType type) { + const struct { + u8 type; + u8 padding[7]; + NcmContentMetaKey key; + } in = { type, {0}, *key }; + return serviceDispatchInOut(&db->s, 3, in, *out_content_id); } -Result ncmContentMetaDatabaseGetLatestContentMetaKey(NcmContentMetaDatabase* db, u64 titleId, NcmMetaRecord* out) { - IpcCommand c; - ipcInitialize(&c); - +Result ncmContentMetaDatabaseListContentInfo(NcmContentMetaDatabase* db, u32* out_entries_written, NcmContentInfo* out_info, size_t out_info_size, const NcmContentMetaKey* key, u32 start_index) { + const struct { + u32 start_index; + NcmContentMetaKey key; + } in = { start_index, *key }; + return serviceDispatchInOut(&db->s, 4, in, *out_entries_written, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { out_info, out_info_size } }, + ); +} +Result ncmContentMetaDatabaseList(NcmContentMetaDatabase* db, u32* out_entries_total, u32* out_entries_written, NcmContentMetaKey* out_keys, size_t out_keys_size, NcmContentMetaType meta_type, u64 application_title_id, u64 title_id_min, u64 title_id_max, NcmContentInstallType install_type) { + const struct { + u8 meta_type; + u8 install_type; + u16 padding; + u64 application_title_id; + u64 title_id_min; + u64 title_id_max; + } in = { meta_type, install_type, 0, application_title_id, title_id_min, title_id_max }; struct { - u64 magic; - u64 cmd_id; - u64 title_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 6; - raw->title_id = titleId; - - Result rc = serviceIpcDispatch(&db->s); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - NcmMetaRecord record; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - memcpy(out, &resp->record, sizeof(NcmMetaRecord)); - } - } - - return rc; + u32 out_entries_total; + u32 out_entries_written; + } out; + return serviceDispatchInOut(&db->s, 5, in, out, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { out_keys, out_keys_size } }, + ); } -Result ncmContentMetaDatabaseListApplication(NcmContentMetaDatabase* db, u8 filter, NcmApplicationContentMetaKey* outBuf, size_t outBufSize, u32* numEntriesWritten, u32* numEntriesTotal) { - IpcCommand c; - ipcInitialize(&c); - ipcAddRecvBuffer(&c, outBuf, outBufSize, BufferType_Normal); - - struct { - u64 magic; - u64 cmd_id; - u8 filter; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 7; - raw->filter = filter; - - Result rc = serviceIpcDispatch(&db->s); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 total_entries; - u32 entries_written; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - if (numEntriesTotal) *numEntriesTotal = resp->total_entries; - if (numEntriesWritten) *numEntriesWritten = resp->entries_written; - } - } - - return rc; +Result ncmContentMetaDatabaseGetLatestContentMetaKey(NcmContentMetaDatabase* db, NcmContentMetaKey* out_key, u64 title_id) { + return serviceDispatchInOut(&db->s, 6, title_id, *out_key); } -Result ncmContentMetaDatabaseHas(NcmContentMetaDatabase* db, const NcmMetaRecord* record, bool* out) { - IpcCommand c; - ipcInitialize(&c); - +Result ncmContentMetaDatabaseListApplication(NcmContentMetaDatabase* db, u32* out_entries_total, u32* out_entries_written, NcmApplicationContentMetaKey* out_keys, size_t out_keys_size, NcmContentMetaType meta_type) { struct { - u64 magic; - u64 cmd_id; - NcmMetaRecord meta_record; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 8; - memcpy(&raw->meta_record, record, sizeof(NcmMetaRecord)); - - Result rc = serviceIpcDispatch(&db->s); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); + u32 out_entries_total; + u32 out_entries_written; + } out; + return serviceDispatchInOut(&db->s, 7, meta_type, out, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { out_keys, out_keys_size } }, + ); +} - struct { - u64 magic; - u64 result; - bool out; - } *resp = r.Raw; +Result ncmContentMetaDatabaseHas(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* key) { + return serviceDispatchInOut(&db->s, 8, *key, *out); +} - rc = resp->result; +Result ncmContentMetaDatabaseHasAll(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* keys, size_t keys_size) { + return serviceDispatchOut(&db->s, 9, *out, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { keys, keys_size } }, + ); +} - if (R_SUCCEEDED(rc)) { - if (out) *out = resp->out; - } - } - - return rc; +Result ncmContentMetaDatabaseGetSize(NcmContentMetaDatabase* db, u64* out_size, const NcmContentMetaKey* key) { + return serviceDispatchInOut(&db->s, 10, *key, *out_size); +} + +Result ncmContentMetaDatabaseGetRequiredSystemVersion(NcmContentMetaDatabase* db, u64* out_version, const NcmContentMetaKey* key) { + return serviceDispatchInOut(&db->s, 11, *key, *out_version); +} + +Result ncmContentMetaDatabaseGetPatchId(NcmContentMetaDatabase* db, u64* out_patch_id, const NcmContentMetaKey* key) { + return serviceDispatchInOut(&db->s, 12, *key, *out_patch_id); } Result ncmContentMetaDatabaseDisableForcibly(NcmContentMetaDatabase* db) { - IpcCommand c; - ipcInitialize(&c); + return _ncmCmdNoIo(&db->s, 13); +} - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 13; - - Result rc = serviceIpcDispatch(&db->s); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - } - - return rc; +Result ncmContentMetaDatabaseLookupOrphanContent(NcmContentMetaDatabase* db, bool* out_orphaned, size_t out_orphaned_size, const NcmNcaId* content_ids, size_t content_ids_size) { + return serviceDispatch(&db->s, 14, + .buffer_attrs = { + SfBufferAttr_HipcMapAlias | SfBufferAttr_Out, + SfBufferAttr_HipcMapAlias | SfBufferAttr_In, + }, + .buffers = { + { out_orphaned, out_orphaned_size }, + { content_ids, content_ids_size }, + }, + ); } Result ncmContentMetaDatabaseCommit(NcmContentMetaDatabase* db) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 15; - - Result rc = serviceIpcDispatch(&db->s); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - } - - return rc; + return _ncmCmdNoIo(&db->s, 15); } -Result ncmContentMetaDatabaseGetAttributes(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u8* out) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - NcmMetaRecord meta_record; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 18; - memcpy(&raw->meta_record, record, sizeof(NcmMetaRecord)); - - Result rc = serviceIpcDispatch(&db->s); - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u8 out; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - if (out) *out = resp->out; - } - } - - return rc; +Result ncmContentMetaDatabaseHasContent(NcmContentMetaDatabase* db, bool* out, const NcmContentMetaKey* key, const NcmNcaId* content_id) { + const struct { + NcmNcaId content_id; + NcmContentMetaKey key; + } in = { *content_id, *key }; + return serviceDispatchInOut(&db->s, 16, in, *out); +} + +Result ncmContentMetaDatabaseListContentMetaInfo(NcmContentMetaDatabase* db, u32* out_entries_written, void* out_meta_info, size_t out_meta_info_size, const NcmContentMetaKey* key, u32 start_index) { + const struct { + u32 start_index; + u32 padding; + NcmContentMetaKey key; + } in = { start_index, 0, *key }; + return serviceDispatchInOut(&db->s, 17, in, *out_entries_written, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { out_meta_info, out_meta_info_size } }, + ); +} + +Result ncmContentMetaDatabaseGetAttributes(NcmContentMetaDatabase* db, const NcmContentMetaKey* key, u8* out) { + return serviceDispatchInOut(&db->s, 18, *key, *out); +} + +Result ncmContentMetaDatabaseGetRequiredApplicationVersion(NcmContentMetaDatabase* db, u64* out_version, const NcmContentMetaKey* key) { + if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + return serviceDispatchInOut(&db->s, 19, *key, *out_version); +} + +Result ncmContentMetaDatabaseGetContentIdByTypeAndIdOffset(NcmContentMetaDatabase* db, NcmNcaId* out_content_id, const NcmContentMetaKey* key, NcmContentType type, u8 id_offset) { + if (hosversionBefore(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + const struct { + u8 type; + u8 id_offset; + u8 padding[6]; + NcmContentMetaKey key; + } in = { type, id_offset, {0}, *key }; + return serviceDispatchInOut(&db->s, 20, in, *out_content_id); }