The CTR file system is a group of archives. Archives contain files and directories, and provide a means of accessing those files and directories.
The main steps for accessing files or directories using an archive are given below.
To access a file or directory, you must first mount an archive that has been created and formatted. Mounting refers to the act of checking the status of the archive specified by the user, securing required resources such as memory, preparing resources for use, and applying an archive name to the archive. A function specific to each type of archive must be called in order to mount a given archive. These functions have different arguments depending on the archive type, but share a common argument that represents the archive name. The archive name is used to specify a mounted archive by a name given to that archive. An archive name is made up of an ASCII character string of one to seven characters in length, but must not contain a colon (":"). Also, a dollar sign ("$") may not be used to start an archive name.
To open a file or directory, use an access class such as FileStream. Note that a path name must be specified in the initial argument to such classes. A path name is a character string of the form "<archive_name>:<archive_path>". The file position inside the archive specified by archive_name is determined based on archive_path. Many archives support a hierarchical directory structure, where directories are delimited by slashes ('/').
Archives must be unmounted when you are finished using them. Unmount allows system resources being used to maintain the mounted status of an archive to be freed. To unmount an archive, first close all files and directories in the archive in question and call the nn::fs::Unmount function, passing the archive name as an argument. From that point forward, the archive cannot be accessed, even if an attempt is made to access it by archive name.
Mounted status is disabled for archives located on removable media, such as an SD Card, when the media is removed. A ResultArchiveInvalidated type result is returned in response to attempts to access a disabled archive or file within it. To access the archive again, you must first unmount the disabled archive and then call a function for mounting it again.
CTR programs typically utilize the following archives (all optional) regardless of the application type (CARD application or SD application):
The configuration and size of these archives is determined at build time, based on content written in the RSF file. They are ready for use at time of program execution. (However, save data archives must be formatted before they can be used.) Because these archives are specific to the program, they exist together with the program as a set. Mounting is always enabled and cannot be disabled.
Furthermore,
can be used. Since expanded save data archives exist independently from programs, they are specified using a unique ID called an "expanded save data ID." Any expanded save data ID used by a program must be explicitly listed in the RSF file. Also, more than one program can share the same expanded save data. Because expanded save data archives are located on an SD Card, they can be disabled (even while mounted) if the SD Card is removed.
There are several other types of archives that programs can use.
The "archive" concept is used for the following purposes.
Since files and directories belong to an archive, they must first be mounted by applying an archive name to the archive, and then opened by specifying that archive name and a path name inside the archive. Archives must be closed (unmounted) when you are finished with them, but all open files and directories inside the archive must be closed first.
In order to use an expanded save data archive, for example, you must create an expanded save data archive first, before mounting, by calling a special function for creating these archives. You can then create files and directories inside the archive, and read and write data to/from them.
When using a save data archive, the archive region itself must exist at the time of program execution, but must be formatted by calling a special function for formatting these archives, if the archive region is not formatted.
ROM archives do not need to be created before mounting, because they always exist at the time of program execution.
Regardless of the archive type, a standardized interface is used to access files and directories once an archive is mounted. This allows functionality like debugging using a different archive, while keeping changes to a minimum.
Archives come in several types. Access characteristics and allowable operations vary for each type. The fact that there are differences is made clear by the fact that each type of archive is mounted using a special function for mounting that type. Furthermore, you can count on sharing code by using the same mounting function for archives that can be used in the same way, regardless of the application type (CARD application or SD application).
The CTR file system uses large amounts of resources, including memory, compared to a simple file system in order to achieve sufficient security and robustness. The system load is, therefore, lessened by freeing as many unnecessary resources as possible, at this time. The unit of resource allocation here is at the archive level. Conversely, if you need to access multiple files in an archive consecutively, leaving the archive open during this time can increase performance because the amount of time to access data is decreased.
For expanded save data on a removable media (such as an SD Card), if the user removes the media, the data actually accessed may become data on different media entirely (even if mounted using the same parameters and same function for mounting). The file system, therefore, disables the archive when the media containing the archive is removed. It then can no longer be accessed, as-is, even if the media is re-inserted. You must first unmount the original archive, and then mount it again, if you wish to re-enable access. Disabling access due to media removal is performed at the archive level.
In the case of duplicated save data archives, data can be committed by calling a special function for committing data. Conversely, if an archive is unmounted by calling the commit function, data will not be committed, and the status of data when the archive was mounted will be restored. Data is either committed or rolled back at the archive level.
ROM archives are read-only archives for referencing a program-specific ROMFS created at build time. Because ROM archives are guaranteed to already exist when the program starts, they can be used merely by mounting them, without having to create the archive inside the program.
To create a ROM archive at build time, specify Rom/HostRoot and Rom/Reject (optional) in the RSF file. For details, see the ctr_makerom reference.
To mount a ROM archive, call the nn::fs::MountRom function. You must specify a working memory region when calling this function, because a certain amount of memory is required to work with the ROM archive. The required size of this working memory region can be obtained using the nn::fs::GetRomRequiredMemorySize function.
The number of files and directories that can be opened inside the ROM archive can be specified by argument when mounting. As long as the size returned by the nn::fs::GetRomRequiredMemorySize function is acceptable to the program developer, there is no limit on the number of files and directories in a ROM archive that can be opened. Be sure to specify the required number.
You can also select whether or not to cache file management information for the ROM archive in memory. The value returned by the nn::fs::GetRomRequiredMemorySize function varies, depending on this specification. The greater the number of files and directories inside the archive, the larger the size returned. The time required to open files and directories can be reduced by using caching. Caching is recommended in cases where you may be frequently opening a large number of detailed files. Conversely, there is no advantage to caching in cases where only a few files are being handled and open files will remain open for a long period of time. The only advantage to caching, is when opening files or directories for access using file management information. Once a file is open, there is no difference in performance in reading the data after that point.
A save data archive is used to access a program-specific save data region that can be read and written. The physical location of this type of archive varies depending on the program type. It is represented by a file on the CARD for CARD applications, and on the SD Card for SD applications. However, developers do not need to be concerned about this difference, because it is handled by the system. The save data region is guaranteed to be placed in the correct position by the system, at the time a program starts. This type of archive is not created during program execution. The content of save data is protected by the system. The data is guaranteed to be free of illegal tampering, if it can be accessed without an error.
The size of the save data region is determined by information given in the RSF file specified at build time. For details, see the ctr_makerom reference.
To mount a save data archive, call the nn::fs::MountSaveData function with only the argument for the archive name. Calls to this function will fail if save data has not been formatted, such as, when using the save data for the first time. The save data region must, therefore, be formatted using the nn::fs::FormatSaveData function. For details on handling this type of archive, see Error Handling.
You can specify the number of files and directories that can be created inside a save data archive when it is formatted. Be sure to specify a large enough number, because you will not be able to create any more files or directories than specified here.
You can also select whether to duplicate save data when it is formatted. The amount of data that can actually be used is about half, in the case of duplicated save data, compared to unduplicated data. However, the data is guaranteed to be free of corruption, as long as it has not been intentionally altered (such as by directly editing data on the SD Card using a PC). Conversely, data may be corrupted in the case of unduplicated data, if the power fails or media is removed while writing data. Nintendo recommends that you use duplicated save data, as long as there is no problem with save data capacity.
Use the Save Data File System Capacity Calculation Sheet to calculate the data size that can be used for save data. Note, however, that save data files are handled in blocks of 512 bytes each. Note that even if the actual file size is only 1 byte, the capacity required to maintain it will be 512 bytes.
Operations performed on a duplicated save data archive (creating and deleting files, writing data to files, and so forth) are not enabled on actual storage until the nn::fs::CommitSaveData function is called on the archive name in question. If an archive is unmounted without calling the nn::fs::CommitSaveData function and then the save data archive is mounted again, status will be rolled back to the same file and directory structure in place the last time the archive was mounted, and file contents will be identical to what they were at that time. In general, be sure to call the nn::fs::CommitSaveData function before showing the user a message such as "Save complete". If you want to intentionally roll back the status of an archive, you can do so by unmounting the archive without calling the nn::fs::CommitSaveData function.
The first 512 byes of a save data archive file newly created using nn::fs::TryCreateFile are guaranteed to be padded with zeroes. If a subsequent attempt is made to read an area of this file to which data has not yet been written, either a ResultVerificationFailed type error will be returned or an undefined value will be read.
Every program maintains a save data region, and although there are restrictions, it is possible for a given program to access the save data in the possession of other programs. Those other programs are recognized by their unique ID and variation.
To mount the save data that is in the possession of another program, call the nn::fs::MountSaveData function to get that unique ID and variation. The only unique IDs that can be specified at this time are the unique IDs specified in the RSF files of the programs that call this function call. For details, see AccessControlInfo/OtherUserSaveDataIdN and AccessControlInfo/UseOtherVariationSaveData in the ctr_makerom reference.
When a program acts to access the save data of another program, there is no ironclad guarantee that the save data actually exists. Moreover, there may be times when the media containing the target save data gets removed while the save data is being accessed. So be aware of the need for error handling for other errors than those that can occur when a program accesses its own save data. For details on how to handle errors, see Error Handling.
As for other specifications, they are the same as for a program's own save data archives. In the case of duplicated save data, you need to call the nn::fs::CommitSaveData function when writing it.
An expanded save data archive is a read/write archive created on an SD Card. In order to use an extended save data archive, the program must explicitly create the archive. The content of expanded save data is protected by the system. The data is guaranteed to be free of illegal tampering, if it can be accessed without an error.
Expanded save data is identified by an expanded save data ID. Expanded save data that can be manipulated by the application is limited to that data specified using AccessControlInfo/ExtSaveDataNumber in the RSF file specified at build time. Other expanded save data cannot be altered. For details, see the ctr_makerom reference.
To mount an extended save data archive, call the nn::fs::MountExtSaveData function. Mounting will fail if the archive does not exist. In this case, an archive must be created using the nn::fs::CreateExtSavedData function. For details on handling this type of archive, see Error Handling.
As a limitation on the operations that can be performed on files in an expanded save data archive, the size of a file cannot be changed. The size of such a file therefore cannot be changed using the nn::fs::FileStream::TrySetSize function, or automatically extended when using the nn::fs::FileStream::TryWrite function. Furthermore, you cannot create files using a function like nn::fs::FileStream::TryInitialize, that does not allow a size specification. You must always create files ahead of time, with a size specification, using the nn::fs::TryCreateFile function.
Because meta data or other data may be added to an expanded save data archive file, SD Card memory is used when the amount of data exceeds the actual usable size. Use the Save Data File System Capacity Calculation Sheet to determine how much space to actually procure when creating a file.
The first 512 byes of a save data archive file newly created using nn::fs::TryCreateFile is guaranteed to be padded with zeroes. If a subsequent attempt is made to read an area of this file to which data has not yet been written, either a ResultVerificationFailed type error will be returned, or an undefined value will be read.
An expanded save data archive may be disabled if the SD Card is unintentionally removed, because it is located on an SD Card, which is removable media. Data may be corrupted at this time. Furthermore, the possibility of unwanted operations by another program increases, because the same expanded save data can be shared by more than one program.Be sure to perform careful error handling when dealing with expanded save data.
It takes a bit longer to perform a given operation on an expanded save data archive, due to needing to handle a large amount of meta data. Write times may be particularly excessive, depending on the SD Card type.Make sure to perform a thorough performance check during development.
SDMC archives are used to directly reference the FAT file system on SD Cards during debugging.
SDMC archives cannot be accessed by production versions of software, because they are intended for debugging purposes only. Furthermore, you must list Debug under AccessControlInfo/FileSystemAccess in the RSF file, even to use this type of archive during debugging. For details, see the ctr_makerom reference.
To mount an SDMC archive, call the nn::fs::MountSdmc function, while the SD Card is inserted. Archives are disabled if the SD Card is removed. Re-mounting then becomes necessary.
A write-only SDMC archive accesses the FAT file system on an SD Card in write-only mode. This type of archive is essentially used in the same manner as an SDMC archive.
You must list DirectSdmcWrite under AccessControlInfo/FileSystemAccess in the RSF file, in order to use a write-only SDMC archive. For details, see the ctr_makerom reference.
An HIO archive views the directory specified on the host PC, and everything in it as a single archive. Features of the HIO library can be used to work with these archives using the common interface of the FS library. Since the HIO library is used to implement this type of archive, they are subject to the limitations of the HIO library.
To mount an HIO archive, first initialize the HIO library using the nn::hio::CTR::Initialize function. Then call nn::fs::hio::MountHioArchive, while passing the directory path name of the host PC as an argument.
HIO archives cannot be accessed by production versions of software, because they are intended for development and debugging purposes only. Also, note that values returned at time of access for return values, such as Result, are not the same as for other archives. Finally, behavior may change as the SDK and debugger software change. Only use this type of archive to supplement development and debugging.
| Read (R) Write (W) | Changing Sizes | Creating files | Opening multiple files simultaneously | |
|---|---|---|---|---|
| ROM Archives | R | Impossible | Impossible | Only when all read-only |
| Save Data Archives | R/W | Possible | FileStreamFileOutputStreamnn::fs::TryCreateFile | Only when all read-only |
| Expanded Save Data Archives | R/W | Impossible | nn::fs::TryCreateFile only | Only when all read-only |
| SDMC Archives | R/W | Possible | FileStreamFileOutputStreamnn::fs::TryCreateFile | Possible |
| Write-only SDMC Archives | W | Possible | FileStreamFileOutputStreamnn::fs::TryCreateFile | Impossible |
| HIO Archives | R/W | Possible | FileStreamFileOutputStreamnn::fs::TryCreateFile | (Operation not guaranteed) |
| Filename Length | Path Length (See Note 1) | Case-sensitive | Forbidden characters | |
|---|---|---|---|---|
| ROM Archives | - | 253 characters | Yes | (※3) |
| Save Data Archives | 16 characters | 253 characters | Yes | (※2)(※3) |
| Expanded Save Data Archives | 16 characters | 248 characters | Yes | (※2)(※3) |
| SDMC Archives | 253 characters (See Note 4) | 253 characters (See Note 4) | No | (※3) |
| Write-only SDMC Archives | 253 characters (See Note 4) | 253 characters (See Note 4) | No | (※3) |
| HIO Archives | Comply with host PC restrictions | |||
\ / : * ? " < > |
CON, PRN, NUL, AUX, LPT1, LPT2, LPT3, LPT4, COM1, COM2, COM3, COM4 con, prn, nul, aux, lpt1, lpt2, lpt3, lpt4, com1, com2, com3, com4
| Specified entry name | Actual entry name on which operations are performed (only for SDMC archives) |
|---|---|
| EntryName | EntryName |
| _EntryName | EntryName |
| __EntryName | EntryName |
| Entry_Name | Entry_Name |
| EntryName_ | EntryName |
| _Entry_Name_ | Entry_Name |
, ; = + [ ] and single-byte space from the list of unusable characters.CONFIDENTIAL