# 機能設計書 97-ファイル読み書き

## 概要

本ドキュメントは、libuvにおけるファイル読み書き機能（uv_fs_read / uv_fs_write）の設計仕様を記述する。オープン済みファイルに対して非同期で読み書きを行う機能である。

### 本機能の処理概要

**業務上の目的・背景**：ファイルの読み書きはI/O操作の中心的な機能である。libuvは散布/収集（scatter/gather）I/Oに対応したベクトルI/Oをサポートし、複数のバッファを指定した効率的なファイルI/Oを可能にする。また、オフセット指定による位置指定I/O（pread/pwrite）にも対応する。同期モードと非同期モードの両方をサポートする。

**機能の利用シーン**：ログファイルへの書き込み、設定ファイルの読み込み、データファイルの読み書き、大規模ファイルの分割読み込み、複数バッファへの効率的な読み込みなどで利用される。

**主要な処理内容**：
1. uv_fs_read(): ファイルからバッファにデータを読み込む
2. uv_fs_write(): バッファのデータをファイルに書き込む
3. ベクトルI/O対応（複数バッファの指定が可能）
4. オフセット指定による位置指定I/O対応
5. 非同期モードではスレッドプールで実行

**関連システム・外部連携**：POSIX read()/write()/pread()/pwrite()/readv()/writev()システムコール、Linux io_uring。

**権限による制御**：ファイルのアクセス権限に従う。read権限がないファイルの読み取り、write権限がないファイルへの書き込みはエラーとなる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | ファイルシステム操作 | 主機能 | uv_fs_read()/uv_fs_write()による非同期ファイル読み書きのAPI定義 |
| 34 | ファイルシステム | 主機能 | catコマンド実装サンプルによるファイル読み書きの解説 |

## 機能種別

ファイルI/O操作

## 入力仕様

### 入力パラメータ

#### uv_fs_read()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | NULLでないこと |
| req | uv_fs_t* | Yes | ファイルシステムリクエスト | NULLでないこと |
| file | uv_file | Yes | 読み込み元のファイルディスクリプタ | 有効なFD |
| bufs | const uv_buf_t[] | Yes | 読み込み先バッファの配列 | NULLでないこと |
| nbufs | unsigned int | Yes | バッファの数 | 0でないこと |
| offset | int64_t | Yes | ファイル内の読み込み開始位置（負の場合は現在位置から） | - |
| cb | uv_fs_cb | No | 完了コールバック | - |

#### uv_fs_write()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | NULLでないこと |
| req | uv_fs_t* | Yes | ファイルシステムリクエスト | NULLでないこと |
| file | uv_file | Yes | 書き込み先のファイルディスクリプタ | 有効なFD |
| bufs | const uv_buf_t[] | Yes | 書き込みデータのバッファ配列 | NULLでないこと |
| nbufs | unsigned int | Yes | バッファの数 | 0でないこと |
| offset | int64_t | Yes | ファイル内の書き込み開始位置（負の場合は現在位置から） | - |
| cb | uv_fs_cb | No | 完了コールバック | - |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値（同期） | int | 読み書きされたバイト数、または負のエラーコード |
| 戻り値（非同期） | int | 常に0（リクエスト投入成功）、またはUV_EINVAL/UV_ENOMEM |
| req->result | ssize_t | コールバック内で参照。読み書きされたバイト数 |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. INITマクロでリクエスト構造体を初期化
2. バッファ検証（bufs==NULL || nbufs==0 の場合はUV_EINVAL）
3. req->off, req->file, req->bufs, req->nbufs を設定
4. [非同期] バッファ配列をコピー
   └─ nbufs <= ARRAY_SIZE(req->bufsml) ならスタック上のバッファを使用
   └─ それ以外はuv__malloc()でヒープ割り当て
5. [非同期] io_uring対応の場合はuv__iou_fs_read_or_write()で高速パスを試行
6. POSTマクロでスレッドプールに投入/同期実行
7. uv__fs_read()/uv__fs_write()が実際のI/O操作を実行
   └─ off < 0: read()/write()/readv()/writev()（現在位置使用）
   └─ off >= 0: pread()/pwrite()/preadv()/pwritev()（位置指定）
   └─ nbufs == 1: 単一バッファ系API
   └─ nbufs > 1: ベクトルI/O系API
```

### フローチャート

```mermaid
flowchart TD
    A[uv_fs_read/write] --> B{bufs/nbufs有効?}
    B -->|No| C[return UV_EINVAL]
    B -->|Yes| D[req設定]
    D --> E{非同期?}
    E -->|Yes| F[バッファコピー]
    F --> G{io_uring?}
    G -->|Yes| H[io_uringパス]
    G -->|No| I[スレッドプール投入]
    E -->|No| J[uv__fs_read/write直接実行]
    I --> J
    J --> K{off < 0?}
    K -->|Yes| L{nbufs == 1?}
    K -->|No| M{nbufs == 1?}
    L -->|1| N[read/write]
    L -->|>1| O[readv/writev]
    M -->|1| P[pread/pwrite]
    M -->|>1| Q[preadv/pwritev]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-97-1 | オフセット負値 | offset < 0の場合は現在のファイル位置から読み書きする | off < 0 |
| BR-97-2 | オフセット正値 | offset >= 0の場合は指定位置から読み書きする（pread/pwrite使用） | off >= 0 |
| BR-97-3 | 小バッファ最適化 | bufsml[]（スタック上の小バッファ配列）を使い、少数バッファ時のmalloc回避 | nbufs <= ARRAY_SIZE(bufsml) |
| BR-97-4 | iovmax制限 | ベクトルI/Oのバッファ数はuv__getiovmax()で取得した上限に制限される | ベクトルI/O実行時 |
| BR-97-5 | EINTRリトライ対象外 | READ操作はEINTRリトライの対象外とする | uv__fs_work内 |

### 計算ロジック

特になし。

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | 不正パラメータ | bufsがNULLまたはnbufsが0 | 有効なバッファを指定する |
| UV_ENOMEM | メモリ不足 | バッファコピー時のメモリ確保失敗 | メモリを確保する |
| UV_EBADF | 不正FD | 無効なファイルディスクリプタ | 有効なFDを指定する |
| UV_ECANCELED | キャンセル | uv_cancel()によるリクエストキャンセル | 再試行する |

### リトライ仕様

CLOSEとREAD以外の操作では、EINTRによる中断時に自動リトライされる。

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

該当なし。

## パフォーマンス要件

- 小バッファ最適化により、少数バッファ使用時のヒープ割り当てを回避
- UV__WORK_FAST_IO優先度でスレッドプールに投入される
- io_uring対応環境では更なる高速化が可能

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

- バッファオーバーフローの防止は呼び出し元の責任
- ファイルアクセス権限のチェックはOSに委ねる

## 備考

- uv_fs_write()は内部的にuv__fs_write_all()を使用し、全データの書き込みを保証する
- uv_buf_tはstruct iovecと互換性がある（Unixプラットフォーム）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | uv_fs_t構造体（1450-1460行目）とuv_buf_t型 |
| 1-2 | uv.h | `include/uv.h` | API宣言（1480-1497行目） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fs.c | `src/unix/fs.c` | uv_fs_read()（2018-2051行目）。バッファ検証とコピー処理 |
| 2-2 | fs.c | `src/unix/fs.c` | uv_fs_write()（2207-2238行目）。書き込みリクエストの設定 |

**主要処理フロー**:
- **2026-2027行目**: bufs/nbufs検証
- **2031行目**: `req->bufs = (uv_buf_t*) bufs` - 同期時は直接参照
- **2037-2044行目**: 非同期時のバッファコピー（bufsml最適化含む）
- **2046行目**: io_uring高速パスの試行

#### Step 3: 内部読み書き実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fs.c | `src/unix/fs.c` | uv__fs_read()（505-535行目）。ベクトルI/O分岐 |
| 3-2 | fs.c | `src/unix/fs.c` | uv__fs_write()（1198-1224行目）。書き込みのベクトルI/O分岐 |

**主要処理フロー**:
- **523-533行目**: off < 0でread/readv、off >= 0でpread/preadv
- **1211-1221行目**: off < 0でwrite/writev、off >= 0でpwrite/pwritev

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

```
uv_fs_read(loop, req, file, bufs, nbufs, off, cb)
    |
    +-- INIT(READ)
    +-- バッファ検証・コピー
    +-- [非同期] uv__iou_fs_read_or_write() or POST
    |       +-- uv__fs_work()
    |               +-- uv__fs_read(req)
    |                       +-- read()/readv()/pread()/preadv()
    +-- [同期] uv__fs_work() → return req->result

uv_fs_write(loop, req, file, bufs, nbufs, off, cb)
    |
    +-- INIT(WRITE)
    +-- バッファコピー
    +-- [非同期] uv__iou_fs_read_or_write() or POST
    |       +-- uv__fs_work()
    |               +-- uv__fs_write_all(req)
    |                       +-- uv__fs_write(req)
    |                               +-- write()/writev()/pwrite()/pwritev()
    +-- [同期] uv__fs_work() → return req->result
```

### データフロー図

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

uv_file, bufs[], off  ───> read系syscall      ───> バッファにデータ
                            (read/pread/readv)       ssize_t (bytes read)

uv_file, bufs[], off  ───> write系syscall     ───> ファイルにデータ
                            (write/pwrite/writev)    ssize_t (bytes written)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | API宣言、uv_fs_t/uv_buf_t型定義 |
| fs.c | `src/unix/fs.c` | ソース | Unix系のファイルI/O実装 |
| fs.c | `src/win/fs.c` | ソース | Windows版のファイルI/O実装 |
