# 機能設計書 38-Microsoft.Extensions.FileProviders.Physical

## 概要

本ドキュメントは、Microsoft.Extensions.FileProviders.Physical（物理ファイルプロバイダ）機能の設計内容を記述する。この機能はディスク上の物理ファイルシステムへのアクセスを抽象化し、ファイル読み取りと変更監視機能を提供する。

### 本機能の処理概要

Microsoft.Extensions.FileProviders.Physicalは、IFileProviderインターフェースを通じてディスク上のファイルシステムにアクセスするプロバイダーである。ファイル情報の取得、ディレクトリ内容の列挙、ファイル変更の監視を提供する。

**業務上の目的・背景**：アプリケーションは静的ファイル（HTML、CSS、画像等）、設定ファイル、テンプレートファイルなどにアクセスする必要がある。このライブラリは、ファイルシステムアクセスを抽象化することで、テスト容易性と柔軟性を提供する。ファイル変更の自動検知により、設定やテンプレートのホットリロードも実現できる。

**機能の利用シーン**：静的ファイルの配信、設定ファイルの読み込み、Razorビューファイルの読み込み、ファイル変更時の自動リロードなど、ファイルアクセスが必要なシナリオで使用される。

**主要な処理内容**：
1. IFileProviderを通じたファイル情報取得
2. ディレクトリ内容の列挙
3. FileSystemWatcherを使用したファイル変更監視
4. ポーリングベースの変更監視（マウントドライブ対応）
5. Globパターンによるファイルフィルタリング
6. 隠しファイル/システムファイルの除外フィルタ

**関連システム・外部連携**：Microsoft.Extensions.FileProviders.Abstractions、Microsoft.Extensions.Primitives、Microsoft.Extensions.FileSystemGlobbing、Microsoft.Extensions.Configurationと連携する。

**権限による制御**：OSのファイルシステム権限に依存。読み取り権限のないファイル/ディレクトリにはアクセス不可。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングに該当なし |

## 機能種別

データ連携 / ファイルシステムアクセス

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| root | string | Yes | ルートディレクトリパス | 絶対パス必須、存在確認 |
| filters | ExclusionFilters | No | 除外フィルター | Hidden/System/DotPrefixed |
| subpath | string | Yes | ルートからの相対パス | パストラバーサル防止 |
| filter | string | Yes（Watch時） | Globパターン | 有効なGlobパターン |

### 入力データソース

- ディスク上の物理ファイルシステム
- 環境変数DOTNET_USE_POLLING_FILE_WATCHER（ポーリング有効化）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| FileInfo | IFileInfo | ファイル情報 |
| DirectoryContents | IDirectoryContents | ディレクトリ内容 |
| ChangeToken | IChangeToken | ファイル変更通知トークン |

### 出力先

- アプリケーションコードへのファイル情報
- 変更通知のコールバック

## 処理フロー

### 処理シーケンス

```
1. プロバイダー初期化フェーズ
   └─ PhysicalFileProviderインスタンス作成、ルートパス検証
2. ファイル情報取得フェーズ
   └─ GetFileInfo()でファイル情報を返却
3. ディレクトリ列挙フェーズ
   └─ GetDirectoryContents()でディレクトリ内容を返却
4. 変更監視設定フェーズ
   └─ Watch()でPhysicalFilesWatcherにパターン登録
5. 変更検知フェーズ
   └─ FileSystemWatcherまたはポーリングで変更を検知
6. 通知発火フェーズ
   └─ IChangeTokenをトリガーしてコールバック呼び出し
```

### フローチャート

```mermaid
flowchart TD
    A[PhysicalFileProvider作成] --> B[ルートパス検証]
    B --> C{パスが絶対パス?}
    C -->|No| D[ArgumentException]
    C -->|Yes| E{ディレクトリ存在?}
    E -->|No| F[DirectoryNotFoundException]
    E -->|Yes| G[プロバイダー初期化完了]
    G --> H{操作}
    H -->|GetFileInfo| I[相対パス解決]
    I --> J{パストラバーサル?}
    J -->|Yes| K[NotFoundFileInfo返却]
    J -->|No| L{ファイル存在?}
    L -->|Yes| M[PhysicalFileInfo返却]
    L -->|No| K
    H -->|GetDirectoryContents| N[相対パス解決]
    N --> O[PhysicalDirectoryContents返却]
    H -->|Watch| P[PhysicalFilesWatcher取得]
    P --> Q{ポーリング有効?}
    Q -->|Yes| R[PollingFileChangeToken作成]
    Q -->|No| S[FileSystemWatcher登録]
    S --> T[IChangeToken返却]
    R --> T
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-38-01 | 絶対パス必須 | ルートパスは絶対パスでなければならない | コンストラクタ |
| BR-38-02 | パストラバーサル防止 | ..による上位ディレクトリアクセスを防止 | GetFileInfo/GetDirectoryContents |
| BR-38-03 | ルート内制限 | ルートディレクトリ外のファイルにはアクセス不可 | 全操作 |
| BR-38-04 | 除外フィルター | Hidden/System/DotPrefixedファイルを除外可能 | GetFileInfo/GetDirectoryContents |

### 計算ロジック

フルパス計算：
1. ルートパスと相対パスを結合
2. Path.GetFullPath()で正規化
3. ルートパスで始まることを確認
4. パストラバーサルを検出した場合はNotFoundを返却

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ArgumentException | ルートパスが相対パス | 絶対パスを指定 |
| - | DirectoryNotFoundException | ルートディレクトリが存在しない | ディレクトリを作成 |
| - | NotFoundFileInfo | ファイルが見つからない | パスを確認 |
| - | NotFoundDirectoryContents | ディレクトリが見つからない | パスを確認 |

### リトライ仕様

ファイルI/Oエラーは例外として伝播。Watch時の変更検知は内部でハンドリング。

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

該当なし

## パフォーマンス要件

- GetFileInfo: O(1)（ディスクI/O依存）
- GetDirectoryContents: O(n)（ファイル数依存）
- Watch: FileSystemWatcherまたはポーリング（間隔は設定可能）

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

- パストラバーサル攻撃への対策（..の検出）
- ルートディレクトリ外へのアクセス防止
- 隠しファイル/システムファイルの除外
- ファイルアクセス権限はOSに依存

## 備考

- 環境変数DOTNET_USE_POLLING_FILE_WATCHERでポーリングモードを強制
- ブラウザ、iOS、tvOS等ではFileSystemWatcher非対応のためポーリングにフォールバック
- UseActivePollingでアクティブポーリングを有効化可能

---

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

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

### 推奨読解順序

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

ファイルプロバイダーの基本的なインターフェースを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | IFileProvider.cs | `src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/IFileProvider.cs` | プロバイダーインターフェース |
| 1-2 | IFileInfo.cs | `src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/IFileInfo.cs` | ファイル情報インターフェース |
| 1-3 | IDirectoryContents.cs | `src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/IDirectoryContents.cs` | ディレクトリ内容インターフェース |

**読解のコツ**: IFileProvider→IFileInfo/IDirectoryContentsの関係を理解する。プロバイダーがファイル情報とディレクトリ内容を提供する。

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

PhysicalFileProviderの実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | PhysicalFileProvider.cs | `src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileProvider.cs` | メインプロバイダー実装 |

**主要処理フロー**:
1. **44-47行目、54-71行目**: コンストラクタでルートパス検証（絶対パス、存在確認）
2. **263-292行目**: GetFileInfo()でファイル情報を取得（パストラバーサル防止）
3. **306-339行目**: GetDirectoryContents()でディレクトリ内容を取得
4. **355-366行目**: Watch()でファイル変更監視を設定

#### Step 3: 変更監視を理解する

PhysicalFilesWatcherの実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | PhysicalFilesWatcher.cs | `src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs` | ファイル監視実装 |
| 3-2 | PollingFileChangeToken.cs | `src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PollingFileChangeToken.cs` | ポーリングトークン |

**主要処理フロー**:
- **CreateFileChangeToken()**: Globパターンに基づく変更監視トークンを作成
- **FileSystemWatcher**: OSのファイル変更イベントを監視
- **PollingFileChangeToken**: 定期的にファイル状態をポーリング

#### Step 4: ファイル情報を理解する

PhysicalFileInfoとPhysicalDirectoryContentsの実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | PhysicalFileInfo.cs | `src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileInfo.cs` | ファイル情報実装 |
| 4-2 | PhysicalDirectoryContents.cs | `src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalDirectoryContents.cs` | ディレクトリ内容実装 |

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

```
PhysicalFileProvider.GetFileInfo(subpath)
    │
    ├─ subpath.TrimStart(_pathSeparators)
    │
    ├─ Path.IsPathRooted(subpath) → NotFoundFileInfo
    │
    ├─ GetFullPath(subpath)
    │      │
    │      ├─ PathUtils.PathNavigatesAboveRoot() → null
    │      │
    │      └─ Path.GetFullPath(Path.Combine(Root, path))
    │
    └─ new PhysicalFileInfo(new FileInfo(fullPath))

PhysicalFileProvider.Watch(filter)
    │
    ├─ filter検証
    │
    └─ FileWatcher.CreateFileChangeToken(filter)
           │
           └─ PhysicalFilesWatcher.CreateFileChangeToken()
                  │
                  ├─ UsePollingFileWatcher? → PollingFileChangeToken
                  │
                  └─ FileSystemWatcher登録 → IChangeToken
```

### データフロー図

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

root (絶対パス) ───▶ PhysicalFileProvider ───▶ 初期化完了
                              │
                              ▼
GetFileInfo(subpath) ───▶ GetFullPath() ───▶ PhysicalFileInfo
                              │                     │
                              ▼                     ▼
                        パス検証              FileInfo(fullPath)
                              │
                              ▼
                     ルート内チェック
                              │
                              ▼
                   NotFoundFileInfo or PhysicalFileInfo

Watch(filter) ───▶ PhysicalFilesWatcher ───▶ IChangeToken
                              │
                              ▼
                   FileSystemWatcher or Polling
                              │
                              ▼
                      変更検知時にトリガー
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PhysicalFileProvider.cs | `src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileProvider.cs` | ソース | メインプロバイダー |
| PhysicalFileInfo.cs | `src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileInfo.cs` | ソース | ファイル情報 |
| PhysicalDirectoryContents.cs | `src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalDirectoryContents.cs` | ソース | ディレクトリ内容 |
| PhysicalFilesWatcher.cs | `src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFilesWatcher.cs` | ソース | ファイル監視 |
| PollingFileChangeToken.cs | `src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PollingFileChangeToken.cs` | ソース | ポーリングトークン |
| PollingWildCardChangeToken.cs | `src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PollingWildCardChangeToken.cs` | ソース | Globポーリング |
| ExclusionFilters.cs | `src/libraries/Microsoft.Extensions.FileProviders.Physical/src/ExclusionFilters.cs` | ソース | 除外フィルター |
| PathUtils.cs | `src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Internal/PathUtils.cs` | ソース | パスユーティリティ |
