NCM services: Difference between revisions
No edit summary |
No edit summary |
||
Line 290: | Line 290: | ||
| 0 || [[#GeneratePlaceHolderId]] || Returns a random UUID for the Content Storage. | | 0 || [[#GeneratePlaceHolderId]] || Returns a random UUID for the Content Storage. | ||
|- | |- | ||
| 1 || CreatePlaceHolder || Takes | | 1 || CreatePlaceHolder || Takes a [[#ContentId]], a [[#PlaceHolderId]], and a u64 filesize. | ||
|- | |- | ||
| 2 || DeletePlaceHolder || Takes a [[# | | 2 || DeletePlaceHolder || Takes a [[#PlaceHolderId]]. | ||
|- | |- | ||
| 3 || HasPlaceHolder || Takes a [[# | | 3 || HasPlaceHolder || Takes a [[#PlaceHolderId]] and returns an output u8 bool. | ||
|- | |- | ||
| 4 || WritePlaceHolder || Takes a [[# | | 4 || WritePlaceHolder || Takes a [[#PlaceHolderId]], a u64-offset, and type-0x5 input buffer. Writes the buffer to the file for the placeholder path at the specified offset. | ||
|- | |- | ||
| 5 || Register || Takes | | 5 || Register || Takes a [[#ContentId]] and a [[#PlaceHolderId]], no output. Moves the Placeholder NCA content to the registered NCA path. | ||
|- | |- | ||
| 6 || Delete || Takes a [[# | | 6 || Delete || Takes a [[#ContentId]]. | ||
|- | |- | ||
| 7 || Has || Takes a [[# | | 7 || Has || Takes a [[#ContentId]]. | ||
|- | |- | ||
| 8 || GetPath || Takes a [[# | | 8 || GetPath || Takes a [[#ContentId]] and a type-0x1A output buffer containing a [[#Path]]. | ||
|- | |- | ||
| 9 || GetPlaceHolderPath || Takes a [[# | | 9 || GetPlaceHolderPath || Takes a [[#PlaceHolderId]] and a type-0x1A output buffer containing a [[#Path]]. | ||
|- | |- | ||
| 10 || CleanupAllPlaceHolder || Deletes and re-creates the Placeholder directory. | | 10 || CleanupAllPlaceHolder || No input/output. Deletes and re-creates the Placeholder directory. | ||
|- | |- | ||
| 11 || ListPlaceHolder || This is like [[#GetNumberOfRegisteredEntries]], but for the Placeholder directory. | | 11 || ListPlaceHolder || This is like [[#GetNumberOfRegisteredEntries]], but for the Placeholder directory. | ||
Line 318: | Line 318: | ||
| 14 || [[#GetSizeFromContentId]] || | | 14 || [[#GetSizeFromContentId]] || | ||
|- | |- | ||
| 15 || DisableForcibly || Closes/Flushes all resources for the storage, and causes all future IPC commands to the current session to return error 0xC805. | | 15 || DisableForcibly || No input/output. Closes/Flushes all resources for the storage, and causes all future IPC commands to the current session to return error 0xC805. | ||
|- | |- | ||
| 16 || [2.0.0+] RevertToPlaceHolder || Takes | | 16 || [2.0.0+] RevertToPlaceHolder || Takes a [[#ContentId]], a [[#ContentId]], and a [[#PlaceHolderId]], no output. Creates the registered directory NCA path, and renames the placeholder path to the registered NCA path. | ||
|- | |- | ||
| 17 || [2.0.0+] SetPlaceHolderSize || Takes a [[# | | 17 || [2.0.0+] SetPlaceHolderSize || Takes a [[#PlaceHolderId]], and a s64 size, no output. | ||
|- | |- | ||
| 18 || [2.0.0+] [[#ReadContentIdFile]] || | | 18 || [2.0.0+] [[#ReadContentIdFile]] || | ||
Line 330: | Line 330: | ||
| 20 || [2.0.0+] [[#GetRightsIdFromContentId]] || | | 20 || [2.0.0+] [[#GetRightsIdFromContentId]] || | ||
|- | |- | ||
| 21 || [2.0.0+] WriteContentForDebug || Takes a [[# | | 21 || [2.0.0+] WriteContentForDebug || Takes a [[#ContentId]], a u64 offset, and a type-0x5 input buffer. On debug units, writes the buffer to the NCA's registered path. On retail units, this just aborts. | ||
|- | |- | ||
| 22 || [2.0.0+] GetFreeSpaceSize || Gets free space for the storage. | | 22 || [2.0.0+] GetFreeSpaceSize || Gets free space for the storage. | ||
Line 346: | Line 346: | ||
==== GeneratePlaceHolderId ==== | ==== GeneratePlaceHolderId ==== | ||
Generates a random [[# | Generates a random [[#PlaceHolderId]] for use as a placeholder. | ||
Calls nn::util::GenerateUuid(), which internally calls nn::os::GenerateRandomBytes(16); | Calls nn::util::GenerateUuid(), which internally calls nn::os::GenerateRandomBytes(16); | ||
Line 354: | Line 354: | ||
==== ListContentId==== | ==== ListContentId==== | ||
Takes an output buffer, | Takes an output buffer, s32 offset and gets all entries starting at that offset. | ||
Returns number of entries read. | Returns number of entries read. | ||
Each entry is a [[# | Each entry is a [[#ContentId]]. | ||
The total read entries is exactly the same as the number of "<hex>.nca" directories in the storage FS(or at least under the "registered" directory?). | The total read entries is exactly the same as the number of "<hex>.nca" directories in the storage FS(or at least under the "registered" directory?). | ||
==== GetSizeFromContentId ==== | ==== GetSizeFromContentId ==== | ||
Takes a [[# | Takes a [[#ContentId]] as input. | ||
Returns the total size readable by [[#ReadContentIdFile]]. This is the same as the size-field in the [[NAX0]] "< | Returns the total size readable by [[#ReadContentIdFile]]. This is the same as the size-field in the [[NAX0]] "<ContentId>.nca/00" file. | ||
==== ReadContentIdFile ==== | ==== ReadContentIdFile ==== | ||
Takes | Takes a type-0x6 output buffer, a [[#ContentId]] as input, and a s64 file offset. | ||
Reads plaintext NCA file contents from the Registered path for the | Reads plaintext NCA file contents from the Registered path for the ContentId. | ||
==== GetRightsIdFromPlaceHolderId ==== | ==== GetRightsIdFromPlaceHolderId ==== | ||
Takes a | Takes a [[#PlaceHolderId]], returns a [[#RightsId]]. | ||
Gets the Rights ID for the [[#PlaceHolderId]]'s placeholder path. | |||
Gets the Rights ID for the [[# | |||
==== GetRightsIdFromContentId ==== | ==== GetRightsIdFromContentId ==== | ||
Takes a | Takes a [[#ContentId]], returns a [[#RightsId]]. | ||
Gets the Rights ID for the [[#ContentId]]'s registered path | |||
Gets the Rights ID for the [[# | |||
=== IContentMetaDatabase === | === IContentMetaDatabase === | ||
Line 398: | Line 394: | ||
| 2 || Remove || Takes a [[#ContentMetaKey|Content Meta Key]], and removes the associated record. | | 2 || Remove || Takes a [[#ContentMetaKey|Content Meta Key]], and removes the associated record. | ||
|- | |- | ||
| 3 || GetContentIdByType || Takes a [[#ContentMetaKey|Content Meta Key]] and a u8 [[#ContentMetaType|Content Meta Type]]. Returns a [[# | | 3 || GetContentIdByType || Takes a [[#ContentMetaKey|Content Meta Key]] and a u8 [[#ContentMetaType|Content Meta Type]]. Returns a [[#ContentId]]. | ||
|- | |- | ||
| 4 || ListContentInfo || Takes a type-6 buffer to write [[CNMT#Content_records|Content Record]] entries to, a [[#ContentMetaKey|Content Meta Key]], and a | | 4 || ListContentInfo || Takes a type-6 buffer to write [[CNMT#Content_records|Content Record]] entries to, a [[#ContentMetaKey|Content Meta Key]], and a s32 index into the Content Record entries to start copying from. Returns a s32 entries_read. | ||
|- | |- | ||
| 5 || List || Takes a type-6 buffer to write [[#ContentMetaKey|Content Meta Key]]s to, a u32 [[#ContentMetaType|Content Meta Type]], a u64 TID, a u64 TID_LOW, and u64 TID_HIGH. Writes into the buffer all Content Meta Keys with low <= record->title_id <= high, and record->type == type. Returns | | 5 || List || Takes a type-6 buffer to write [[#ContentMetaKey|Content Meta Key]]s to, a u32 [[#ContentMetaType|Content Meta Type]], a u64 TID, a u64 TID_LOW, and u64 TID_HIGH. Writes into the buffer all Content Meta Keys with low <= record->title_id <= high, and record->type == type. Returns s32 numEntriesTotal, numEntriesWritten. Additionally requires record->title_id == TID, if record->type is Application, Patch, Add-On, or Delta, otherwise, you can pass 0 for type to ignore the type and list them all in the range. | ||
|- | |- | ||
| 6 || GetLatestContentMetaKey || Takes a u64 title id, and returns the [[#ContentMetaKey|Content Meta Key]] with the highest version field for that title id. | | 6 || GetLatestContentMetaKey || Takes a u64 title id, and returns the [[#ContentMetaKey|Content Meta Key]] with the highest version field for that title id. | ||
Line 408: | Line 404: | ||
| 7 || [[#ListApplication]] || | | 7 || [[#ListApplication]] || | ||
|- | |- | ||
| 8 || Has || Takes a [[#ContentMetaKey|Content Meta Key]] and returns whether that record is present in the database. | | 8 || Has || Takes a [[#ContentMetaKey|Content Meta Key]] and returns an output u8 bool indicating whether that record is present in the database. | ||
|- | |- | ||
| 9 || HasAll || Takes a type- | | 9 || HasAll || Takes a type-0x5 input buffer containing an array of [[#ContentMetaKey|Content Meta Key]], and returns whether all of those records are present in the database. | ||
|- | |- | ||
| 10 || GetSize || Takes a [[#ContentMetaKey|Content Meta Key]], and returns the size of the associated [[CNMT#Content_records|Content Records]]. | | 10 || GetSize || Takes a [[#ContentMetaKey|Content Meta Key]], and returns the size of the associated [[CNMT#Content_records|Content Records]]. | ||
Line 420: | Line 416: | ||
| 13 || DisableForcibly || Closes the meta database, and causes all future IPC commands to the current session to return error 0xDC05. | | 13 || DisableForcibly || Closes the meta database, and causes all future IPC commands to the current session to return error 0xDC05. | ||
|- | |- | ||
| 14 || [[#LookupOrphanContent]] || Takes a type-6 byte buffer, and a type-5 buffer of [[# | | 14 || [[#LookupOrphanContent]] || Takes a type-6 byte buffer, and a type-5 buffer of [[#ContentId]]s. | ||
|- | |- | ||
| 15 || Commit || Flushes the in-memory database to savedata. | | 15 || Commit || Flushes the in-memory database to savedata. | ||
|- | |- | ||
| 16 || HasContent || Takes a [[#ContentMetaKey|Content Meta Key]] and an [[# | | 16 || HasContent || Takes a [[#ContentMetaKey|Content Meta Key]] and an [[#ContentId]]. Returns whether the content records for that content meta key contain the ContentId. | ||
|- | |- | ||
| 17 || ListContentMetaInfo || Takes a type-6 [[#ContentMetaKey|Content Meta Key]] output buffer, a | | 17 || ListContentMetaInfo || Takes a type-6 [[#ContentMetaKey|Content Meta Key]] output buffer, a s32 offset into that buffer, and an input [[#ContentMetaKey|Content Meta Key]]. | ||
|- | |- | ||
| 18 || GetAttributes || Takes a [[#ContentMetaKey|Content Meta Key]], and returns u8 from ContentRecords + 6. | | 18 || GetAttributes || Takes a [[#ContentMetaKey|Content Meta Key]], and returns u8 from ContentRecords + 6. | ||
Line 442: | Line 438: | ||
This function takes in a type 6 buffer to write entries to, and a u8 "filter" [[#Title_Types|type]]. If filter is zero, all update records will be copied to to the output buffer (space permitting). Otherwise, only titles with type == filter_type will be copied to the output buffer. | This function takes in a type 6 buffer to write entries to, and a u8 "filter" [[#Title_Types|type]]. If filter is zero, all update records will be copied to to the output buffer (space permitting). Otherwise, only titles with type == filter_type will be copied to the output buffer. | ||
This func returns a | This func returns a s32 num_entries_total, and a s32 num_entries_written. | ||
==== ReadEntryMetaRecords ==== | ==== ReadEntryMetaRecords ==== | ||
Takes a type-6 [[#ContentMetaKey|Content Meta Key]] output buffer, a | Takes a type-6 [[#ContentMetaKey|Content Meta Key]] output buffer, a s32 offset into that buffer, and an input [[#ContentMetaKey|Content Meta Key]] entry. Returns a s32 for total_read_entries. | ||
Reads the content meta keys stored in the entry's content records into the output buffer. | Reads the content meta keys stored in the entry's content records into the output buffer. | ||
Line 452: | Line 448: | ||
==== LookupOrphanContent ==== | ==== LookupOrphanContent ==== | ||
Takes a type-6 byte buffer, and a type- | Takes a type-6 byte buffer, and a type-0x5 buffer containing an array of [[#ContentId]]. | ||
This function was stubbed to return 0xDC05 in [[2.0.0]]. | This function was stubbed to return 0xDC05 in [[2.0.0]]. | ||
On 1.0.0: Initialized the output buffer to all 1s. Then, for each [[# | On 1.0.0: Initialized the output buffer to all 1s. Then, for each [[#ContentId]] in the input buffer, it checks if that ContentId is present anywhere in the database, and if so writes 0 to the corresponding output byte. | ||
In pseudocode, the function basically does the following: | In pseudocode, the function basically does the following: | ||
Line 463: | Line 459: | ||
out_buf[i] = 1 | out_buf[i] = 1 | ||
for i, | for i, ContentId in ContentId: | ||
if is_present_in_database( | if is_present_in_database(ContentId): | ||
out_buf[i] = 0 | out_buf[i] = 0 | ||
=== | === ContentId === | ||
This is | This is "nn::ncm::ContentId". | ||
The | This is a 0x10-byte entry. This is originally from the hex portion of "<hex>.nca" directory-names from this storage FS(like [[SD_Filesystem|SD]]). | ||
The ContentId is the same as the first 0x10-bytes from the calculated SHA256 hash, from hashing the entire output from [[#ReadContentIdFile]]. | |||
=== PlaceHolderId === | |||
This is "nn::ncm::PlaceHolderId". | |||
This is the same as [[#ContentId]], except this is for placeholder content and originates from [[#GeneratePlaceHolderId]]. | |||
== ContentInstallType == | == ContentInstallType == | ||
Line 573: | Line 576: | ||
|- | |- | ||
| 0x9 || 0x7 || Padding | | 0x9 || 0x7 || Padding | ||
|} | |||
== Path == | |||
This is "nn::ncm::Path". | |||
This is a 0x300-byte structure, which contains a [[Filesystem_services#ContentPath|Content Path]]. | |||
== RightsId == | |||
This is "nn::ncm::RightsId". This is a 0x10-byte struct. [3.0.0+] This is a 0x18-byte struct. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset | |||
! Size | |||
! Description | |||
|- | |||
| 0x0 || 0x10 || FS Rights ID | |||
|- | |||
| 0x10 || 0x1 || [3.0.0+] key_generation | |||
|- | |||
| 0x11 || 0x7 || [3.0.0+] Padding | |||
|} | |} | ||