# 機能設計書 96-ファイルオープン・クローズ

## 概要

本ドキュメントは、libuvにおけるファイルオープン・クローズ機能（uv_fs_open / uv_fs_close）の設計仕様を記述する。ファイルの非同期オープンおよびクローズを行う機能である。

### 本機能の処理概要

**業務上の目的・背景**：ファイルI/Oはほぼすべてのアプリケーションで必要とされる基本操作である。libuvはイベントループと統合されたファイルI/O APIを提供し、ブロッキングを回避した非同期ファイル操作を可能にする。uv_fs_open()とuv_fs_close()はファイルI/Oの基本となるオープン・クローズ操作を提供する。同期モード（コールバックNULL）と非同期モード（コールバック指定）の両方をサポートする。

**機能の利用シーン**：ファイルの読み書き前のオープン処理、ファイル使用後のクローズ処理、ファイルディスクリプタのリソース管理、テンポラリファイルの作成と後始末などで利用される。

**主要な処理内容**：
1. uv_fs_open(): 指定パスのファイルをフラグとモードに従ってオープンする
2. uv_fs_close(): オープン済みファイルのファイルディスクリプタをクローズする
3. 非同期モードではスレッドプールでI/O操作を実行し、完了後にコールバックを呼ぶ
4. 同期モードでは呼び出しスレッドで直接I/O操作を実行する

**関連システム・外部連携**：POSIX open()/close()システムコール、Linux io_uring（対応環境）。

**権限による制御**：ファイルのアクセス権限はOSのファイルシステムパーミッションに従う。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | ファイルシステム操作 | 主機能 | uv_fs_open()/uv_fs_close()による非同期ファイルオープン・クローズのAPI定義 |
| 34 | ファイルシステム | 主機能 | ファイルオープン・クローズのサンプルコードを使った解説 |

## 機能種別

ファイルI/O操作

## 入力仕様

### 入力パラメータ

#### uv_fs_open()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | NULLでないこと |
| req | uv_fs_t* | Yes | ファイルシステムリクエスト | NULLでないこと |
| path | const char* | Yes | オープンするファイルパス | NULLでないこと |
| flags | int | Yes | オープンフラグ（O_RDONLY, O_WRONLY, O_CREAT等） | 有効なフラグの組み合わせ |
| mode | int | Yes | ファイル作成時のパーミッション（O_CREAT時のみ有効） | - |
| cb | uv_fs_cb | No | 完了コールバック（NULLの場合は同期実行） | - |

#### uv_fs_close()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | NULLでないこと |
| req | uv_fs_t* | Yes | ファイルシステムリクエスト | NULLでないこと |
| file | uv_file | Yes | クローズするファイルディスクリプタ | 有効なFDであること |
| cb | uv_fs_cb | No | 完了コールバック（NULLの場合は同期実行） | - |

### 入力データソース

呼び出し元コードから直接パラメータとして渡される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値（同期） | int | uv_fs_open: 成功時はファイルディスクリプタ、失敗時は負のエラーコード。uv_fs_close: 成功時は0 |
| 戻り値（非同期） | int | 常に0（リクエスト投入成功） |
| req->result | ssize_t | コールバック内で参照。open: FD値、close: 0または負のエラーコード |

### 出力先

呼び出し元への戻り値、またはコールバック関数のreqパラメータ経由。

## 処理フロー

### 処理シーケンス

```
1. INITマクロでリクエスト構造体を初期化する
   └─ fs_type, result, ptr, loop, path, bufs, cb を設定
2. PATHマクロでパスを設定する（非同期時はコピー）
3. [open] flags, modeをreqに設定
4. [非同期] POSTマクロでスレッドプールに投入する
   └─ uv__work_submit()でUV__WORK_FAST_IOとしてキューイング
   └─ [Linux] io_uring対応の場合はuv__iou_fs_open()で高速パスを試行
5. [同期] uv__fs_work()を直接呼び出す
   └─ uv__fs_open() → open(path, flags | O_CLOEXEC, mode)
   └─ uv__fs_close() → uv__close_nocancel(fd)
6. 結果をreq->resultに格納する
7. [非同期] コールバックを呼び出す
```

### フローチャート

```mermaid
flowchart TD
    A[uv_fs_open/close] --> B[INIT: リクエスト初期化]
    B --> C{cb != NULL?}
    C -->|Yes - 非同期| D{io_uring対応?}
    D -->|Yes| E[io_uringパス]
    D -->|No| F[uv__work_submit]
    F --> G[スレッドプールで実行]
    G --> H[uv__fs_work]
    H --> I[open/close syscall]
    I --> J[uv__fs_done]
    J --> K[コールバック呼出]
    C -->|No - 同期| H
    E --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-96-1 | O_CLOEXEC自動付与 | open()時にO_CLOEXECフラグを自動的に付与し、子プロセスへのFD漏洩を防ぐ | Unix, O_CLOEXECサポート環境 |
| BR-96-2 | cloexecロック | O_CLOEXECがサポートされない環境では、rwlockで保護しながらcloexecを設定する | O_CLOEXEC未サポート環境 |
| BR-96-3 | EINTR/EINPROGRESS処理 | close()でEINTRまたはEINPROGRESSが返された場合は成功として扱う | close()実行時 |
| BR-96-4 | 非同期パスコピー | 非同期モードではpathをstrdup()でコピーし、リクエストが独立してパスを保持する | cb != NULL |
| BR-96-5 | io_uring高速パス | Linux環境でio_uring対応の場合は、スレッドプールをバイパスして高速に処理する | Linux, io_uring対応 |

### 計算ロジック

特になし。

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | 不正パラメータ | reqがNULL | 有効なリクエストを渡す |
| UV_ENOENT | ファイル不存在 | 指定パスのファイルが存在しない | パスを確認する |
| UV_EACCES | アクセス拒否 | ファイルのアクセス権がない | 権限を確認する |
| UV_EMFILE | FD上限 | プロセスのFD上限に達した | 不要なFDを閉じる |
| UV_ENOMEM | メモリ不足 | パスのコピーにメモリが不足 | メモリを確保する |
| UV_ECANCELED | キャンセル | uv_cancel()でリクエストがキャンセルされた | 再試行する |

### リトライ仕様

非同期リクエストの場合、EINTRによるリトライはuv__fs_work()内のdo-whileループで自動的に行われる（ただしCLOSE/READはリトライしない）。

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

該当なし。

## パフォーマンス要件

- 同期モード：システムコール1回分の遅延
- 非同期モード：スレッドプールのワーカースレッド数に依存。UV__WORK_FAST_IO優先度で投入される
- io_uring利用時：カーネルレベルの非同期I/Oにより最も高速

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

- O_CLOEXECフラグの自動付与により、子プロセスへのFD漏洩を防止する
- ファイルパスの検証はOSのファイルシステムに委ねる
- シンボリックリンクの追跡はOSのデフォルト動作に従う

## 備考

- uv_fs_req_cleanup()で非同期リクエストのリソース（パスコピー等）を解放する必要がある
- 同期モードではreq->pathは呼び出し元のポインタを直接参照する（コピーしない）
- INITマクロ、PATHマクロ、POSTマクロがファイルシステム操作の共通パターンを提供する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | uv_fs_t構造体（1450-1460行目）。fs_type, loop, cb, result, ptr, path, statbufフィールドを確認 |
| 1-2 | uv.h | `include/uv.h` | uv_fs_type列挙（1415-1440行目）。UV_FS_OPEN, UV_FS_CLOSEなどの型定義 |

**読解のコツ**: UV_FS_PRIVATE_FIELDSマクロにはfile, flags, mode, nbufs, bufs, off, uid, gid, atime, mtime, work_reqなどのプラットフォーム固有フィールドが含まれる。

#### Step 2: マクロによる共通パターンを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fs.c | `src/unix/fs.c` | INITマクロ（90-104行目）。リクエスト初期化の共通処理 |
| 2-2 | fs.c | `src/unix/fs.c` | PATHマクロ（106-117行目）。パスの設定と非同期時のコピー |
| 2-3 | fs.c | `src/unix/fs.c` | POSTマクロ（139-155行目）。非同期/同期の分岐 |

**主要処理フロー**:
- **90-104行目**: INIT - リクエストの基本フィールドを初期化。fs_type設定が重要
- **106-117行目**: PATH - cbがNULLなら直接参照、cbがあればuv__strdup()でコピー
- **139-155行目**: POST - cbがNULLなら同期実行、cbがあればuv__work_submitでスレッドプールに投入

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fs.c | `src/unix/fs.c` | uv_fs_open()（2001-2015行目）。オープンのAPI実装 |
| 3-2 | fs.c | `src/unix/fs.c` | uv_fs_close()（1816-1823行目）。クローズのAPI実装 |

**主要処理フロー**:
- **2007行目**: `INIT(OPEN)` - UV_FS_OPENとして初期化
- **2008行目**: `PATH` - パスの設定
- **2009-2010行目**: flags, modeの設定
- **2011-2013行目**: io_uring高速パスの試行
- **1817行目**: `INIT(CLOSE)` - UV_FS_CLOSEとして初期化
- **1818行目**: `req->file = file` - FDの設定
- **1820行目**: io_uring高速パスの試行

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | fs.c | `src/unix/fs.c` | uv__fs_open()（362-385行目）。open()システムコールの呼び出し |
| 4-2 | fs.c | `src/unix/fs.c` | uv__fs_close()（158-167行目）。close()の呼び出しとEINTR処理 |
| 4-3 | fs.c | `src/unix/fs.c` | uv__fs_work()（1681-1750行目）。ワーカースレッドでの実行ディスパッチ |
| 4-4 | fs.c | `src/unix/fs.c` | uv__fs_done()（1753-1765行目）。完了処理とコールバック呼び出し |

**主要処理フロー**:
- **363-364行目**: O_CLOEXECサポート時は直接open()にフラグを追加
- **368-381行目**: O_CLOEXEC未サポート時はrwlockで保護しながらcloexecを設定
- **161-164行目**: EINTRまたはEINPROGRESSの場合はrc=0（成功扱い）
- **1698行目**: switchでfs_typeに応じた処理を呼び出す
- **1759-1761行目**: キャンセル時はUV_ECANCELEDを設定

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

```
uv_fs_open(loop, req, path, flags, mode, cb)
    |
    +-- INIT(OPEN)
    +-- PATH
    +-- [非同期] uv__iou_fs_open() or uv__work_submit()
    |       |
    |       +-- uv__fs_work()
    |       |       +-- uv__fs_open(req)
    |       |               +-- open(path, flags | O_CLOEXEC, mode)
    |       |
    |       +-- uv__fs_done()
    |               +-- req->cb(req)
    |
    +-- [同期] uv__fs_work() → return req->result

uv_fs_close(loop, req, file, cb)
    |
    +-- INIT(CLOSE)
    +-- [非同期] uv__iou_fs_close() or uv__work_submit()
    |       |
    |       +-- uv__fs_work()
    |       |       +-- uv__fs_close(req->file)
    |       |               +-- uv__close_nocancel(fd)
    |       |
    |       +-- uv__fs_done()
    |
    +-- [同期] uv__fs_work() → return req->result
```

### データフロー図

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

path, flags, mode ───> open() syscall        ───> file descriptor (int)
                       O_CLOEXEC付与
                       [非同期] スレッドプール

uv_file (fd)      ───> close() syscall       ───> 0 or error
                       EINTR/EINPROGRESS処理
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | API宣言、uv_fs_t構造体、uv_fs_type列挙 |
| fs.c | `src/unix/fs.c` | ソース | Unix系のFS操作全体の実装 |
| fs.c | `src/win/fs.c` | ソース | Windows版のFS操作実装 |
| uv-common.c | `src/uv-common.c` | ソース | 共通ユーティリティ |
