# 機能設計書 1-fs

## 概要

本ドキュメントは、Node.jsのfsモジュール（ファイルシステム操作API）の機能設計を記載する。fsモジュールは、ファイルの読み書き、ディレクトリ操作、ファイル監視等のファイルシステム操作を提供するコアモジュールである。

### 本機能の処理概要

fsモジュールは、POSIX標準のファイルシステム操作をNode.js環境で利用可能にする基盤機能である。同期API、コールバックベースの非同期API、およびPromiseベースの非同期APIの3つの形式でファイル操作を提供する。

**業務上の目的・背景**：アプリケーション開発において、設定ファイルの読み込み、ログファイルの出力、データファイルの永続化など、ファイルシステムへのアクセスは不可欠な要件である。fsモジュールは、これらの要件をNode.js環境で効率的かつ安全に実現するための標準APIを提供する。サーバーサイドアプリケーション、CLIツール、ビルドツールなど幅広いユースケースで利用される。

**機能の利用シーン**：
- Webサーバーでの静的ファイル配信
- 設定ファイル（JSON、YAML等）の読み込み
- ログファイルへの書き込み
- ファイルアップロード処理
- ビルドツールでのソースファイル操作
- データのバックアップ・復元

**主要な処理内容**：
1. ファイルの読み込み（readFile, readFileSync, read, readSync）
2. ファイルへの書き込み（writeFile, writeFileSync, write, writeSync）
3. ファイルのオープン・クローズ（open, openSync, close, closeSync）
4. ディレクトリ操作（mkdir, readdir, rmdir, rm）
5. ファイル情報取得（stat, lstat, fstat）
6. ファイルの移動・名前変更（rename, renameSync）
7. ファイルの削除（unlink, unlinkSync, rm, rmSync）
8. シンボリックリンク操作（symlink, readlink, link）
9. パーミッション変更（chmod, chown）
10. ファイル監視（watch, watchFile）

**関連システム・外部連携**：libuv経由でOSのファイルシステムAPIを呼び出す。内部的にはC++バインディング（internalBinding('fs')）を使用してネイティブ機能にアクセスする。

**権限による制御**：Node.jsのパーミッションモデルが有効な場合、ファイルシステムへのアクセスが制限される。特にsymlinkやfdatasync等の一部APIはパーミッションモデル有効時に無効化される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | Profview (Tick Processor) | 補助機能 | プロファイルファイル（v8.json）の読み込み処理 |
| 4 | Turbolizer | 補助機能 | TurboFanグラフデータファイルのアップロード処理 |
| 6 | Heap Statistics | 補助機能 | トレースファイル（results.html、trace.json.gzip）の読み込み |
| 7 | Heap Layout | 補助機能 | ヒープレイアウトトレースファイルの読み込み |
| 8 | Zone Statistics | 補助機能 | Zoneトレースファイルの読み込み |
| 10 | Parse Processor | 補助機能 | V8ログファイルの読み込み |

## 機能種別

CRUD操作 / ストリーム処理 / ファイル監視

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| path | string / Buffer / URL | Yes | 操作対象のファイルパス | getValidatedPath()で検証 |
| fd | number | Yes（FD操作時） | ファイルディスクリプタ | isInt32()で検証 |
| flags | string / number | No | オープンフラグ（'r', 'w', 'a'等） | stringToFlags()で変換・検証 |
| mode | string / number | No | ファイルパーミッション | parseFileMode()で検証 |
| encoding | string | No | 文字エンコーディング | validateEncoding()で検証 |
| buffer | Buffer / TypedArray / DataView | Yes（read/write時） | データバッファ | validateBuffer()で検証 |
| options | object | No | 各種オプション | validateObject()で検証 |
| signal | AbortSignal | No | 中断シグナル | validateAbortSignal()で検証 |

### 入力データソース

- ファイルパス：アプリケーションコードから直接指定
- ファイルディスクリプタ：open()で取得した値
- バッファ：Buffer.alloc()等で作成したデータ領域

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| data | Buffer / string | 読み込んだファイル内容 |
| bytesRead | number | 読み込んだバイト数 |
| bytesWritten | number | 書き込んだバイト数 |
| fd | number | オープンしたファイルディスクリプタ |
| stats | Stats | ファイル情報オブジェクト |
| files | string[] / Buffer[] / Dirent[] | ディレクトリ内のエントリ一覧 |

### 出力先

- 戻り値（同期API）
- コールバック関数の引数（非同期API）
- Promiseのresolve値（Promise API）

## 処理フロー

### 処理シーケンス

```
1. 入力パラメータの検証
   └─ パス、フラグ、モード、エンコーディング等を検証関数で検証
2. ネイティブバインディング呼び出し
   └─ binding.xxx()でC++実装を呼び出し
3. 結果の変換・整形
   └─ Stats、Dirent等のオブジェクト生成
4. コールバック/Promise解決
   └─ 非同期APIの場合は結果を通知
```

### フローチャート

```mermaid
flowchart TD
    A[API呼び出し] --> B{パラメータ検証}
    B -->|エラー| C[例外をスロー]
    B -->|OK| D{同期/非同期}
    D -->|同期| E[binding直接呼び出し]
    D -->|非同期| F[FSReqCallback作成]
    F --> G[binding呼び出し]
    E --> H[結果変換]
    G --> I[oncomplete待機]
    I --> H
    H --> J[結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | ファイルサイズ上限 | 読み込み可能な最大ファイルサイズはkIoMaxLength | readFile系API |
| BR-002 | パーミッションモデル制限 | パーミッションモデル有効時は一部APIが無効化 | permission.isEnabled()がtrue |
| BR-003 | シンボリックリンク制限 | symlink APIはfs.read/write権限が必要 | パーミッションモデル有効時 |
| BR-004 | UTF-8最適化 | UTF-8エンコーディング指定時は専用高速パスを使用 | readFileSyncでencoding='utf8' |

### 計算ロジック

- ファイルサイズ上限: `kIoMaxLength = 2^31 - 1` バイト（約2GB）
- デフォルトパーミッション: `0o666`（所有者・グループ・その他に読み書き権限）
- デフォルトフラグ: `'r'`（読み取り専用）

## データベース操作仕様

本モジュールはデータベースを直接操作しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ERR_FS_FILE_TOO_LARGE | サイズエラー | ファイルサイズがkIoMaxLengthを超過 | 分割読み込みを検討 |
| ERR_INVALID_ARG_VALUE | 引数エラー | 無効なパス、フラグ等 | 引数を修正 |
| ERR_INVALID_ARG_TYPE | 型エラー | 引数の型が不正 | 正しい型の値を指定 |
| ERR_ACCESS_DENIED | 権限エラー | パーミッションモデルによるアクセス拒否 | 適切な権限を設定 |
| ENOENT | OSエラー | ファイルが存在しない | パスを確認 |
| EACCES | OSエラー | アクセス権限がない | ファイル権限を確認 |
| EEXIST | OSエラー | ファイルが既に存在 | 上書きオプションを検討 |

### リトライ仕様

rm()のみmaxRetriesオプションでリトライ回数を指定可能。retryDelayでリトライ間隔（ミリ秒）を指定。

## トランザクション仕様

ファイルシステム操作はOSレベルのトランザクションに依存。アトミックな操作が必要な場合は適切な同期メカニズムを実装する必要がある。

## パフォーマンス要件

- 同期APIはイベントループをブロックするため、大量データ処理には非同期APIを推奨
- UTF-8読み込みはbinding.readFileUtf8()による最適化パスを使用
- ストリームAPIを使用することでメモリ効率の良い大容量ファイル処理が可能

## セキュリティ考慮事項

- パスインジェクション：ユーザー入力をパスに使用する場合は十分な検証が必要
- パーミッションモデル：機密性の高い環境ではNode.jsのパーミッションモデルを有効化
- シンボリックリンク：symlink APIはセキュリティ上の理由から完全なfs権限が必要

## 備考

- fs/promisesモジュールでPromiseベースのAPIを提供
- graceful-fsなどのサードパーティモジュールとの互換性を考慮した設計
- Node.js v20以降では一部の非推奨APIが削除予定

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、ファイル操作で使用されるデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | utils.js | `lib/internal/fs/utils.js` | Stats、Dirent等のデータ構造定義 |

**読解のコツ**: Stats クラスはファイル情報を保持し、isFile()、isDirectory()等のメソッドを提供する。Direntはディレクトリエントリを表現する。

#### Step 2: エントリーポイントを理解する

処理の起点となるファイル・関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fs.js | `lib/fs.js` | 公開APIの定義とエクスポート |

**主要処理フロー**:
1. **214-226行目**: access()関数 - パスの検証とバインディング呼び出し
2. **356-382行目**: readFile()関数 - ファイル読み込みの非同期実装
3. **428-485行目**: readFileSync()関数 - UTF-8最適化パスとバッファ処理
4. **526-545行目**: open()関数 - ファイルオープン処理
5. **598-671行目**: read()関数 - ファイル読み込みの低レベルAPI

#### Step 3: 内部実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | promises.js | `lib/internal/fs/promises.js` | Promise版APIの実装 |
| 3-2 | streams.js | `lib/internal/fs/streams.js` | ReadStream/WriteStreamの実装 |
| 3-3 | watchers.js | `lib/internal/fs/watchers.js` | ファイル監視の実装 |

**主要処理フロー（promises.js）**:
- **151-163行目**: FileHandleクラスのコンストラクタ
- **509-598行目**: readFileHandle()関数 - Promise版ファイル読み込み
- **602-608行目**: access()関数 - Promise版アクセスチェック

### プログラム呼び出し階層図

```
fs.readFile(path, options, callback)
    │
    ├─ getValidatedPath(path)          // パス検証
    │      └─ validatePath()
    │
    ├─ getOptions(options)             // オプション正規化
    │
    ├─ stringToFlags(options.flag)     // フラグ変換
    │
    └─ binding.open()                  // ネイティブ呼び出し
           │
           ├─ readFileAfterOpen()      // オープン完了コールバック
           │      └─ binding.fstat()
           │             └─ readFileAfterStat()
           │                    └─ context.read()
           │                           └─ binding.read()
           │
           └─ context.close()          // クローズ処理
                  └─ binding.close()
```

### データフロー図

```
[入力]                    [処理]                         [出力]

パス(string)    ───▶  getValidatedPath()  ───▶  検証済みパス
                           │
オプション      ───▶  getOptions()        ───▶  正規化オプション
                           │
                      binding.open()      ───▶  ファイルディスクリプタ(fd)
                           │
                      binding.fstat()     ───▶  ファイル情報(stats)
                           │
                      binding.read()      ───▶  Buffer(データ)
                           │
                      toString()          ───▶  string(エンコード済み)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| fs.js | `lib/fs.js` | ソース | 公開API定義（同期・非同期） |
| promises.js | `lib/internal/fs/promises.js` | ソース | Promise版API実装 |
| utils.js | `lib/internal/fs/utils.js` | ソース | ユーティリティ関数・データ構造 |
| streams.js | `lib/internal/fs/streams.js` | ソース | ストリームAPI実装 |
| watchers.js | `lib/internal/fs/watchers.js` | ソース | ファイル監視実装 |
| dir.js | `lib/internal/fs/dir.js` | ソース | ディレクトリ操作実装 |
| cp.js | `lib/internal/fs/cp/cp.js` | ソース | コピー機能実装 |
| rimraf.js | `lib/internal/fs/rimraf.js` | ソース | 再帰削除実装 |
| read/context.js | `lib/internal/fs/read/context.js` | ソース | 読み込みコンテキスト |
