libnx/nx/source/services/ncm.c

609 lines
13 KiB
C

#include <string.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;
return smGetService(&g_ncmSrv, "ncm");
}
void ncmExit(void) {
if (atomicDecrement64(&g_ncmRefCnt) == 0) {
serviceClose(&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;
}
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;
}
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 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 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);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 size;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*out = resp->size;
}
}
return rc;
}
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;
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);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
}
Result ncmContentStorageGetRightsIdFromContentId(NcmContentStorage* cs, const NcmNcaId* ncaId, NcmRightsId* rightsIdOut, u32* keyGenerationOut) {
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 = 20;
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;
NcmRightsId rights_id;
u32 key_generation;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (rightsIdOut) memcpy(rightsIdOut, &resp->rights_id, sizeof(NcmRightsId));
if (keyGenerationOut) *keyGenerationOut = resp->key_generation;
}
}
return rc;
}
Result ncmContentMetaDatabaseSet(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u64 contentRecordSize, NcmContentRecord* contentRecords) {
IpcCommand c;
ipcInitialize(&c);
ipcAddSendBuffer(&c, contentRecords, contentRecordSize, BufferType_Normal);
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);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
}
Result ncmContentMetaDatabaseGet(NcmContentMetaDatabase* db, const NcmMetaRecord* record, u64 contentRecordSize, NcmContentRecord* contentRecordsOut, u64* sizeRead) {
IpcCommand c;
ipcInitialize(&c);
ipcAddRecvBuffer(&c, contentRecordsOut, contentRecordSize, 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;
}
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 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 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 ncmContentMetaDatabaseGetLatestContentMetaKey(NcmContentMetaDatabase* db, u64 titleId, NcmMetaRecord* out) {
IpcCommand c;
ipcInitialize(&c);
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;
}
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 ncmContentMetaDatabaseHas(NcmContentMetaDatabase* db, const NcmMetaRecord* record, bool* 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 = 8;
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;
bool out;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (out) *out = resp->out;
}
}
return rc;
}
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;
}