# 機能設計書 104-ディレクトリ走査

## 概要

本ドキュメントは、libuvが提供するディレクトリ走査機能（uv_fs_scandir / uv_fs_scandir_next / uv_fs_opendir / uv_fs_readdir / uv_fs_closedir）の設計仕様を記載する。

### 本機能の処理概要

ディレクトリの内容を列挙する2つのAPIセットを提供する。scandir系APIは一括読み込み方式、opendir/readdir/closedir系APIはストリーミング方式でディレクトリエントリを取得する。

**業務上の目的・背景**：ファイルマネージャ、ビルドツール、ファイル同期ツールなど、ディレクトリの内容を走査する処理は多くのアプリケーションで必要とされる。scandir系は小～中規模ディレクトリに適し、ソート済み結果を一括取得できる。opendir系は大規模ディレクトリに適し、メモリ使用量を制御可能である。

**機能の利用シーン**：ファイル一覧の取得、再帰的ディレクトリ走査、ファイル検索、ビルドシステムのソースファイル列挙、バックアップツールの対象ファイル列挙など。

**主要な処理内容**：
1. scandir: ディレクトリの全エントリを一括読み込み（.と..を除外、名前順ソート）
2. scandir_next: scandirの結果から1エントリずつ取得
3. opendir: ディレクトリハンドルを開く
4. readdir: ディレクトリエントリをバッチ読み込み
5. closedir: ディレクトリハンドルを閉じてリソースを解放

**関連システム・外部連携**：POSIXのscandir/opendir/readdir/closedir。

**権限による制御**：対象ディレクトリの読み取り権限および検索権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | ファイルシステム操作 | 主機能 | uv_fs_scandir()/opendir()/readdir()/closedir()によるディレクトリ走査のAPI定義 |

## 機能種別

データ取得処理（ディレクトリエントリの読み取り）

## 入力仕様

### 入力パラメータ

**uv_fs_scandir:**

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | - |
| req | uv_fs_t* | Yes | FSリクエスト | NULLでUV_EINVAL |
| path | const char* | Yes | ディレクトリパス | assert(path != NULL) |
| flags | int | Yes | フラグ（現在未使用） | - |
| cb | uv_fs_cb | No | コールバック | NULLで同期実行 |

**uv_fs_opendir:**

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | - |
| req | uv_fs_t* | Yes | FSリクエスト | NULLでUV_EINVAL |
| path | const char* | Yes | ディレクトリパス | assert(path != NULL) |
| cb | uv_fs_cb | No | コールバック | NULLで同期実行 |

**uv_fs_readdir:**

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | - |
| req | uv_fs_t* | Yes | FSリクエスト | NULLでUV_EINVAL |
| dir | uv_dir_t* | Yes | ディレクトリハンドル | NULL/dir->dir==NULL/dirents==NULLでUV_EINVAL |
| cb | uv_fs_cb | No | コールバック | NULLで同期実行 |

### 入力データソース

ユーザーがAPI呼び出し時に指定するディレクトリパスまたはuv_dir_tハンドル。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | ssize_t | scandir: エントリ数。readdir: 読み込んだエントリ数。EOF時は0 |
| uv_dirent_t.name | const char* | エントリ名 |
| uv_dirent_t.type | uv_dirent_type_t | エントリ種別（FILE/DIR/LINK等） |

### 出力先

scandir: req->ptrにソート済みエントリ配列、scandir_nextで逐次取得。readdir: dir->dirents配列に格納。

## 処理フロー

### 処理シーケンス

```
1. scandir系:
   a. INITマクロ + PATH + flags設定
   b. POSTで実行
   c. uv__fs_scandir(): scandir()で全エントリ一括読み込み（.と..除外、名前順ソート）
   d. req->ptrにエントリ配列格納、req->resultにエントリ数設定
   e. uv_fs_scandir_next()で1エントリずつ取得（nbufsをインデックスとして使用）

2. opendir/readdir/closedir系:
   a. opendir: uv_dir_t確保、opendir()呼び出し
   b. readdir: dir->nentriesまでreaddir()をループ呼び出し（.と..除外）
   c. closedir: closedir()呼び出し、uv_dir_t解放
```

### フローチャート

```mermaid
flowchart TD
    A{API種別} -->|scandir| B[scandir呼び出し]
    A -->|opendir| C[opendir呼び出し]
    B --> D[全エントリ一括読み込み]
    D --> E[名前順ソート]
    E --> F[scandir_nextで逐次取得]
    C --> G[uv_dir_t確保]
    G --> H[readdir呼び出し]
    H --> I[バッチ読み込み]
    I --> J{EOF?}
    J -->|No| H
    J -->|Yes| K[closedir呼び出し]
    K --> L[リソース解放]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-401 | .と..の除外 | scandirとreaddirの両方で.と..エントリを除外する | 常時 |
| BR-402 | 名前順ソート | scandirの結果は名前のアルファベット順にソートされる | scandir使用時 |
| BR-403 | nbufsをインデックスに使用 | scandir_nextではnbufsフィールドをエントリインデックスとして流用する | scandir_next使用時 |
| BR-404 | readdir戻り値 | readdirは読み込んだエントリ数を返す。EOFで0、エラーで-1 | readdir使用時 |

### 計算ロジック

特に複雑な計算ロジックはなし。

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

### 操作別データベース影響一覧

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | パラメータエラー | req/dir/direntsがNULL | 正しいパラメータを渡す |
| UV_ENOENT | パス不在 | ディレクトリが存在しない | パスの正当性を確認する |
| UV_EACCES | 権限エラー | 読み取り権限がない | 権限を確認する |
| UV_ENOTDIR | 非ディレクトリ | 対象がディレクトリでない | パスの種別を確認する |
| UV_EOF | 終端 | scandir_nextで全エントリ取得済み | 走査完了 |
| UV_ENOMEM | メモリ不足 | エントリ名のstrdupに失敗 | メモリを解放する |

### リトライ仕様

EINTRで中断された場合、自動リトライされる。

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

該当なし

## パフォーマンス要件

- scandirは全エントリを一括読み込みするため、大規模ディレクトリではメモリ消費が大きくなる
- opendir/readdir/closedirはバッチサイズを制御可能で、大規模ディレクトリに適する

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

- ディレクトリの読み取り権限が必要
- readdirでエントリ名をstrdupするため、メモリ管理に注意が必要

## 備考

- scandirの結果メモリはシステムアロケータ（free）で管理される部分がある
- readdirのエントリ名はuv__strdupで確保され、uv_fs_req_cleanup()で解放される
- uv_dirent_type_tの値はプラットフォームによってはUV_DIRENT_UNKNOWNになる場合がある

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | uv_dirent_t構造体、uv_dirent_type_t列挙体 |
| 1-2 | uv.h | `include/uv.h` | uv_dir_t構造体（dir, dirents, nentriesフィールド） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fs.c | `src/unix/fs.c` | uv_fs_scandir()（2054-2063行目） |
| 2-2 | fs.c | `src/unix/fs.c` | uv_fs_opendir()（2065-2072行目） |
| 2-3 | fs.c | `src/unix/fs.c` | uv_fs_readdir()（2074-2085行目）。dir/dirents NULLチェック |
| 2-4 | fs.c | `src/unix/fs.c` | uv_fs_closedir()（2087-2098行目） |
| 2-5 | uv-common.c | `src/uv-common.c` | uv_fs_scandir_next()（738行目以降） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fs.c | `src/unix/fs.c` | uv__fs_scandir()（569-592行目）。scandir()呼び出し、フィルタとソート |
| 3-2 | fs.c | `src/unix/fs.c` | uv__fs_opendir()（594-612行目）。uv_dir_t確保、opendir() |
| 3-3 | fs.c | `src/unix/fs.c` | uv__fs_readdir()（614-658行目）。readdir()ループ、.と..除外 |
| 3-4 | fs.c | `src/unix/fs.c` | uv__fs_closedir()（660-673行目）。closedir()、uv_dir_t解放 |

**主要処理フロー**:
- **569-592行目**: uv__fs_scandir -- scandir()で一括読み込み、nbufsを0に初期化
- **614-658行目**: uv__fs_readdir -- whileループでdir->nentriesまで読み込み、.と..をskip

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

```
uv_fs_scandir()
    +-- POST -> uv__fs_work -> uv__fs_scandir()
                                   +-- scandir() [システムコール]
    +-- uv_fs_scandir_next()  [ユーザー呼び出し]

uv_fs_opendir()
    +-- POST -> uv__fs_work -> uv__fs_opendir()
                                   +-- uv__malloc(uv_dir_t)
                                   +-- opendir()

uv_fs_readdir()
    +-- POST -> uv__fs_work -> uv__fs_readdir()
                                   +-- readdir() [ループ]
                                   +-- uv__strdup() [エントリ名コピー]

uv_fs_closedir()
    +-- POST -> uv__fs_work -> uv__fs_closedir()
                                   +-- closedir()
                                   +-- uv__free(uv_dir_t)
```

### データフロー図

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

path  ------------>  scandir()  -------->  ソート済みエントリ配列 (req->ptr)
                                           +-- scandir_next()で逐次取得

path  ------------>  opendir()  -------->  uv_dir_t (req->ptr)
uv_dir_t  -------->  readdir()  -------->  dir->dirents[] (エントリバッチ)
uv_dir_t  -------->  closedir() -------->  リソース解放
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | API宣言、uv_dirent_t/uv_dir_t定義 |
| fs.c | `src/unix/fs.c` | ソース | Unix系のディレクトリ走査実装 |
| uv-common.c | `src/uv-common.c` | ソース | uv_fs_scandir_next()実装 |
| fs.c | `src/win/fs.c` | ソース | Windows版実装 |
