# 機能設計書 112-ファイルアクセス確認

## 概要

本ドキュメントは、libuvのファイルアクセス権確認機能 `uv_fs_access()` の設計仕様を記述する。ファイルの読み取り・書き込み・実行権限を非同期で確認するAPI設計について定義する。

### 本機能の処理概要

`uv_fs_access()` は、指定されたパスのファイルまたはディレクトリに対して、現在のプロセスが指定された権限でアクセス可能かどうかを確認する機能である。POSIX access(2)システムコールのlibuvラッパーとして動作する。

**業務上の目的・背景**：ファイル操作を行う前に、対象ファイルが存在するか、必要な権限（読み取り・書き込み・実行）があるかを事前確認することで、本処理でのエラーを未然に防止し、アプリケーションの堅牢性を向上させる。

**機能の利用シーン**：設定ファイルの読み込み前のアクセス権チェック、ログファイル書き込み前の権限確認、実行ファイルの存在確認、ファイルの存在確認（F_OK）など。

**主要な処理内容**：
1. uv_fs_tリクエストの初期化（INIT(ACCESS)マクロ）
2. 対象パスの設定（PATHマクロ）
3. アクセスモードフラグの設定（req->flags）
4. 非同期/同期モードでのaccess(2)システムコール実行
5. 結果のコールバック通知

**関連システム・外部連携**：POSIX access(2)システムコール。OSのファイルシステム権限管理機構と連携する。

**権限による制御**：確認対象のファイルの権限に依存。real UIDとreal GIDに基づいてアクセス権が判定される（access(2)の仕様）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | ファイルシステム操作 | 主機能 | uv_fs_access()によるアクセス権確認のAPI定義 |

## 機能種別

バリデーション処理（ファイルアクセス権の事前検証）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループハンドル（同期実行時はNULL可） | - |
| req | uv_fs_t* | Yes | ファイルシステムリクエスト | NULLの場合UV_EINVALを返す |
| path | const char* | Yes | 確認対象のファイルパス | NULLでないこと（assertで検証） |
| mode | int | Yes | アクセスモードフラグ（F_OK, R_OK, W_OK, X_OK の組み合わせ） | POSIX定義のフラグ |
| cb | uv_fs_cb | No | 完了コールバック（NULLで同期実行） | - |

### 入力データソース

ユーザーが指定するファイルパス文字列。アクセスモードはPOSIXで定義された定数（F_OK=0, R_OK=4, W_OK=2, X_OK=1）。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 成功時は0、エラー時は負のエラーコード |
| req->result | ssize_t | アクセス可能時は0、不可時は負のエラーコード |

### 出力先

コールバック関数への通知（非同期時）、または戻り値としての直接返却（同期時）。

## 処理フロー

### 処理シーケンス

```
1. リクエスト初期化（INIT(ACCESS)マクロ）
   └─ req->fs_type = UV_FS_ACCESS
2. パス設定（PATHマクロ）
   └─ cb指定時はパスをuv__strdupで複製、同期時は直接参照
3. フラグ設定
   └─ req->flags = mode（アクセスモード）
4. 実行（POSTマクロ）
   ├─ cb != NULL: スレッドプールでaccess(req->path, req->flags)を実行
   └─ cb == NULL: 同期的にaccess()を実行
5. 結果返却
   └─ req->resultに結果を設定（0:アクセス可能、負:エラー）
```

### フローチャート

```mermaid
flowchart TD
    A[uv_fs_access 呼び出し] --> B[INIT: リクエスト初期化]
    B --> C[PATH: パス設定]
    C --> D[req->flags = mode]
    D --> E{cb != NULL?}
    E -->|Yes| F[スレッドプールへ非同期ディスパッチ]
    E -->|No| G[同期実行]
    F --> H[access path, flags]
    G --> H
    H --> I{access成功?}
    I -->|Yes| J[req->result = 0]
    I -->|No| K[req->result = -errno]
    J --> L[コールバック通知 or 結果返却]
    K --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-112-1 | real UID/GID判定 | access(2)はreal UID/GIDを使用して権限判定を行う | 常時 |
| BR-112-2 | フラグ組み合わせ | R_OK, W_OK, X_OKはビットOR演算で組み合わせ可能 | 複数権限確認時 |
| BR-112-3 | 存在確認 | F_OK(=0)を指定するとファイルの存在のみ確認する | 存在確認時 |

### 計算ロジック

特になし。access(2)システムコールの結果をそのまま返却する。

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | パラメータ不正 | reqがNULL | 有効なリクエストを渡す |
| UV_ENOENT | ファイル未存在 | 指定パスにファイルが存在しない | パスを確認する |
| UV_EACCES | アクセス拒否 | 指定された権限でのアクセスが拒否された | 権限を確認する |
| UV_ENOTDIR | パス不正 | パス中のディレクトリが存在しない | パスを確認する |
| UV_ENAMETOOLONG | パス長超過 | パスが長すぎる | 短いパスを使用する |
| UV_ECANCELED | キャンセル | uv_cancel()でキャンセルされた | 必要に応じて再実行 |

### リトライ仕様

EINTRによる中断は、uv__fs_workのdo-whileループで自動リトライされる。

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

該当なし。読み取り専用操作のため、トランザクション管理は不要。

## パフォーマンス要件

- access(2)はシステムコール1回で完了するため、個々の呼び出しは高速
- 非同期モードではスレッドプール（UV__WORK_FAST_IO）で実行
- TOCTOU（Time of check to time of use）の問題に注意が必要

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

- access(2)はreal UID/GIDを使用するため、setuid/setgidプログラムではeffective UID/GIDとの不一致に注意
- TOCTOU問題：access()の結果と実際のファイル操作の間に状態が変化する可能性がある

## 備考

- access(2)の仕様上、シンボリックリンクは自動的に辿られる
- uv__fs_workのディスパッチテーブルではaccessシステムコールが直接INVOKEされない（ACCESSケースで`access(req->path, req->flags)`が実行される）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | **L1449-1460**: uv_fs_s構造体。path, flags, resultフィールドに注目 |
| 1-2 | uv.h | `include/uv.h` | **L1415**: UV_FS_ACCESS列挙値の定義 |

**読解のコツ**: access機能ではreq->flagsにアクセスモード（R_OK等）を格納する。これはsendfileのin_fd格納とは異なる正統な使い方である。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | uv.h | `include/uv.h` | **L1591-1595**: uv_fs_access()のAPI宣言 |
| 2-2 | fs.c | `src/unix/fs.c` | **L1778-1787**: uv_fs_access()の実装 |

**主要処理フロー**:
1. **L1783**: INIT(ACCESS) - リクエスト初期化
2. **L1784**: PATH - パス設定（非同期時はstrdup）
3. **L1785**: req->flags = flags - アクセスモード設定
4. **L1786**: POST - 非同期/同期実行の分岐

#### Step 3: ワーカースレッドでのディスパッチを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fs.c | `src/unix/fs.c` | **L1700-1750**: uv__fs_work関数。ACCESS case ではaccess(req->path, req->flags)が直接実行される |

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

```
uv_fs_access()                    [src/unix/fs.c L1778]
    |
    +-- INIT(ACCESS)               [src/unix/fs.c L90-104]
    +-- PATH                       [src/unix/fs.c L106-117]
    +-- POST                       [src/unix/fs.c L139-149]
         |
         +-- uv__work_submit()     [スレッドプールへ投入]
              |
              +-- uv__fs_work()    [src/unix/fs.c L1700]
              |    |
              |    +-- access()    [POSIX access(2)]
              |
              +-- uv__fs_done()    [src/unix/fs.c L1753]
                   |
                   +-- req->cb(req)
```

### データフロー図

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

path (ファイルパス) ──> access(2)    ──> req->result (0 or -errno)
mode (R_OK等)       ──> システムコール  ──> コールバック通知
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | uv_fs_access()のAPI宣言 |
| fs.c (Unix) | `src/unix/fs.c` | ソース | Unix系のaccess実装 |
| fs.c (Win) | `src/win/fs.c` | ソース | Windows版のaccess実装 |
| threadpool.c | `src/threadpool.c` | ソース | スレッドプール実装 |
