# 機能設計書 107-ファイルタイムスタンプ変更

## 概要

本ドキュメントは、libuvが提供するファイルタイムスタンプ変更機能（uv_fs_utime / uv_fs_futime / uv_fs_lutime）の設計仕様を記載する。

### 本機能の処理概要

ファイルのアクセス時刻（atime）および修正時刻（mtime）を非同期で変更する機能を提供する。パス指定（utime）、ファイルディスクリプタ指定（futime）、シンボリックリンク非追跡（lutime）の3種類のAPIを備える。

**業務上の目的・背景**：ファイルのタイムスタンプ管理はビルドシステム、バックアップツール、ファイル同期ツールで重要な役割を果たす。コピーしたファイルのタイムスタンプを元ファイルに合わせたり、ビルドアーティファクトの更新日時を制御したりする場合に使用される。UV_FS_UTIME_NOWとUV_FS_UTIME_OMITの特殊値により、現在時刻への設定や特定フィールドの変更スキップも可能。

**機能の利用シーン**：ファイルコピー時のタイムスタンプ保持、ビルドシステムでのファイル更新日時制御、バックアップリストア時のタイムスタンプ復元、touchコマンド相当の操作、シンボリックリンク自体のタイムスタンプ変更など。

**主要な処理内容**：
1. リクエスト構造体を初期化し、対象パスまたはFDとatime/mtimeを設定する
2. プラットフォームに応じた内部実装関数を呼び出す
3. utimensat/futimensまたはutime/utimesで時刻を変更する

**関連システム・外部連携**：POSIXのutimensat()/futimens()/utime()、UV_FS_UTIME_NOW（INFINITY）/UV_FS_UTIME_OMIT（NAN）マクロ。

**権限による制御**：ファイル所有者またはroot権限、もしくはファイルへの書き込み権限が必要（atimeのみの変更は制限が緩い場合がある）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | ファイルシステム操作 | 主機能 | uv_fs_utime()/futime()/lutime()によるタイムスタンプ変更のAPI定義 |

## 機能種別

データ更新処理（ファイルメタデータの変更）

## 入力仕様

### 入力パラメータ

**uv_fs_utime / uv_fs_lutime:**

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | - |
| req | uv_fs_t* | Yes | FSリクエスト | NULLでUV_EINVAL |
| path | const char* | Yes | 対象パス | assert(path != NULL) |
| atime | double | Yes | アクセス時刻（秒、小数部はナノ秒） | INFINITY=now, NAN=omit |
| mtime | double | Yes | 修正時刻（秒、小数部はナノ秒） | INFINITY=now, NAN=omit |
| cb | uv_fs_cb | No | コールバック | NULLで同期実行 |

**uv_fs_futime:**

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | - |
| req | uv_fs_t* | Yes | FSリクエスト | NULLでUV_EINVAL |
| file | uv_file | Yes | ファイルディスクリプタ | 有効なFD |
| atime | double | Yes | アクセス時刻 | INFINITY=now, NAN=omit |
| mtime | double | Yes | 修正時刻 | INFINITY=now, NAN=omit |
| cb | uv_fs_cb | No | コールバック | NULLで同期実行 |

### 入力データソース

ユーザーがAPI呼び出し時に指定するパスまたはFD、atime/mtime。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | ssize_t | 成功時0、失敗時は負のエラーコード |

### 出力先

uv_fs_t構造体のresultフィールド。

## 処理フロー

### 処理シーケンス

```
1. INITマクロによるリクエスト初期化
2. パラメータ設定
   └─ utime/lutime: PATH + req->atime + req->mtime
   └─ futime: req->file + req->atime + req->mtime
3. POSTマクロによる実行
4. 内部関数での時刻変換と設定
   └─ uv__fs_to_timespec()でdoubleからstruct timespecに変換
   └─ INFINITY -> UTIME_NOW, NAN -> UTIME_OMIT
   └─ utime: utimensat(AT_FDCWD, path, ts, 0)
   └─ futime: futimens(file, ts)
   └─ lutime: utimensat(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW)
```

### フローチャート

```mermaid
flowchart TD
    A[API呼び出し] --> B{操作種別}
    B -->|utime| C[INIT + PATH + atime/mtime]
    B -->|futime| D[INIT + file + atime/mtime]
    B -->|lutime| E[INIT + PATH + atime/mtime]
    C --> F[POST: 実行]
    D --> F
    E --> F
    F --> G[uv__fs_to_timespec変換]
    G --> H{INFINITY/NAN?}
    H -->|INFINITY| I[UTIME_NOW設定]
    H -->|NAN| J[UTIME_OMIT設定]
    H -->|通常値| K[sec/nsec分離]
    I --> L[utimensat/futimens呼び出し]
    J --> L
    K --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-701 | UV_FS_UTIME_NOW | INFINITYが渡された場合、UTIME_NOWとして現在時刻を設定 | atime/mtimeがINFINITY |
| BR-702 | UV_FS_UTIME_OMIT | NANが渡された場合、UTIME_OMITとしてそのフィールドを変更しない | atime/mtimeがNAN |
| BR-703 | ナノ秒精度 | doubleの小数部をナノ秒に変換（(time - tv_sec) * 1e9） | 通常値 |
| BR-704 | 負ナノ秒補正 | tv_nsecが負の場合、1e9を加算しtv_secを1減算する | tv_nsec < 0 |
| BR-705 | lutimeのリンク非追跡 | utimensatにAT_SYMLINK_NOFOLLOWフラグを付与 | lutime |
| BR-706 | プラットフォーム非対応 | 一部プラットフォーム（非POSIX）ではENOSYSを返す | 非対応環境 |

### 計算ロジック

```c
// doubleからstruct timespecへの変換
ts.tv_sec  = (long)time;
ts.tv_nsec = (time - ts.tv_sec) * 1e9;
if (ts.tv_nsec < 0) {
    ts.tv_nsec += 1e9;
    ts.tv_sec -= 1;
}
```

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

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | パラメータエラー | reqがNULL | 有効なリクエスト構造体を渡す |
| UV_ENOENT | ファイル不在 | 指定パスが存在しない | パスの正当性を確認する |
| UV_EACCES | 権限エラー | 権限が不足 | 適切な権限で実行 |
| UV_ENOSYS | 非対応 | プラットフォームで非サポート | 代替手段を検討 |
| UV_EBADF | 不正FD | futimeに無効なFDが渡された | 有効なFDを確認する |

### リトライ仕様

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

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

該当なし

## パフォーマンス要件

システムコール1回で完了するため、パフォーマンス上の懸念はない。

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

- タイムスタンプの偽装により、ファイルの更新日時に基づく検知を回避する攻撃が可能
- 監査ログと組み合わせて使用することを推奨

## 備考

- UV_FS_UTIME_NOWはINFINITYとして定義（uv.h 1601行目）
- UV_FS_UTIME_OMITはNANとして定義（uv.h 1602行目）
- AIX 7.1未満ではutime()にフォールバックされ、ナノ秒精度が失われる
- MVS環境では__fchattr/__lchattrを使用する特殊実装

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | UV_FS_UTIME_NOW/UV_FS_UTIME_OMITマクロ定義（1601-1602行目） |
| 1-2 | uv.h | `include/uv.h` | uv_fs_t構造体のatime/mtimeフィールド（プライベートフィールド内） |

**読解のコツ**: INFINITY/NANはC99の浮動小数点定数であり、uv__isinf()/uv__isnan()で検出される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fs.c | `src/unix/fs.c` | uv_fs_utime()実装（2193-2204行目） |
| 2-2 | fs.c | `src/unix/fs.c` | uv_fs_futime()実装（1911-1922行目） |
| 2-3 | fs.c | `src/unix/fs.c` | uv_fs_lutime()実装（1924-1935行目） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fs.c | `src/unix/fs.c` | uv__fs_to_timespec()実装（216-232行目）。doubleからtimespecへの変換ロジック |
| 3-2 | fs.c | `src/unix/fs.c` | uv__fs_utime()実装（1141-1173行目）。utimensat呼び出し、AIX/MVSフォールバック |
| 3-3 | fs.c | `src/unix/fs.c` | uv__fs_futime()実装（236-263行目）。futimens呼び出し |
| 3-4 | fs.c | `src/unix/fs.c` | uv__fs_lutime()実装（1176-1195行目）。AT_SYMLINK_NOFOLLOW付きutimensat |

**主要処理フロー**:
- **216-232行目**: uv__fs_to_timespec -- INFINITY->UTIME_NOW、NAN->UTIME_OMIT、通常値->sec+nsec分離
- **1141-1155行目**: uv__fs_utime -- utimensat(AT_FDCWD, path, ts, 0)
- **1190行目**: uv__fs_lutime -- utimensat(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW)

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

```
uv_fs_utime()
    +-- INIT(UTIME) + PATH + atime/mtime
    +-- POST -> uv__fs_work -> uv__fs_utime()
                                   +-- uv__fs_to_timespec() x2
                                   +-- utimensat(AT_FDCWD, path, ts, 0)

uv_fs_futime()
    +-- INIT(FUTIME) + file + atime/mtime
    +-- POST -> uv__fs_work -> uv__fs_futime()
                                   +-- uv__fs_to_timespec() x2
                                   +-- futimens(file, ts)

uv_fs_lutime()
    +-- INIT(LUTIME) + PATH + atime/mtime
    +-- POST -> uv__fs_work -> uv__fs_lutime()
                                   +-- uv__fs_to_timespec() x2
                                   +-- utimensat(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW)
```

### データフロー図

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

atime (double) ----+
                   +---> uv__fs_to_timespec() ---> struct timespec
mtime (double) ----+           |
                          INFINITY -> UTIME_NOW
                          NAN -> UTIME_OMIT
                          通常 -> sec + nsec
                               |
                               v
                    utimensat / futimens           ---> result (0 or error)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | API宣言、UTIME_NOW/UTIME_OMITマクロ |
| fs.c | `src/unix/fs.c` | ソース | Unix系のutime/futime/lutime実装 |
| fs.c | `src/win/fs.c` | ソース | Windows版実装 |
