# 機能設計書 103-ディレクトリ操作

## 概要

本ドキュメントは、libuvが提供するディレクトリ操作機能（uv_fs_mkdir / uv_fs_rmdir / uv_fs_mkdtemp / uv_fs_mkstemp）の設計仕様を記載する。

### 本機能の処理概要

ディレクトリの作成・削除、一時ディレクトリ・一時ファイルの作成を非同期で行う機能を提供する。4種類のAPIにより、通常のディレクトリ操作と安全な一時リソース作成をサポートする。

**業務上の目的・背景**：ファイルシステムの構造管理に不可欠な機能群である。ディレクトリの動的作成・削除はアプリケーションのデータ管理に必要であり、一時ディレクトリ・ファイルの安全な作成はセキュリティ上重要である。テンプレートパターン（XXXXXX）を用いたランダムな名前生成により、レースコンディションのないリソース作成が保証される。

**機能の利用シーン**：ログ出力先ディレクトリの作成、キャッシュディレクトリの作成、一時ファイルの安全な作成、ビルドアーティファクト用ディレクトリの管理、不要ディレクトリの削除など。

**主要な処理内容**：
1. mkdir: 指定パスにディレクトリを作成（パーミッション指定可能）
2. rmdir: 指定パスのディレクトリを削除（空であること必須）
3. mkdtemp: テンプレートに基づく一時ディレクトリの作成
4. mkstemp: テンプレートに基づく一時ファイルの作成（FD返却）

**関連システム・外部連携**：POSIXのmkdir/rmdir/mkdtemp/mkstemp、Linux io_uringによるmkdir高速化。

**権限による制御**：mkdir/mkdtempでは親ディレクトリへの書き込み権限が必要。rmdirでは対象ディレクトリの親ディレクトリへの書き込み権限が必要。

## 関連画面

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

## 機能種別

データ操作処理（ファイルシステム構造の変更）

## 入力仕様

### 入力パラメータ

**uv_fs_mkdir:**

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

**uv_fs_rmdir:**

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| 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_mkdtemp / uv_fs_mkstemp:**

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | - |
| req | uv_fs_t* | Yes | FSリクエスト | NULLでUV_EINVAL |
| tpl | const char* | Yes | テンプレート（末尾XXXXXX） | 末尾6文字がXXXXXXであること |
| cb | uv_fs_cb | No | コールバック | NULLで同期実行 |

### 入力データソース

ユーザーがAPI呼び出し時に指定するパスまたはテンプレート文字列。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | ssize_t | 成功時0（mkdir/rmdir/mkdtemp）、FD（mkstemp）。失敗時は負のエラーコード |
| path | const char* | mkdtemp/mkstemp: 作成されたパス（テンプレートのXXXXXXが置換済み） |

### 出力先

uv_fs_t構造体のresultフィールドおよびpathフィールド。

## 処理フロー

### 処理シーケンス

```
1. INITマクロによるリクエスト初期化
2. パラメータ設定
   └─ mkdir: PATH + req->mode設定
   └─ rmdir: PATH設定
   └─ mkdtemp/mkstemp: テンプレート文字列のstrdup
3. [mkdir, Linux非同期] io_uring最適化の試行
4. POSTマクロによる実行
5. 内部処理
   └─ mkdir: mkdir(req->path, req->mode)
   └─ rmdir: rmdir(req->path)
   └─ mkdtemp: mkdtemp(req->path) -- パスが直接変更される
   └─ mkstemp: mkostemp/mkstemp -- O_CLOEXECの有無で分岐
```

### フローチャート

```mermaid
flowchart TD
    A[API呼び出し] --> B{操作種別}
    B -->|mkdir| C[INIT + PATH + mode設定]
    B -->|rmdir| D[INIT + PATH]
    B -->|mkdtemp| E[INIT + テンプレートstrdup]
    B -->|mkstemp| F[INIT + テンプレートstrdup]
    C --> G[POST]
    D --> G
    E --> G
    F --> G
    G --> H{mkstemp?}
    H -->|Yes| I[テンプレート末尾XXXXXX検証]
    I --> J{O_CLOEXEC対応?}
    J -->|Yes| K[mkostemp使用]
    J -->|No| L[mkstemp + uv__cloexec]
    H -->|No| M[mkdir/rmdir/mkdtemp呼び出し]
    K --> N[結果返却]
    L --> N
    M --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-301 | テンプレート検証 | mkstempではテンプレート末尾6文字がXXXXXXであることを検証 | mkstemp呼び出し時 |
| BR-302 | O_CLOEXEC優先 | mkstempではO_CLOEXEC付きのmkostempを優先使用 | O_CLOEXECサポート環境 |
| BR-303 | mkdtemp/mkstempのパスコピー | テンプレートは常にstrdupされる（同期/非同期問わず） | mkdtemp/mkstemp |
| BR-304 | mkstemp失敗時のパスクリア | mkstemp失敗時はpath[0]を'\0'に設定 | mkstemp失敗時 |
| BR-305 | io_uring mkdir最適化 | Linux環境の非同期mkdirではio_uringを試行 | Linux非同期mkdir |

### 計算ロジック

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

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

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

該当なし（ファイルシステム操作のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | パラメータエラー | reqがNULL、テンプレートが不正 | 正しいパラメータを渡す |
| UV_EEXIST | 既存パス | mkdirで既にパスが存在 | 存在確認してから作成 |
| UV_ENOENT | パス不在 | 親ディレクトリが存在しない | 親ディレクトリを先に作成 |
| UV_EACCES | 権限エラー | 書き込み権限がない | 権限を確認する |
| UV_ENOTEMPTY | ディレクトリ非空 | rmdirで空でないディレクトリを削除しようとした | 中身を先に削除 |
| UV_ENOMEM | メモリ不足 | テンプレート文字列のstrdup失敗 | メモリを解放する |

### リトライ仕様

EINTRで中断された場合、uv__fs_work内のdo-whileループで自動リトライされる。

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

該当なし（各操作はアトミックに実行される）

## パフォーマンス要件

- mkdirではLinux環境でio_uringによる高速化が可能
- 同期モードでは直接システムコールを呼び出し

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

- mkdtemp/mkstempはセキュアな一時リソース作成手段であり、レースコンディションを防ぐ
- mkstempで作成されたFDにはO_CLOEXECが設定され、子プロセスへのFD漏洩を防止
- 非同期mkstempではcloexec_lockでロックを取得してレースコンディションを防ぐ

## 備考

- mkdtemp/mkstempのテンプレート文字列は常にstrdupされ、uv_fs_req_cleanup()で解放される
- rmdirは空ディレクトリのみ削除可能（再帰削除は非対応）
- mkstempの返却FDは呼び出し側で明示的にクローズが必要

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | uv_fs_t構造体（1450-1460行目）。path、mode、resultフィールドに注目 |

**読解のコツ**: mkdtemp/mkstempではreq->pathがテンプレートとしてコピーされ、システムコールにより直接書き換えられる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fs.c | `src/unix/fs.c` | uv_fs_mkdir()実装（1962-1974行目）。io_uring最適化あり |
| 2-2 | fs.c | `src/unix/fs.c` | uv_fs_rmdir()実装（2134-2138行目）。単純なINIT/PATH/POST |
| 2-3 | fs.c | `src/unix/fs.c` | uv_fs_mkdtemp()実装（1977-1986行目）。テンプレートのstrdup |
| 2-4 | fs.c | `src/unix/fs.c` | uv_fs_mkstemp()実装（1989-1998行目）。テンプレートのstrdup |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fs.c | `src/unix/fs.c` | uv__fs_mkdtemp()実装（266-268行目）。mkdtemp()呼び出し |
| 3-2 | fs.c | `src/unix/fs.c` | uv__fs_mkstemp()実装（290-359行目）。O_CLOEXEC/mkostemp/mkstemp分岐 |
| 3-3 | fs.c | `src/unix/fs.c` | uv__mkostemp_initonce()実装（274-287行目）。mkostemp関数の動的検索 |

**主要処理フロー**:
- **290-314行目**: テンプレート末尾XXXXXX検証
- **316行目**: uv_once()でmkostempの動的検索を一度だけ実行
- **318-334行目**: O_CLOEXECサポート時のmkostemp使用
- **337-353行目**: フォールバック: mkstemp + uv__cloexec + cloexec_lock
- **356-358行目**: 失敗時にpath[0] = '\0'

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

```
uv_fs_mkdir()
    +-- INIT(MKDIR) + PATH + req->mode
    +-- [Linux非同期] uv__iou_fs_mkdir()
    +-- POST -> uv__fs_work -> mkdir()

uv_fs_rmdir()
    +-- INIT(RMDIR) + PATH
    +-- POST -> uv__fs_work -> rmdir()

uv_fs_mkdtemp()
    +-- INIT(MKDTEMP) + strdup(tpl)
    +-- POST -> uv__fs_work -> uv__fs_mkdtemp()
                                   +-- mkdtemp()

uv_fs_mkstemp()
    +-- INIT(MKSTEMP) + strdup(tpl)
    +-- POST -> uv__fs_work -> uv__fs_mkstemp()
                                   +-- uv_once(uv__mkostemp_initonce)
                                   +-- mkostemp() / mkstemp() + uv__cloexec()
```

### データフロー図

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

path + mode  ---------> uv_fs_mkdir()  -----------> result (0 or error)
path  -----------------> uv_fs_rmdir()  -----------> result (0 or error)
tpl (XXXXXX)  ---------> uv_fs_mkdtemp() ----------> path (XXXXXX置換済み)
tpl (XXXXXX)  ---------> uv_fs_mkstemp() ----------> result (FD), path (置換済み)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | API宣言 |
| fs.c | `src/unix/fs.c` | ソース | Unix系のmkdir/rmdir/mkdtemp/mkstemp実装 |
| fs.c | `src/win/fs.c` | ソース | Windows版実装 |
