Extdata: Difference between revisions
→Tools: old extdata_tool is a dead link; Add new tools |
TimmSkiller (talk | contribs) |
||
| (18 intermediate revisions by 8 users not shown) | |||
| Line 29: | Line 29: | ||
* Device file with <code>SubDirID = SubFileID = 00000000</code> doesn't exist. Other ID combinations can exists. | * Device file with <code>SubDirID = SubFileID = 00000000</code> doesn't exist. Other ID combinations can exists. | ||
* Device file with <code>SubDirID = 00000000</code> and <code>SubFileID = 00000001</code> is the VSXE metadata file and must exist. | * Device file with <code>SubDirID = 00000000</code> and <code>SubFileID = 00000001</code> is the VSXE metadata file and must exist. | ||
* Other files, besides <code>Quota.dat</code> and <code>00000000/00000001</code>, are normal sub files, are these device files one-to-one correspond to virtual files. | * Other files, besides <code>Quota.dat</code> and <code>00000000/00000001</code>, are normal sub files, are these device files one-to-one correspond to virtual files. They contain raw virtual file data in the DIFF inner content. | ||
* <code>SubDirID = 00000000</code> is usually the only one device directory that can be seen. See [[#Device Directory Capacity]] for more information. | * <code>SubDirID = 00000000</code> is usually the only one device directory that can be seen. See [[#Device Directory Capacity]] for more information. | ||
== Quota File == | == Quota File == | ||
The inner data of <code>Quota.dat</code> is 0x48 bytes with the following format. The | The inner data of <code>Quota.dat</code> is 0x48 bytes with the following format. The file applies limits to the file system, similar to quotas for other file systems. | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
| Line 47: | Line 47: | ||
| 0x04 | | 0x04 | ||
| 4 | | 4 | ||
| | | Version, always 0x30000 | ||
|- | |- | ||
| 0x08 | | 0x08 | ||
| 4 | | 4 | ||
| 0x1000 | | Block size. Always 0x1000. | ||
|- | |- | ||
| 0x0C | | 0x0C | ||
| 4 | | 4 | ||
| Always 126 | | Maximum number of physical files in each physical directory. Always 126. See [[#Device Directory Capacity]] for more information. | ||
|- | |- | ||
| | | 0x10 | ||
| 4 | | 4 | ||
| | | padding | ||
|- | |- | ||
| | | 0x14 | ||
| 8 | | 8 | ||
| | | Block count (capacity) | ||
|- | |- | ||
| 0x1C | | 0x1C | ||
| 8 | | 8 | ||
| | | Number of remaining blocks | ||
|- | |- | ||
| | | 0x24 | ||
| 4 | | 4 | ||
| | | Current pending operation | ||
{| class="wikitable" border="1" | |||
! Value !! Description | |||
|- | |- | ||
| | | 0 || No pending operation. | ||
| | |||
| | |||
|- | |- | ||
| | | 1 || Physical file deletion is pending | ||
| | |||
| | |||
|- | |- | ||
| | | 2 || Physical file resize is pending (redundant, see below note) | ||
| | |||
| | |||
|- | |- | ||
| | | 3 || Physical subdirectory creation is pending | ||
| | |||
| | |||
|- | |- | ||
| | | 4 || Physical subdirectory deletion is pending | ||
|} | |||
| | |||
| | |||
|- | |- | ||
| | | 0x28 | ||
| 8 | | 8 | ||
| | | Number of available blocks (from offset 0x1C) at the time the above operation was queued (if any). | ||
|- | |- | ||
| | | 0x30 | ||
| 8 | | 8 | ||
| File | | File ID that is related to the above operation info. Same as the one in [[Inner_FAT#Filesystem Header|Filesystem Header]] | ||
|- | |- | ||
| | | 0x38 | ||
| 8 | | 8 | ||
| File | | File size of the above mentioned file. For resize, this is interpreted as the old file size. | ||
|- | |- | ||
| | | 0x40 | ||
| 8 | | 8 | ||
| | | For resize operations, the new file size to apply for the above mentioned file. | ||
|- | |- | ||
|} | |} | ||
The quota is implemented as follows: | |||
= | * During initial Extdata creation with [[FS:CreateExtSaveData]], the input size limit is divided by the block size (0x1000). This becomes the block count (capacity). | ||
* Each physical subdirectory (not to be confused with the inner virtual directories in the EXSV filesystem) counts one block towards the block quota. | |||
** Every 126 files, a new physical subdirectory is created. | |||
** This includes the initial physical subdirectory (00000000). | |||
* Each physical subfile (= full DIFF container for a virtual file) counts its file size (rounded up to the quota block size) in blocks towards the block quota. | |||
** This includes all initial physical subfiles, namely <code>icon</code> and the root EXSV filesystem file containing the [[Inner_FAT#Filesystem Header|Filesystem Header]]. | |||
** The physical subfile size is taken as the number of blocks corresponding to the physical subfile size rounded up to the block size as specified in the Quota.dat. | |||
* Quota.dat itself is given one block. | |||
Note: Extdata files do not support resizing after their initial creation, because each file is a separate, fixed-size DIFF container. The resize operation is therefore nonfunctional. | |||
== | == Device Directory Capacity == | ||
A device directory in an extdata (a <code><SubDirID></code> directory) seems to have a maximum number of device files it can contain. For SD extdata, this maximum number seems to be hard-coded as 126. For NAND extdata, the number is probably indicated by a field in Quota.dat, which is, again, always 126 as observed. 3DS FS tries to put all device files in the device directory <code>00000000</code> if possible, and only when more than 126 files needed to add, a second device directory <code>00000001</code> and so on are created. However, few extdata have such amount of files to store, so the behavior lacks of use cases to confirm. | |||
The number 126 is probably from some kind of other capacity of 128 with <code>"."</code> and <code>".."</code> entries reserved. It is theorized that this is to keep a FAT directory table, with 0x20 bytes for each entry, in one 0x1000 cluster. The motivation is unclear. | |||
== | == VSXE Filesystem == | ||
This | This is one variant of the [[Inner FAT|FAT filesystem]]. Please refer to its page for the description of the filesystem. In general, device file <code>00000000/00000001</code> contains the metadata of the filesystem, while other device files (except for the Quota file) contains normal sub-files | ||
Each non-dummy file entry corresponds to a device file. The path to the device file is generated by the following computation: | Each non-dummy file entry corresponds to a device file. The path to the device file is generated by the following computation: | ||
| Line 303: | Line 143: | ||
char extdata_path[...]; // ".../extdata/<ExtdataID-High>/<ExtdataId-Low>" | char extdata_path[...]; // ".../extdata/<ExtdataID-High>/<ExtdataId-Low>" | ||
char device_path[...]; // output path | char device_path[...]; // output path | ||
sprintf(device_path, "%s/%08x/%08x", extdata_path, SubDirID, SubFileID); | |||
</pre> | </pre> | ||
When mounting extdata, the unique identifier is used to match the ID stored in subfile's [[DISA and DIFF#DIFF header|DIFF header]]. If the ID doesn't match, mounting will fail. | When mounting extdata, the unique identifier is used to match the ID stored in subfile's [[DISA and DIFF#DIFF header|DIFF header]]. If the ID doesn't match, mounting will fail. | ||
| Line 435: | Line 275: | ||
| | | | ||
|- | |- | ||
| | | 00000516 | ||
| 00000517 | | 00000517 | ||
| 00000518 | | 00000518 | ||
| Line 539: | Line 379: | ||
|- | |- | ||
| ? | | ? | ||
| | | 00001132 | ||
| 00001131 | | 00001131 | ||
| Fantasy Life | | Fantasy Life | ||
| Line 551: | Line 391: | ||
|- | |- | ||
| ? | | ? | ||
| | | 000012c8 | ||
| 000012ca | | 000012ca | ||
| Mario vs. Donkey Kong: Tipping Stars | | Mario vs. Donkey Kong: Tipping Stars | ||
| Line 598: | Line 438: | ||
| | | | ||
|- | |- | ||
| | | 000016C6 | ||
| ? | | ? | ||
| 00001678 | | 00001678 | ||
| Line 611: | Line 451: | ||
|- | |- | ||
| ? | | ? | ||
| | | 0000198e | ||
| 0000198f | | 0000198f | ||
| Animal Crossing: New Leaf - Welcome amiibo | | Animal Crossing: New Leaf - Welcome amiibo | ||
| Line 622: | Line 462: | ||
| | | | ||
|- | |- | ||
| | | 00001a2c | ||
| ? | | ? | ||
| 00001a2e | | 00001a2e | ||
| Line 709: | Line 549: | ||
Empty space is filled with 0xC-long sequences of 00 00 ... 07 | Empty space is filled with 0xC-long sequences of 00 00 ... 07 | ||
== Tools == | |||
* [https://github.com/wwylele/3ds-save-tool 3ds-save-tool] - Extract/verifies extdata | * [https://github.com/wwylele/3ds-save-tool 3ds-save-tool] - Extract/verifies extdata | ||