# 機能設計書 8-open_read_write

## 概要

本ドキュメントは、Hack Standard Library (HSL) のファイル操作モジュール `HH\Lib\File\open_read_write` 関数の機能設計書である。

### 本機能の処理概要

**業務上の目的・背景**：
ファイルの読み取りと書き込みを同時に行う必要がある場合がある。例えば、設定ファイルの読み込み後の更新、データファイルの部分修正、ログファイルのローテーション処理などである。`open_read_write`関数は、ファイルを読み書き両用モードで開き、同一ハンドルで読み取りと書き込みの両方の操作が可能なハンドルを返す。これにより、ファイルを一度開くだけで柔軟なファイル操作が実現できる。

**機能の利用シーン**：
- 設定ファイルの読み込みと更新
- データファイルの部分修正（特定位置への上書き）
- ファイルの先頭を読み取り、末尾に追記
- テスト用一時ファイルの作成と読み書き
- ファイルベースのキャッシュ操作

**主要な処理内容**：
1. 指定されたパスのファイルをOS\O_RDWRモードと指定されたWriteModeで開く
2. ファイルが存在しない場合、WriteModeに応じて新規作成
3. ファイル作成時のパーミッションを指定可能
4. CloseableReadWriteHandleインスタンスを作成して返却

**関連システム・外部連携**：
- `OS\open()`関数でファイルを開く
- `_File\CloseableReadWriteHandle`クラスでハンドルをラップ
- `WriteMode`列挙型でオープンモードを制御

**権限による制御**：ファイルシステムのパーミッションに依存

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 画面なし | - | 本プロジェクトはUIを持たないライブラリのため該当なし |

## 機能種別

ファイルI/O / 読み書き操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| path | string | Yes | 開くファイルのパス | 有効なファイルパス |
| mode | WriteMode | No | オープンモード（デフォルト: OPEN_OR_CREATE） | WriteMode列挙値 |
| create_file_permissions | int | No | 新規作成時のパーミッション（デフォルト: 0644） | 有効なUnixパーミッション |

### 入力データソース

- プログラムから直接呼び出し（API）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | CloseableReadWriteHandle | 読み書き両方の操作が可能なファイルハンドル |

### 出力先

- 呼び出し元プログラムへの戻り値
- 指定されたファイルパス（書き込み先）

## 処理フロー

### 処理シーケンス

```
1. open_read_write($path, $mode, $create_file_permissions)が呼び出される
   └─ デフォルト値: mode=OPEN_OR_CREATE, permissions=0644
2. OS\open()でファイルを開く
   └─ フラグ: OS\O_RDWR | $mode as int
   └─ O_CREATフラグがある場合はpermissionsを渡す
3. CloseableReadWriteHandleを作成
   └─ FileDescriptorとパスを渡す
4. ハンドルを返却
   └─ 呼び出し元で読み書き操作を実行可能
```

### フローチャート

```mermaid
flowchart TD
    A[open_read_write開始] --> B{WriteMode判定}
    B --> C[O_RDWR | mode フラグ生成]
    C --> D{O_CREATを含む?}
    D -->|Yes| E[permissions引数付きでOS::open]
    D -->|No| F[OS::open]
    E --> G{ファイル操作成功?}
    F --> G
    G -->|No| H[ErrnoException]
    G -->|Yes| I[FileDescriptor取得]
    I --> J[CloseableReadWriteHandle作成]
    J --> K[ハンドルを返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 読み書き両用 | ファイルは読み取りと書き込みの両方が可能 | 常時 |
| BR-02 | モード別動作 | WriteModeにより作成・上書き・追記の動作が決まる | 常時 |
| BR-03 | パーミッション適用 | O_CREATフラグがある場合のみpermissionsが適用される | ファイル新規作成時 |
| BR-04 | シーク共有 | 読み取りと書き込みは同一のファイル位置を共有 | 常時 |
| BR-05 | クローズ責任 | 呼び出し元がclose()またはcloseWhenDisposed()を呼ぶ責任を持つ | 常時 |

### 計算ロジック

**ファイル位置の共有**:
- 読み取り後、ファイル位置は読み取った分だけ進む
- その位置から書き込むと、その位置から上書きされる
- `seek()`で明示的に位置を変更可能
- APPENDモードでは書き込み位置は常にファイル末尾

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ENOENT | OS\ErrnoException | 親ディレクトリが存在しない | ディレクトリを作成する |
| EACCES | OS\ErrnoException | 読み取りまたは書き込み権限がない | ファイル/ディレクトリのパーミッションを確認 |
| EISDIR | OS\ErrnoException | パスがディレクトリ | ファイルパスを指定する |
| EEXIST | OS\ErrnoException | MUST_CREATEでファイルが既に存在 | 別のWriteModeを使用 |
| EMFILE | OS\ErrnoException | プロセスのFD上限に達した | ファイルを適切にclose |

### リトライ仕様

本機能自体にリトライ機構は組み込まれていない。

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

該当なし（ファイルシステムのアトミック性に依存）

## パフォーマンス要件

- ファイルオープンはOSのシステムコールに依存
- 読み取りと書き込みを交互に行う場合、ファイル位置に注意
- バッファリングの影響を考慮（flush()が必要な場合あり）

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

- ファイルパスのバリデーション（パストラバーサル対策）は呼び出し元の責任
- デフォルトパーミッション0644は他ユーザーからの読み取りを許可
- センシティブなデータを扱う場合は0600を推奨
- 読み書き両用で開くため、意図しない書き込みに注意

## 備考

- 非推奨の`open_read_write_nd`関数が存在するが、`open_read_write`を使用すること
- `open_read_only`と`open_write_only`の機能を組み合わせたもの
- TemporaryFile内部で使用されている
- truncate()メソッドでファイルを切り詰め可能

---

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

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

### 推奨読解順序

#### Step 1: 関数シグネチャを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | open.php | `src/file/open.php` | open_read_write関数（32-43行目） |

**読解のコツ**: open_write_onlyとほぼ同じ構造だが、O_RDWRフラグを使用。

**主要処理フロー**:
- **34行目**: `WriteMode $mode = WriteMode::OPEN_OR_CREATE` - デフォルトモード
- **35行目**: `int $create_file_permissions = 0644` - デフォルトパーミッション
- **37-39行目**: `OS\O_RDWR | $mode as int` - 読み書きフラグの結合
- **42行目**: `new _File\CloseableReadWriteHandle($$, $path)` - ハンドル作成

#### Step 2: ハンドル実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CloseableReadWriteHandle.php | `src/file/_Private/CloseableReadWriteHandle.php` | 読み書きハンドル実装（16-22行目） |

**主要処理フロー**:
- **17-18行目**: `extends CloseableFileHandle implements File\CloseableReadWriteHandle`
- **19行目**: `use _IO\FileDescriptorReadHandleTrait` - 読み取り機能
- **20行目**: `use _IO\FileDescriptorWriteHandleTrait` - 書き込み機能
- **21行目**: `use TruncateTrait` - 切り詰め機能

#### Step 3: インターフェース階層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Handle.php | `src/file/Handle.php` | ReadWriteHandleインターフェース（55-56行目） |
| 3-2 | CloseableHandle.php | `src/file/CloseableHandle.php` | CloseableReadWriteHandleインターフェース（29-35行目） |

**主要なインターフェース**:
- **55行目**: `ReadWriteHandle extends WriteHandle, ReadHandle` - 複合インターフェース
- **29-34行目**: 多重継承で読み取り・書き込み・クローズ機能を統合

#### Step 4: テストコードで使用例を確認

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | FileTest.php | `tests/file/FileTest.php` | open_read_writeの使用例 |

**主要処理フロー**:
- **207行目**: `File\open_read_write($filename)` - 読み書きモードでオープン
- **209-214行目**: truncate, readAll, seek の組み合わせ使用

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

```
File\open_read_write($path, $mode, $permissions)
    |
    +-- フラグ計算: OS\O_RDWR | $mode as int
    |
    +-- permissions判定: ($mode & OS\O_CREAT) ? $permissions : null
    |
    +-- OS\open($path, $flags, $permissions)
    |       |
    |       +-- FileDescriptor を返却
    |
    +-- new _File\CloseableReadWriteHandle($fd, $path)
            |
            +-- extends CloseableFileHandle
            +-- use _IO\FileDescriptorReadHandleTrait
            |       |
            |       +-- readAllowPartialSuccessAsync()
            |       +-- readAllAsync()
            |
            +-- use _IO\FileDescriptorWriteHandleTrait
            |       |
            |       +-- writeAllowPartialSuccessAsync()
            |       +-- writeAllAsync()
            |
            +-- use TruncateTrait
                    |
                    +-- truncate($length)
```

### データフロー図

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

string $path
WriteMode $mode
int $permissions
    |
    v
┌─────────────────────────────────────────────────────────────────────┐
│ フラグ生成                                                          │
│   O_RDWR | mode                                                     │
│   - 読み取り + 書き込み + modeオプション                            │
└─────────────────────────────────────────────────────────────────────┘
    |
    v
┌─────────────────────────────────────────────────────────────────────┐
│ OS\open($path, $flags, $permissions)                                │
│   - システムコールでファイルを開く/作成                              │
│   - FileDescriptor を取得                                           │
└─────────────────────────────────────────────────────────────────────┘
    |
    v
┌─────────────────────────────────────────────────────────────────────┐
│ CloseableReadWriteHandle($fd, $path)                                │
│   - 読み取り + 書き込み操作を提供                                    │
│     - readAllowPartialSuccessAsync() / readAllAsync()              │
│     - writeAllowPartialSuccessAsync() / writeAllAsync()            │
│     - seek() / tell()                                               │
│     - truncate()                                                    │
└─────────────────────────────────────────────────────────────────────┘
    |
    v
CloseableReadWriteHandle ──────────> ファイルとの双方向データ転送
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| open.php | `src/file/open.php` | ソース | open_read_write関数の定義 |
| WriteMode.php | `src/file/WriteMode.php` | ソース | WriteMode列挙型の定義 |
| Handle.php | `src/file/Handle.php` | ソース | ReadWriteHandleインターフェース |
| CloseableHandle.php | `src/file/CloseableHandle.php` | ソース | CloseableReadWriteHandleインターフェース |
| CloseableReadWriteHandle.php | `src/file/_Private/CloseableReadWriteHandle.php` | ソース | 読み書きハンドルの実装 |
| CloseableFileHandle.php | `src/file/_Private/CloseableFileHandle.php` | ソース | ファイルハンドルの基底実装 |
| FileDescriptorReadHandleTrait.php | `src/io/_Private/FileDescriptorReadHandleTrait.php` | ソース | 読み取り機能のトレイト |
| FileDescriptorWriteHandleTrait.php | `src/io/_Private/FileDescriptorWriteHandleTrait.php` | ソース | 書き込み機能のトレイト |
| TruncateTrait.php | `src/file/_Private/TruncateTrait.php` | ソース | 切り詰め機能のトレイト |
| TemporaryFile.php | `src/file/TemporaryFile.php` | ソース | 内部で使用 |
| FileTest.php | `tests/file/FileTest.php` | テスト | ファイル操作のテスト |
