# 機能設計書 60-ファイル操作

## 概要

本ドキュメントは、JenkinsのFilePath（ファイル操作）機能の設計を記述する。FilePathはJenkinsのリモーティング機能と統合されたファイル操作の抽象化レイヤーであり、コントローラーとエージェント間でシームレスなファイル操作を実現する。

### 本機能の処理概要

**業務上の目的・背景**：JenkinsはコントローラーとエージェントからなるJavaの分散アプリケーションである。ビルド処理ではワークスペース内のファイル操作が頻繁に発生するが、そのファイルがコントローラー上にあるのかエージェント上にあるのかを意識せずに操作できる抽象化が必要となる。FilePathは`java.io.File`のリモート対応版として、透過的なファイル操作を提供する。

**機能の利用シーン**：
- ビルドステップでワークスペース内のファイルを読み書きする際
- アーティファクトをアーカイブ・展開する際
- ファイルをコントローラーとエージェント間でコピーする際
- ワークスペースのクリーンアップを行う際
- ファイル一覧の取得やパターンマッチングを行う際

**主要な処理内容**：
1. ローカル/リモートファイルパスの統一的な表現
2. ファイルの読み書き（`read()`/`write()`）
3. ファイル/ディレクトリの作成・削除（`mkdirs()`/`delete()`/`deleteContents()`）
4. ファイルコピー（`copyTo()`/`copyFrom()`/`copyRecursiveTo()`）
5. アーカイブ操作（`zip()`/`unzip()`/`tar()`/`untar()`）
6. FileCallableによるリモートコード実行（`act()`）
7. ファイル一覧取得（`list()`）

**関連システム・外部連携**：
- Jenkins Remoting: エージェントとの通信基盤
- VirtualChannel: リモート呼び出しのチャネル
- VirtualFile: 読み取り専用ファイルの抽象化

**権限による制御**：FilePathの操作自体には直接の権限制御はない。ビルド・ワークスペース操作の権限は呼び出し元で制御される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 18 | ワークスペース | 主機能 | ファイル一覧表示、ダウンロード |
| 16 | アーティファクト | 補助機能 | アーティファクトのアーカイブ |

## 機能種別

ファイル操作 / リモーティング / ユーティリティ

## 入力仕様

### 入力パラメータ（コンストラクタ）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| channel | VirtualChannel | No | リモートチャネル（nullでローカル） | - |
| remote | String | Yes | ファイルパス文字列 | 非null |
| localPath | File | - | ローカルファイル（別コンストラクタ） | - |
| base | FilePath | - | ベースパス（別コンストラクタ） | - |
| rel | String | - | 相対パス（別コンストラクタ） | - |

### 入力データソース

- ファイルシステム: ローカルまたはリモートのファイル/ディレクトリ
- InputStream: ファイル書き込み用のデータストリーム
- URL: ダウンロード元のリソース

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| remote | String | ファイルパス文字列 |
| channel | VirtualChannel | 関連付けられたリモートチャネル |
| InputStream | InputStream | ファイル読み込みストリーム |
| OutputStream | OutputStream | ファイル書き込みストリーム |

### 出力先

- ファイルシステム: ファイルの作成・変更・削除
- OutputStream: ファイル内容の出力
- リモートエージェント: リモート操作の結果

## 処理フロー

### 処理シーケンス

```
1. FilePathオブジェクトの作成
   └─ channel（リモートチャネル）とremote（パス文字列）を設定
2. ファイル操作の呼び出し
   └─ 例: mkdirs(), read(), write(), copyTo()等
3. チャネル判定
   └─ channel != null: リモート実行
   └─ channel == null: ローカル実行
4. リモートの場合
   └─ FileCallableをシリアライズしてリモートに送信
   └─ リモートでinvoke()を実行
   └─ 結果をシリアライズして返却
5. ローカルの場合
   └─ 直接java.io.Fileとして操作
```

### フローチャート

```mermaid
flowchart TD
    A[FilePath操作呼び出し] --> B{channel != null?}
    B -->|Yes| C[リモート実行]
    B -->|No| D[ローカル実行]
    C --> E[FileCallable作成]
    E --> F[channel.call]
    F --> G[リモートでinvoke]
    G --> H[結果をシリアライズ]
    H --> I[結果返却]
    D --> J[File操作実行]
    J --> I
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-60-01 | パス正規化 | パスは「.」「..」を解決して正規化される | コンストラクタ |
| BR-60-02 | クロスプラットフォーム | Windows/Unix両対応のパス解決 | パス解決時 |
| BR-60-03 | シリアライズ | FilePathはリモーティング経由でのみシリアライズ可能 | リモート転送時 |
| BR-60-04 | チャネル反転 | リモートに転送されるとchannelの向きが反転する | リモート転送時 |

### 計算ロジック

パス正規化（`normalize()`）:
- 絶対パスプレフィックス（`C:\`、`/`、`\\`等）を検出
- 「.」「..」を解決
- 重複セパレータを除去

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

本機能はデータベースを操作しない。ファイルシステムに対する操作を行う。

### ファイル操作

| 操作 | メソッド | 概要 |
|-----|---------|------|
| ファイル読み込み | `read()` | InputStreamを返却 |
| ファイル書き込み | `write()` | OutputStreamを返却 |
| ディレクトリ作成 | `mkdirs()` | 必要な親ディレクトリも作成 |
| ファイル削除 | `delete()` | ファイルまたはディレクトリを削除 |
| 内容削除 | `deleteContents()` | ディレクトリ内容のみ削除 |
| コピー | `copyTo()`, `copyFrom()` | ファイルコピー |
| 再帰コピー | `copyRecursiveTo()` | ディレクトリの再帰コピー |
| ZIP作成 | `zip()` | ZIPアーカイブ作成 |
| ZIP展開 | `unzip()`, `unzipFrom()` | ZIPアーカイブ展開 |
| TAR作成 | `tar()` | TARアーカイブ作成 |
| TAR展開 | `untar()`, `untarFrom()` | TARアーカイブ展開 |
| 一覧取得 | `list()` | ファイル一覧取得 |
| 存在確認 | `exists()` | ファイル/ディレクトリ存在確認 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | IOException | ファイル操作失敗 | 例外スロー、詳細メッセージ付き |
| - | InterruptedException | 操作中断 | 例外スロー |
| - | NotSerializableException | シリアライズ失敗 | 例外スロー（コンテキスト外使用） |

### リトライ仕様

- `installIfNecessaryFrom()`: HTTPリダイレクトを最大20回フォロー
- その他の操作: 基本的にリトライしない

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

本機能はトランザクション管理を行わない。ファイル操作はアトミックではない。

## パフォーマンス要件

- リモート操作: ネットワーク遅延とシリアライズコストが発生
- 大量ファイル操作: `copyRecursiveTo()`等ではTARストリーミングで効率化
- 並列処理: `actAsync()`で非同期実行可能

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

- FileCallableはControllerToAgentFileCallable使用を推奨（エージェントからコントローラーへの呼び出しを防止）
- パストラバーサル対策: `child()`でシンボリックリンクのチェックが可能
- ZIPスリップ対策: 展開時にパス検証を実施

## 備考

- FilePathはローカルチャネル（LocalChannel）の場合、channelをnullとして扱う
- `isRemote()`でリモートパスかどうかを判定可能
- `isUnix()`でUnix/Windows判定（パスセパレータから推測）
- `VirtualFile`はFilePathの読み取り専用版として使用可能

---

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

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

### 推奨読解順序

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

まず、FilePathのフィールド構造とコンストラクタを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | FilePath.java | `core/src/main/java/hudson/FilePath.java` | クラス定義、channel/remoteフィールド |

**読解のコツ**: `channel`フィールドはリモートパスの場合はリモートへのチャネル、ローカルパスの場合はnull。リモーティング経由で転送されるとこの値が反転する（Javadocの226-237行目参照）。

**主要処理フロー**:
1. **214行目**: `public final class FilePath implements SerializableOnlyOverRemoting`
2. **238行目**: `private transient VirtualChannel channel`（transientでシリアライズ時に特殊処理）
3. **246行目**: `private /*final*/ String remote`
4. **255-258行目**: メインコンストラクタ（channel, remote）
5. **267-270行目**: ローカルファイルコンストラクタ
6. **277-280行目**: ベースパス+相対パスコンストラクタ

#### Step 2: パス正規化を理解する

パス文字列の正規化処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | FilePath.java | `core/src/main/java/hudson/FilePath.java` | normalize()メソッド |

**主要処理フロー**:
- **314-370行目**: `normalize()`メソッドでパス正規化
- **302-304行目**: `isAbsolute()`で絶対パス判定
- **306-308行目**: DRIVE_PATTERN, UNC_PATTERN, ABSOLUTE_PREFIX_PATTERNの定義

#### Step 3: リモート実行を理解する

FileCallableによるリモートコード実行を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | FilePath.java | `core/src/main/java/hudson/FilePath.java` | FileCallable、act()メソッド |

**主要処理フロー**:
- **1176-1190行目**: `FileCallable`インターフェースの定義
- **1196-1216行目**: `act(FileCallable)`メソッドの実装
- **1201-1208行目**: リモート実行時のラッパー処理
- **1212-1214行目**: ローカル実行時の直接呼び出し

#### Step 4: 主要操作を理解する

よく使用されるファイル操作メソッドを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | FilePath.java | `core/src/main/java/hudson/FilePath.java` | mkdirs(), copyTo(), zip()等 |

**主要処理フロー**:
- **1387-1391行目**: `mkdirs()`でディレクトリ作成
- **1116-1160行目**: `copyFrom()`シリーズでファイルコピー
- **412-420行目**: `zip()`でZIPアーカイブ作成
- **548-556行目**: `unzip()`でZIPアーカイブ展開

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

```
FilePath操作（例: mkdirs()）
    │
    ├─ act(FileCallable)
    │      │
    │      ├─ channel != null（リモート）
    │      │      │
    │      │      └─ FileCallableWrapper作成
    │      │             │
    │      │             └─ channel.call(wrapper)
    │      │                    │
    │      │                    └─ リモートでinvoke()実行
    │      │
    │      └─ channel == null（ローカル）
    │             │
    │             └─ callable.invoke(new File(remote), localChannel)
    │
    └─ 結果返却
```

### データフロー図

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

FilePath              act(FileCallable)              結果/ストリーム
(channel, remote) ───▶ (チャネル判定)         ───▶
      │                      │
      ├─ リモート            │                        リモート実行
      │  channel!=null ──▶  channel.call()     ───▶    結果シリアライズ
      │                                                     │
      └─ ローカル            │                        ローカル実行
         channel==null ──▶  直接File操作       ───▶    直接結果
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| FilePath.java | `core/src/main/java/hudson/FilePath.java` | ソース | メインクラス（3000行超） |
| VirtualFile.java | `core/src/main/java/jenkins/util/VirtualFile.java` | ソース | 読み取り専用ファイル抽象化 |
| VirtualChannel.java | `remoting/src/main/java/hudson/remoting/VirtualChannel.java` | ソース | リモートチャネルインターフェース |
| MasterToSlaveFileCallable.java | `core/src/main/java/jenkins/MasterToSlaveFileCallable.java` | ソース | コントローラー→エージェント用FileCallable |
| ControllerToAgentFileCallable.java | `core/src/main/java/jenkins/agents/ControllerToAgentFileCallable.java` | ソース | 推奨FileCallable基底クラス |
| DirScanner.java | `core/src/main/java/hudson/util/DirScanner.java` | ソース | ディレクトリスキャンユーティリティ |
