# 機能設計書 98-ファイルコピー

## 概要

本ドキュメントは、libuvにおけるファイルコピー機能（uv_fs_copyfile）の設計仕様を記述する。ファイルを非同期でコピーし、メタデータ（パーミッション、タイムスタンプ、所有者）も保持する機能である。

### 本機能の処理概要

**業務上の目的・背景**：ファイルコピーは多くのアプリケーションで必要とされる基本操作である。libuvはクロスプラットフォームなファイルコピーAPIを提供し、EXCL（排他的コピー）、FICLONE（Copy-on-Write）、FICLONE_FORCE（COW強制）といったオプションもサポートする。ソースファイルのメタデータ（パーミッション、タイムスタンプ、所有者）も自動的にコピー先に反映される。

**機能の利用シーン**：ファイルのバックアップ作成、設定ファイルのコピー、テンプレートからのファイル生成、COW対応ファイルシステムでの効率的なコピーなどで利用される。

**主要な処理内容**：
1. フラグの妥当性を検証する
2. ソースファイルをオープンし、メタ情報を取得する
3. コピー先ファイルをオープンする
4. FICLONE対応の場合はioctl(FICLONE)によるCOWコピーを試みる
5. COWが失敗または非対応の場合はuv_fs_sendfile()でデータをコピーする
6. タイムスタンプ、所有者、パーミッションをコピーする
7. エラー時はコピー先ファイルを削除する

**関連システム・外部連携**：POSIX open()/close()/fstat()/futimens()/fchown()/fchmod()、Linux ioctl(FICLONE)、uv_fs_sendfile()。

**権限による制御**：ソースファイルの読み取り権限、コピー先ディレクトリの書き込み権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | ファイルシステム操作 | 主機能 | uv_fs_copyfile()による非同期ファイルコピーのAPI定義 |

## 機能種別

ファイルI/O操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | NULLでないこと |
| req | uv_fs_t* | Yes | ファイルシステムリクエスト | NULLでないこと |
| path | const char* | Yes | コピー元ファイルパス | NULLでないこと |
| new_path | const char* | Yes | コピー先ファイルパス | NULLでないこと |
| flags | int | Yes | コピーオプションフラグ | UV_FS_COPYFILE_EXCL/FICLONE/FICLONE_FORCEの組み合わせ |
| cb | uv_fs_cb | No | 完了コールバック | - |

### フラグ定義

| フラグ名 | 値 | 説明 |
|---------|-----|------|
| UV_FS_COPYFILE_EXCL | 0x0001 | コピー先が既に存在する場合はエラーを返す |
| UV_FS_COPYFILE_FICLONE | 0x0002 | COW（Copy-on-Write）コピーを試みる。失敗時はフォールバック |
| UV_FS_COPYFILE_FICLONE_FORCE | 0x0004 | COWコピーを強制。失敗時はエラー |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値（同期） | int | 成功時は0、失敗時は負のエラーコード |
| 戻り値（非同期） | int | 常に0 |
| req->result | ssize_t | コールバック内で参照。0または負のエラーコード |

### 出力先

呼び出し元への戻り値。コピー先ファイルがファイルシステム上に作成される。

## 処理フロー

### 処理シーケンス

```
1. フラグの検証（無効なフラグの場合はUV_EINVALを返す）
2. ソースファイルをO_RDONLYでオープンする
3. fstat()でソースファイルのメタ情報を取得する
4. コピー先ファイルをオープンする（EXCL時はO_EXCLフラグ付き）
5. [非EXCL] ソースとコピー先が同一ファイルでないことを確認する
6. [非EXCL] コピー先ファイルをftruncate()で切り詰める
7. futimens()でタイムスタンプをコピーする
8. fchown()/fchmod()で所有者とパーミッションをコピーする
9. [FICLONE対応] ioctl(FICLONE)でCOWコピーを試みる
   └─ 成功した場合はデータコピーをスキップ
   └─ FICLONE_FORCEで失敗した場合はエラー
10. sendfile()でデータをコピーする（チャンク単位のループ）
11. ソース・コピー先ファイルをクローズする
12. エラー時はコピー先ファイルをunlink()で削除する
```

### フローチャート

```mermaid
flowchart TD
    A[uv_fs_copyfile] --> B{フラグ有効?}
    B -->|No| C[return UV_EINVAL]
    B -->|Yes| D[ソースopen]
    D --> E[fstat]
    E --> F[コピー先open]
    F --> G{EXCL?}
    G -->|No| H{同一ファイル?}
    H -->|Yes| I[goto out - 成功]
    H -->|No| J[ftruncate]
    G -->|Yes| K[タイムスタンプコピー]
    J --> K
    K --> L[fchown/fchmod]
    L --> M{FICLONE?}
    M -->|Yes| N[ioctl FICLONE]
    N -->|成功| I
    N -->|失敗+FORCE| O[エラー]
    N -->|失敗+非FORCE| P[sendfileコピー]
    M -->|No| P
    P --> I
    I --> Q[close src/dst]
    Q --> R{エラーあり?}
    R -->|Yes| S[unlink dst]
    R -->|No| T[return 0]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-98-1 | フラグ検証 | EXCL/FICLONE/FICLONE_FORCE以外のフラグが設定された場合はUV_EINVAL | 常時 |
| BR-98-2 | 同一ファイル検出 | ソースとコピー先のst_dev/st_inoが一致する場合はコピーをスキップ | 非EXCL時 |
| BR-98-3 | メタデータコピー | タイムスタンプ・所有者・パーミッションをソースからコピーする | 常時 |
| BR-98-4 | FICLONE優先 | FICLONEフラグが指定された場合はCOWコピーを優先試行する | FICLONE/FICLONE_FORCE時 |
| BR-98-5 | エラー時クリーンアップ | コピー失敗時はコピー先ファイルを削除する | エラー発生時 |
| BR-98-6 | CIFS/SMB互換 | LinuxでCIFS/SMBマウントのfchmod() EPERMを許容する | Linux, CIFS/SMBファイルシステム |

### 計算ロジック

特になし。

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | 不正フラグ | 無効なフラグの組み合わせ | 有効なフラグを指定する |
| UV_EEXIST | ファイル既存 | EXCL指定時にコピー先が既に存在 | 別のパスを指定するか、EXCLを外す |
| UV_ENOENT | 不存在 | ソースファイルが存在しない | パスを確認する |
| UV_ENOSYS | 未サポート | FICLONE_FORCEでCOW非対応のファイルシステム | FICLONEまたはフラグなしに変更 |

### リトライ仕様

自動リトライはuv__fs_work()のdo-whileで行われる。

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

該当なし。コピー中のエラーではコピー先ファイルを削除してクリーンアップする。

## パフォーマンス要件

- COW対応ファイルシステムではFICLONEにより高速コピーが可能
- 通常のコピーはsendfile()を使用し、ユーザー空間へのデータコピーを回避
- 大規模ファイルはチャンク単位（SSIZE_MAX）でコピーする

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

- ソースファイルの所有者/パーミッションがコピーされるため、機密ファイルのコピー時は注意が必要
- fchown()の失敗は無視される（cpコマンドの挙動に合わせる）

## 備考

- 内部的にuv_fs_open(), uv_fs_sendfile(), uv_fs_unlink(), uv_fs_req_cleanup()を使用する
- FICLONE機能はLinuxカーネルのファイルシステムサポートに依存する（Btrfs, XFS等）
- タイムスタンプのコピーはfutimens()を使用し、プラットフォームごとの差異を吸収する

---

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

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

### 推奨読解順序

#### Step 1: データ構造とフラグ定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | コピーフラグ定義（1502-1514行目）。EXCL/FICLONE/FICLONE_FORCE |
| 1-2 | uv.h | `include/uv.h` | API宣言（1516-1521行目） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fs.c | `src/unix/fs.c` | uv_fs_copyfile()（2274-2291行目）。フラグ検証とPATH2マクロ |

**主要処理フロー**:
- **2282-2286行目**: 無効フラグの検証
- **2288行目**: `PATH2` - 両パスの設定
- **2289行目**: `req->flags = flags` - フラグの設定

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fs.c | `src/unix/fs.c` | uv__fs_copyfile()（1227-1427行目）。コピーのコア実装 |

**主要処理フロー**:
- **1246行目**: ソースファイルをO_RDONLYでオープン
- **1253行目**: `uv__fstat()` でメタ情報取得
- **1264-1270行目**: コピー先ファイルをオープン
- **1287-1290行目**: 同一ファイルの検出（st_dev/st_ino比較）
- **1293-1308行目**: ftruncate()による切り詰め
- **1327行目**: `futimens()` でタイムスタンプコピー
- **1338-1357行目**: `fchown()`/`fchmod()` で所有者/パーミッションコピー
- **1359-1378行目**: FICLONE処理
- **1382-1397行目**: sendfile()によるデータコピーのループ
- **1421-1424行目**: エラー時のコピー先ファイル削除

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

```
uv_fs_copyfile(loop, req, path, new_path, flags, cb)
    |
    +-- INIT(COPYFILE)
    +-- PATH2
    +-- POST → uv__fs_work() → uv__fs_copyfile(req)
            |
            +-- uv_fs_open(src, O_RDONLY)
            +-- uv__fstat(srcfd)
            +-- uv_fs_open(dst, O_WRONLY|O_CREAT[|O_EXCL])
            +-- [非EXCL] uv__fstat(dstfd) → 同一ファイル判定
            +-- [非EXCL] ftruncate(dstfd, 0)
            +-- futimens(dstfd, times)
            +-- fchown(dstfd, uid, gid)
            +-- fchmod(dstfd, mode)
            +-- [FICLONE] ioctl(dstfd, FICLONE, srcfd)
            +-- [フォールバック] uv_fs_sendfile() ループ
            +-- close(srcfd), close(dstfd)
            +-- [エラー] uv_fs_unlink(new_path)
```

### データフロー図

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

path (src)          ───> open → fstat → read  ───>
                                                     sendfile/FICLONE
new_path (dst)      ───> open → truncate      ───> コピー先ファイル
int flags           ───> フラグ判定           ───>
                         metadata copy         ───> timestamp/owner/perm
```

### 関連ファイル一覧

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