# 機能設計書 108-シンボリックリンク操作

## 概要

本ドキュメントは、libuvが提供するシンボリックリンク操作機能（uv_fs_symlink / uv_fs_readlink / uv_fs_realpath / uv_fs_link）の設計仕様を記載する。

### 本機能の処理概要

シンボリックリンクの作成・読み取り・解決、およびハードリンクの作成を非同期で行う機能群を提供する。

**業務上の目的・背景**：ファイルシステム上のリンク管理はデプロイメント、パッケージ管理、バージョン管理などで広く利用される。シンボリックリンクによるバージョン切り替えや、ハードリンクによるスペース効率的なファイル管理が可能となる。realpathによるパス正規化はセキュリティ上も重要で、パストラバーサル攻撃の防御に使用される。

**機能の利用シーン**：ソフトウェアのバージョン切り替え（/usr/local/bin/node -> node-v18）、設定ファイルのシンボリックリンク管理、パス正規化によるセキュリティチェック、ハードリンクによるバックアップスペース節約など。

**主要な処理内容**：
1. symlink: シンボリックリンクの作成（Windows用のフラグサポート）
2. readlink: シンボリックリンクのリンク先パスを取得
3. realpath: パスを正規化（シンボリックリンクを解決し絶対パスを返す）
4. link: ハードリンクの作成

**関連システム・外部連携**：POSIXのsymlink()/readlink()/realpath()/link()、Linux io_uringによるsymlink/link高速化。

**権限による制御**：シンボリックリンク/ハードリンクの作成にはターゲットディレクトリへの書き込み権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | ファイルシステム操作 | 主機能 | uv_fs_symlink()/readlink()/realpath()/link()によるリンク操作のAPI定義 |

## 機能種別

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

## 入力仕様

### 入力パラメータ

**uv_fs_symlink:**

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | - |
| req | uv_fs_t* | Yes | FSリクエスト | NULLでUV_EINVAL |
| path | const char* | Yes | リンク先（ターゲット） | assert(path != NULL) |
| new_path | const char* | Yes | リンク名（作成先） | assert(new_path != NULL) |
| flags | int | Yes | フラグ（UV_FS_SYMLINK_DIR/JUNCTION） | Windowsでのみ使用 |
| cb | uv_fs_cb | No | コールバック | NULLで同期実行 |

**uv_fs_readlink / uv_fs_realpath:**

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

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | - |
| req | uv_fs_t* | Yes | FSリクエスト | NULLでUV_EINVAL |
| path | const char* | Yes | 既存ファイルパス | assert(path != NULL) |
| new_path | const char* | Yes | 新しいリンク名 | assert(new_path != NULL) |
| cb | uv_fs_cb | No | コールバック | NULLで同期実行 |

### 入力データソース

ユーザーがAPI呼び出し時に指定するパス。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | ssize_t | 成功時0、失敗時は負のエラーコード |
| ptr | void* | readlink/realpath: 解決されたパス文字列（動的確保） |

### 出力先

uv_fs_t構造体のresultフィールドおよびptrフィールド。readlink/realpathの結果文字列はuv_fs_req_cleanup()で解放される。

## 処理フロー

### 処理シーケンス

```
1. INITマクロによるリクエスト初期化
2. パラメータ設定
   └─ symlink/link: PATH2マクロで2つのパスを設定
   └─ readlink/realpath: PATHマクロでパスを設定
3. [symlink/link, Linux非同期] io_uring最適化の試行
4. POSTマクロによる実行
5. 内部処理
   └─ symlink: symlink(path, new_path)
   └─ readlink: readlink()でリンク先取得、バッファ動的確保
   └─ realpath: realpath()でパス正規化、結果をstrdup
   └─ link: link(path, new_path)
```

### フローチャート

```mermaid
flowchart TD
    A[API呼び出し] --> B{操作種別}
    B -->|symlink| C[symlink作成]
    B -->|readlink| D[リンク先読み取り]
    B -->|realpath| E[パス正規化]
    B -->|link| F[ハードリンク作成]
    D --> G[PATH_MAX計算]
    G --> H[バッファ確保]
    H --> I[readlink呼び出し]
    I --> J[NUL終端付加]
    J --> K[req->ptr設定]
    E --> L[realpath呼び出し]
    L --> M[結果をstrdup]
    M --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-801 | Windowsフラグ | UV_FS_SYMLINK_DIR(0x0001)とUV_FS_SYMLINK_JUNCTION(0x0002)はWindows用 | Windows |
| BR-802 | readlinkバッファ管理 | PATH_MAXまたはファイルサイズからバッファサイズを決定し動的確保 | readlink |
| BR-803 | readlink NUL終端 | readlink()はNUL終端しないため、明示的に追加する | readlink |
| BR-804 | readlinkバッファリサイズ | len == maxlenの場合、バッファをlen+1にリサイズ | readlink |
| BR-805 | realpath動的確保 | POSIX 200809L以降ではrealpath(path, NULL)を使用し、結果をstrdupしてfreeする | realpath |
| BR-806 | io_uring最適化 | Linux非同期ではsymlink/linkにio_uringを試行 | Linux非同期 |

### 計算ロジック

readlinkのバッファサイズ決定：
- `_POSIX_PATH_MAX`または`PATH_MAX`が定義されている場合: `pathconf(path, _PC_PATH_MAX)`を使用
- 定義されていない場合: `lstat()`でシンボリックリンクのサイズを取得し、0の場合はデフォルト値を使用

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

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | パラメータエラー | reqがNULL、readlinkの対象がリンクでない | パラメータを確認 |
| UV_ENOENT | パス不在 | 対象パスが存在しない | パスを確認 |
| UV_EEXIST | 既存パス | symlink/linkの作成先が既に存在 | 作成先を確認 |
| UV_EACCES | 権限エラー | 書き込み権限がない | 権限を確認 |
| UV_ENOMEM | メモリ不足 | バッファ確保に失敗 | メモリを解放 |
| UV_EXDEV | クロスデバイス | linkで異なるファイルシステム間のハードリンク | symlink使用を検討 |

### リトライ仕様

EINTRで中断された場合、自動リトライされる。

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

該当なし

## パフォーマンス要件

- symlink/linkではLinux環境でio_uringによる高速化が可能
- readlinkではバッファの動的確保とリサイズが発生する場合がある

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

- realpathはパストラバーサル攻撃の防御に使用可能
- シンボリックリンクの作成はTOCTOU攻撃の対象となりうる
- readlinkの結果は信頼できない場合がある（レースコンディション）

## 備考

- readlinkの結果とrealpathの結果はreq->ptrに格納され、uv_fs_req_cleanup()で解放される
- MVS環境ではos390_readlink()を使用する特殊実装がある
- UV_FS_SYMLINK_DIRとUV_FS_SYMLINK_JUNCTIONはUnixでは無視される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | UV_FS_SYMLINK_DIR/JUNCTION定義（1635-1641行目） |
| 1-2 | uv.h | `include/uv.h` | symlink/readlink/realpath/link API宣言（1625-1656行目） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fs.c | `src/unix/fs.c` | uv_fs_symlink()実装（2167-2180行目）。io_uring最適化あり |
| 2-2 | fs.c | `src/unix/fs.c` | uv_fs_readlink()実装（2100-2107行目） |
| 2-3 | fs.c | `src/unix/fs.c` | uv_fs_realpath()実装（2110-2117行目） |
| 2-4 | fs.c | `src/unix/fs.c` | uv_fs_link()実装（1948-1959行目）。io_uring最適化あり |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fs.c | `src/unix/fs.c` | uv__fs_readlink()実装（734-791行目）。バッファ管理とNUL終端 |
| 3-2 | fs.c | `src/unix/fs.c` | uv__fs_realpath()実装（793-829行目）。POSIX版とフォールバック版 |
| 3-3 | fs.c | `src/unix/fs.c` | uv__fs_pathmax_size()実装（723-732行目）。PATH_MAX取得 |

**主要処理フロー**:
- **734-791行目**: uv__fs_readlink -- バッファ確保、readlink()、NUL終端、リサイズ
- **793-829行目**: uv__fs_realpath -- realpath(path, NULL)またはバッファ確保版realpath()

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

```
uv_fs_symlink()
    +-- INIT(SYMLINK) + PATH2 + flags
    +-- [Linux非同期] uv__iou_fs_symlink()
    +-- POST -> uv__fs_work -> symlink(req->path, req->new_path)

uv_fs_readlink()
    +-- INIT(READLINK) + PATH
    +-- POST -> uv__fs_work -> uv__fs_readlink()
                                   +-- uv__fs_pathmax_size()
                                   +-- uv__malloc()
                                   +-- readlink()
                                   +-- req->ptr = buf

uv_fs_realpath()
    +-- INIT(REALPATH) + PATH
    +-- POST -> uv__fs_work -> uv__fs_realpath()
                                   +-- realpath()
                                   +-- uv__strdup() / req->ptr = buf

uv_fs_link()
    +-- INIT(LINK) + PATH2
    +-- [Linux非同期] uv__iou_fs_link()
    +-- POST -> uv__fs_work -> link(req->path, req->new_path)
```

### データフロー図

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

path + new_path  -------> symlink()  ------------>  result (0 or error)
path  -------------------> readlink() ------------>  ptr (リンク先パス文字列)
path  -------------------> realpath() ------------>  ptr (正規化パス文字列)
path + new_path  -------> link()     ------------>  result (0 or error)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | API宣言、フラグ定義 |
| fs.c | `src/unix/fs.c` | ソース | Unix系のリンク操作実装 |
| fs.c | `src/win/fs.c` | ソース | Windows版実装 |
