# 標準アーカイブ (overview)

## 説明

FSライブラリは、起動したプログラムの種類に応じていくつかの標準的なアーカイブをマウントします。
ここでは、それぞれのアーカイブについておおまかな特徴を解説します。

## ROMアーカイブ

全てのプログラムは、makeromツールによって構築された1個のディレクトリツリーをDSカードのROMデータ領域内に格納しています。 このディレクトリツリーにアクセスするアーカイブがROMアーカイブであり、常に"rom:"という名前でマウントされます。 ROMに収録すべきデータはビルド時にmakeromツールで指定することができ、 NitroROMフォーマットと呼ばれるデータ構造を持ちます。 データの収録方法に関する詳細はmakeromツールのリファレンスをご参照ください。

ROMアーカイブは通常のカードアプリであれば特に問題なく使用することができますが、 それ以外のモードで起動した場合にはDSカードが実際に挿入されているかどうか定かではないため、 あたかも空のディレクトリであるかのように振舞います。 プログラムのブート種別については別途`OS_GetBootType( )`の説明をご参照ください。

DSダウンロードプレイによって起動したプログラムでカードアプリと同様にROMアーカイブを使用したい場合は、 WFSライブラリの使用をおすすめします。 このライブラリは、ダウンロード元の親機と再接続してローカル通信経由でROMデータへアクセスするためのユーティリティです。

ニンテンドーDSiでの機能拡張にともない、TWL-SDKではROMアーカイブの動作に大きな変更がありました。 以下、旧パッケージであるNITRO-SDKからの変更点をおおまかにまとめます。

- ROMデータの正当性検証
  TWLモードの環境で動作している場合にはROMデータの正当性を検証するためのハッシュチェック処理が行われます。
  これは従来と大きく異なる追加仕様であり、以下のような挙動を示す点に注意してください。
  - CARDライブラリの【概要】で述べたROM転送処理に加えてハッシュ計算処理が実行されるため、より多くのCPU計算時間と転送速度の低下が起こります。
    例として、カードブート時のROMアクセス速度はNTRモードでおよそ1.6[MB/s]ですが、TWLモードではおよそ1.2[MB/s]になります。
  - ROMイメージに対するハッシュチェック用テーブルもデータとして収録されるため、一定の比率でROM容量を追加消費します。 また、その一部をオンメモリに保持しておく必要があるため`CARD_Init( )`の内部でアリーナからメインメモリが消費されます。 これらの所要量はROMサイズとmakeromツールのDigestParam設定に依存し、以下の計算式で算出されます。

        (消費メモリサイズ) = 20 * (ROMサイズ) / (DigestParam引数1) / (DigestParam引数2)
        (追加消費ROMサイズ) = 20 * (ROMサイズ) / (DigestParam引数1) + (消費メモリサイズ)

    現行ではDigestParamは常に"1024 32"ですので、実際の計算式は常に以下のようになります。

        消費メモリサイズ = ROMサイズ * 0.0006104
        追加消費ROMサイズ = ROMサイズ * 0.02014

    例として、1Gb(128MB)のROMであればメインメモリを約20kB、ROM容量を約2.7MB追加で消費することになります。
  なお、この検証処理にはSRLファイルまたはTADファイルに格納されている情報が必要なため、TLFファイルのみをロードした場合は検証処理が行われません。
- TWL専用ファイル
  ニンテンドーDSi対応ゲームカードの新しいセキュリティで保護される「TWL専用領域」へ個別にファイルを選んで配置することができます。
  TWL専用領域に配置されたファイルは「TWL専用ファイル」となり、NITROモード環境ではカードからの読み出しが不可能となります。 HYBRIDモードでビルドされたプログラムはニンテンドーDS/DSiどちらの本体でも動作する必要がありますが、ニンテンドーDSiでしか使用しないファイルをこの機能で個別に指定しておくことにより、コピープロテクト機能の向上が期待できます。
  TWL専用ファイルを指定する方法は、makelcf.TWLの"Ltdautoload"や"Ltdoverlay"パラメータ、または makerom.TWLの"Put"パラメータなどがあります。詳細は各々の説明を参照してください。
- NANDアプリへの自動対応
  NANDアプリとして起動した場合は自分自身のROMデータがDSカード上でなくNANDファイルとして存在しているため、 NANDファイルをDSカードとみなして振舞う特別なアーカイブがNAライブラリの初期化処理によって自動的に構築されます。 このため、ROMアクセスに関してカードアプリからNANDアプリへの移行時に必要な変更作業は特にありません。

## NANDアーカイブ

TWLには本体NANDメモリが内蔵されており、この領域に存在するファイルシステムへアクセスするための何種類かのアーカイブを総称してNANDアーカイブと呼びます。 本体NANDメモリはそれ自体がいくつかのパーティションに分割されており、 個々のNANDアプリが保持するセーブデータファイルもそれぞれが1個の独立したファイルシステムになっていますが、 内部構造は全てFATフォーマットを採用しています。
本体NANDメモリの性能については別途プログラミングマニュアルをご参照ください。

NANDアーカイブとしてマウントされるアーカイブはNANDアプリの設定によって最大で10個近く存在し、それぞれが"photo:"や"dataPub:"などの異なる名前を持ちます。 各々のアーカイブに関する詳細はNANDアプリ開発用の関連ドキュメントをご参照ください。

## SDメモリカードアーカイブ

TWLにはSDメモリカードスロットが搭載されており、プログラムの設定によってはこのスロットへのアクセスが可能です。 このときに使用するアーカイブがSDメモリカードアーカイブであり、"sdmc:"という名前でマウントされます。 SDメモリカードもFATフォーマットで構成されているため基本的な使用方法はNANDアーカイブとまったく同じですが、 データ転送速度が個々のSDメモリカードごとに大きく異なる点やアクセス中にメディアを抜き挿しされてしまう可能性がある点には注意が必要です。

メディアの抜き挿しをイベントとして監視したい場合は`FS_RegisterEventHook()`を利用することができます。現在のスロットの状態やライトプロテクトなどを確認したい場合は`FS_GetPathInfo("sdmc:/", info)`のようにルートディレクトリの情報として取得することができますが、スロットが空であったり不明なデバイスが挿入されている場合はこの関数が失敗しますので、`FS_GetArchiveResultCode()`の返り値で詳細を確認する必要があります。(たとえば`FS_RESULT_MEDIA_NOTHING`であればスロットが空であることを示します)

また、SDメモリカードはパーソナルコンピュータや多くのデジタル家電製品でも一般的に使用される記憶媒体であり、 使用にあたってはアプリケーションの意図していない不正な内容のデータを外部から受け取ってしまう危険性を常に充分に考慮する必要があります。このような安全上の観点により現行ではSDメモリカードアーカイブは原則的に使用禁止となっていますが、開発の利便性を考慮し、TWL-SDK5.1PR以降ではDebug/Releaseビルド時のみ限定的にアクセスが許可されるようになりました。

## メモリファイルアーカイブ

このアーカイブはFSライブラリ内部に存在する無名のアーカイブであり、システムにはマウントされていません。 `FS_CreateFileFromMemory( )`を呼び出してオープンした無名のファイルはこのアーカイブに属します。

任意のメモリ空間をあたかもファイルのように扱うことができるため、 頻繁に使用する小さなファイルをオンメモリ化するなど、使い方によっては大変便利なアーカイブです。

## 内部フォーマット

前述したいくつかの標準アーカイブは、それぞれに特性の異なる内部フォーマットを採用しています。 ここでは、各フォーマットのおおまかな特徴を解説します。

### NitroROMフォーマット

makeromツールやTWL-Systemのnnsarc.exeツールなどで採用されている、 TWL-SDK固有のデータアーカイブフォーマットです。以下のような特徴を備えています。

- 全てのファイルとディレクトリに一意なIDが割り当てられているため、繰り返し使用するファイルのIDを `FS_ConvertPathToFileID( )`で取得しておけば `FS_OpenFileFast( )`を使用して高速に開くことができます。
- 格納媒体がROMであることを考慮したフォーマットであるため、ディレクトリツリーの構造を変更することが困難です。 NitroROMフォーマットを採用しているアーカイブは、ファイルやディレクトリの新規作成・削除・移動などの操作をサポートしていません。

NitroROMフォーマットの概要については $TwlSDK/docs/technicalNotes/AboutFileSystem.pdf で紹介されていますが、通常は一般開発者がこの仕様を考慮する必要はありません。

### FATフォーマット

国際規格ISO/IEC 9293として標準化され、SDメモリカードやハードディスクなどで広く採用されている、いわゆるFATファイルシステムです。 FATフォーマットに関してはさまざまな解説書籍や仕様書などが存在しますので説明を省略しますが、 ここでは実際の使用にあたって注意しておきたいいくつかの特徴を述べておきます。

- ディレクトリやファイル名のために内部的な管理情報を保持しておく必要があるため、 ファイルを作成すると名目上のファイルサイズ以外にも管理情報のためにドライブの空き容量を消費することがあります。 消費されるサイズはファイルシステムの内部状態やパス名の長さに依存しますが、ディレクトリ作成時は少なくとも確実に1クラスタ分の空き容量を必要としますので、作成するファイルやディレクトリの総数が不定な場合はドライブの空き容量にいくらかの充分なマージンを見積もっておく必要があります。
- ルートディレクトリの直下に生成できるファイルやディレクトリの総数に上限があり、 その数はFATのフォーマットタイプや容量、ファイル名の長さなどに依存します。
- SDメモリカードによっては初回アクセスの際に非常に長い時間を要することがあり、 その時間はクラスタサイズや容量、メーカ固有のデータ転送速度などに依存します。
- 長いファイル名と短いファイル名の2種類が存在し、それぞれが異なる文字コードになっています。 長いファイル名は常にUTF-16LE(Unicode)で格納されますが、短いファイル名については「ファイルを作成した環境のロケール」 であること以外に特別な規定がありません。そのため、短いファイル名のみからその正確な文字コードを確認する手段はありません。

また、TWLにおけるFATのドライバ実装は以下のような特徴を持っています。

- FAT12/FAT16/FAT32に対応しており、SDHCメモリカードにも対応しています。
- FATフォーマットで実装された全てのアーカイブをARM7コンポーネント内の単一のドライバが処理しているため、 複数のスレッドから複数のアーカイブへ同時にコマンドを発行してもひとつずつ処理されます。
- ドライバがARM7コンポーネント内に存在するため、ファイルの読み書き処理がキャッシュライン32バイト境界の影響を受けます。
  ReadFile/WriteFileに指定するバッファや転送サイズがキャッシュライン整合していない場合には ライブラリ内部の一時バッファを経由するメモリコピーが発生するため、 非同期呼び出しは無視されて常にブロッキング動作となり、転送速度も低下します。
- ファイルやディレクトリを生成する際、エントリ名が8.3形式で表現できるかどうかに関わらず常に長いファイル名を生成します。
- オープンしたファイルを読み書きする際、シークポインタが4バイト整合していない場合にアクセス性能が低下します。
- 長い処理時間がかかる可能性のあるコマンドは、 システムのシャットダウンが開始された場合FS_RESULT_CANCELEDを返して全て中止されます。
  SDメモリカードへの初回アクセス時や2MB以上の一括読み書きアクセスがこれに該当します。
  また、NAND アーカイブでこれが発生した場合には、NAND が FS_RESULT_BAD_FORMAT を返す状態になります。
- より製品環境に近いテストのため、本体NANDメモリの読み書き寿命を内部でエミュレーションします。 DebugおよびReleaseビルド時には読み出しアクセス時間にランダムな遅延時間が追加されます。
- `FS_ReadDirectory( )`で取得するディレクトリエントリの順番は特にソートされず、ファイルシステム内に格納されている順でそのまま渡されます。 また、"."や".."といったシステムノードやSDメモリカードのボリュームラベルといった特殊なエントリもフィルタされずにそのまま取得することができます。
- ドライバの仕様により、`FS_ReadDirectory( )`では更新時刻しか取得できず、 生成時刻と最新アクセス時刻は取得できません。 これらの情報が必要な場合、別途`FS_GetPathInfo( )`を呼び出して取得する必要があります。
- 8.3形式でない長いファイル名で新規作成する際、短いファイル名の選定のために非常に長い処理時間を要する場合があります。
  たとえば "aaaaaaaa101.bin" というファイルを新規作成すると短いファイル名の候補は "AAAAAA~1.BIN" になりますが、 すでに"aaaaaaaa001.bin"、"aaaaaaaa002.bin"、… "aaaaaaaa100.bin" のような100個の連番ファイルが存在するフォルダであれば "AAAAAA~1.BIN"、"AAAAAA~2.BIN"、… "AAAA~100.BIN" までのすべての候補が競合してしまうため、 "AAAA~101.BIN" でようやく成功するまでディレクトリ内を100回繰り返し列挙することになります。
  連番になりえるファイル群の名前は8.3形式におさめるか連番を接頭子にすえると処理速度が向上します。

また、SDメモリカードへアクセスしている最中にSDメモリカードを抜かれてしまうと、 FATの内部状態に不整合をきたしてしまう致命的なタイミングが存在します。 そのときに起こりえる不具合と対策を以下にまとめます。

抜かれる状況 | まれに起こる症状 | プログラムでとりうる対策
ファイルサイズ変更中(SetFileLength) | 増加予定分のファイルサイズが空き容量から失われる。 または減少した分のファイルサイズが空き容量から失われる。 (ファイル自体には異常なし) | プログラムからこれを復旧する方法はありません。PCなどの外部環境でチェックディスクツールを使用すれば復旧できるかもしれません。
エントリの作成中(Create) エントリの移動中(Rename) | 内部で確保中だった長いファイル名が消失し、13文字あたり32バイトが空き容量から失われる。
エントリの削除中(Delete) エントリの移動中(Rename) | 削除中のエントリが使用していた全クラスタが空き容量から失われる。*1
長いファイル名だけが消失してしまい、8.3形式の短いファイル名となる。*2 | プログラムが大文字と小文字の違いを特に区別しないのであれば問題ありません。
エントリの移動中(Rename) | 新旧両方のエントリが存在し、どちらを参照/変更しても同じ内容を指すようになる。 一方を削除したらもう一方は削除操作以外全てFS_RESULT_ERRORで失敗する。 | 新旧両方のエントリを削除して作り直す必要があります。
ファイル追記後のクローズ中(Close) | 追記した領域の実体が確保されないままファイルサイズ情報だけが更新され、不整合が生じる。 追記した領域へアクセスするとFS_RESULT_ERRORで失敗する。 | ファイルを削除して作り直す必要があります。
*1と*2が同時に発生することはありません。

### 各フォーマットの動作比較

FSライブラリは多くのファイルシステム操作APIを用意し、各アーカイブがそのインタフェースに準拠することを要求していますが、 ファイルシステムの仕様上どうしてもサポートできないオペレーションについては実装しないことも許容しています。 そのようなアーカイブに対してAPIを呼び出した場合、常に`FS_RESULT_UNSUPPORTED`のエラーが返されます。
主要な関数に対する各フォーマットの対応状況を下表に示します。

使用可能 | 使用不可能

関数 | NitroROMフォーマット (ROMアーカイブ) | FATフォーマット (NANDアーカイブ、 SDメモリカードアーカイブ) | (メモリファイルアーカイブ)
FS_OpenFileEx (FS_OpenFile) |  |  | *3
FS_OpenFileFast |  | *4 | *3
FS_ConvertPathToFileID |  | *4 | *3
FS_OpenFileDirect |  | *5 | *3
FS_GetFileImageTop |  | *5 |
FS_GetFileImageBottom |  | *5 |
FS_CloseFile |  |  |
FS_GetFileLength |  |  |
FS_SetFileLength |  |  |
FS_GetFilePosition |  |  |
FS_SeekFile FS_SeekFileToBegin FS_SeekFileToEnd |  |  |
FS_ReadFile |  |  |
FS_ReadFileAsync |  |  |
FS_WriteFile | *1 |  |
FS_WriteFileAsync | *1 |  |
FS_FlushFile | *1 |  |
FS_OpenDirectory (FS_FindDir) |  |  | *3
FS_ReadDirectory (FS_ReadDir) |  |  | *3
FS_CloseDirectory |  |  | *3
FS_TellDir |  | *4 | *3
FS_SeekDir |  | *4 | *3
FS_RewindDir |  | *4 | *3
FS_GetPathName |  | *4 | *3
FS_GetPathLength |  | *4 | *3
FS_CreateFile | *2 |  | *3
FS_DeleteFile | *2 |  | *3
FS_RenameFile | *2 |  | *3
FS_CreateDirectory | *2 |  | *3
FS_DeleteDirectory | *2 |  | *3
FS_RenameDirectory | *2 |  | *3

*1 ファイルの内容を書き換えるコマンドは非対応です。
*2 ディレクトリ構造を動的に変更するコマンドは非対応です。
*3 ディレクトリ構造へアクセスするコマンドは非対応です。
*4 ファイルIDやディレクトリIDを使用するコマンドは非対応です。
*5 デバイスのアドレス空間へ直接アクセスするコマンドは非対応です。

### 返しうるエラーコードの一覧

FSライブラリが定義しているエラーコードは全てのアーカイブの内部処理を包括したものなので、 エラーコードによっては特定のアーカイブからしか返されないものもいくつか存在します。 参考までに、各アーカイブが返す可能性のあるエラーコードの一覧を下表に示します。

エラーコード (`FSResult`) | ROMアーカイブ | NANDアーカイブ | SDメモリカードアーカイブ | メモリファイルアーカイブ | 備考
FS_RESULT_SUCCESS | Yes | Yes | Yes | Yes |
FS_RESULT_FAILURE | Yes | Yes | Yes | Yes |
FS_RESULT_BUSY | Yes | Yes | Yes | Yes |
FS_RESULT_CANCELED | Yes | Yes | Yes | Yes |
FS_RESULT_UNSUPPORTED | Yes | Yes | Yes | Yes |
FS_RESULT_ERROR | Yes | Yes | Yes | Yes |
FS_RESULT_INVALID_PARAMETER | Yes | Yes | Yes | Yes |
FS_RESULT_NO_MORE_RESOURCE | No | Yes | Yes | No |
FS_RESULT_ALREADY_DONE | No | Yes | Yes | No |
FS_RESULT_PERMISSION_DENIED | Yes | Yes | Yes | No |
FS_RESULT_MEDIA_FATAL | No | Yes | Yes | No | NAND/SDメモリカード固有のエラーです。
FS_RESULT_NO_ENTRY | Yes | Yes | Yes | No |
FS_RESULT_MEDIA_NOTHING | No | No | Yes | No | SDメモリカード固有のエラーです。
FS_RESULT_MEDIA_UNKNOWN | No | No | Yes | No | SDメモリカード固有のエラーです。
FS_RESULT_BAD_FORMAT | No | Yes | Yes | No | FATフォーマット固有のエラーです。

## 参照

`FS関数一覧
`

## 履歴

2010/07/10 長い処理時間がかかるコマンド中の電源断でNANDがFS_RESULT_BAD_FORMATを返す状態になる旨を追記
2009/06/08 TWL専用領域とTWL専用ファイルについて追記。
2009/05/13 SDメモリカードの挿抜検出やスロット状態の判定方法について追記。
2009/04/13 参考資料の文書名を訂正。TWLモードでのROMアーカイブ動作について追記。
2009/04/10 表中で使用する記号を標準的な表記に置き換え。
2009/02/27 FATドライバのファイルアクセス動作について追記
2009/01/13 SDメモリカードアーカイブがDebug/Releaseビルド時のみ限定的にアクセス許可される旨を追記
2008/12/08 各アーカイブが返しうるエラーコードの一覧を追記
2008/10/28 FATで連番ファイルを作成する際の注意を追記
2008/10/20 TLFをロードしてた場合にROMの検証処理が実行されない旨を追記
2008/09/30 SDメモリカードの挿抜で生じるFAT状態不整合に関して追記
2008/09/26 SDメモリカードの挿抜に関して追記、ROMアーカイブのアクセス速度に関して追記
2008/09/16 FATドライバの仕様に関して追記
2008/09/12 初版