# 機能設計書 101-ファイル情報取得

## 概要

本ドキュメントは、libuvのファイルシステム操作APIのうち、ファイルのステータス情報を非同期で取得する機能（uv_fs_stat / uv_fs_fstat / uv_fs_lstat）について、その設計仕様を記載する。

### 本機能の処理概要

ファイルやディレクトリのメタデータ（サイズ、パーミッション、タイムスタンプ、所有者等）を取得する機能を提供する。パス指定（stat）、ファイルディスクリプタ指定（fstat）、シンボリックリンク非追跡（lstat）の3種類のAPIを備える。

**業務上の目的・背景**：アプリケーションがファイルの存在確認、サイズ確認、パーミッション確認、最終更新日時の取得などを行う際に不可欠な機能である。ファイルの変更監視、キャッシュの有効性判定、アクセス制御の判断材料として広く利用される。非同期版ではイベントループをブロックせずにこれらの情報を取得できるため、高スループットなアプリケーションの構築が可能となる。

**機能の利用シーン**：ファイルの存在確認、ファイルサイズの取得によるバッファ割り当て、ファイルの更新日時によるキャッシュ有効性判定、パーミッション確認によるアクセス制御、シンボリックリンクのリンク先ではなくリンク自体の情報取得など。

**主要な処理内容**：
1. リクエスト構造体（uv_fs_t）を初期化し、対象パスまたはファイルディスクリプタを設定する
2. コールバックが指定された場合はスレッドプールに処理を投入し非同期で実行する
3. Linuxではstatxシステムコールを優先使用し、フォールバックとしてstat/fstat/lstatを使用する
4. OS固有のstat結果をプラットフォーム非依存のuv_stat_t構造体に変換する
5. 結果をreq->statbufに格納し、req->ptrをstatbufへのポインタに設定する

**関連システム・外部連携**：POSIXのstat/fstat/lstat、Linuxのstatxシステムコール、Windowsファイル情報API。io_uringによるstatx高速化（Linux環境）。

**権限による制御**：対象パスの各ディレクトリに対する実行（検索）権限が必要。ファイル自体の読み取り権限は不要（メタデータのみ取得するため）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | ファイルシステム操作 | 主機能 | uv_fs_stat()/fstat()/lstat()によるファイルステータス情報取得のAPI定義 |

## 機能種別

データ取得処理（ファイルメタデータの読み取り）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | NULLの場合は同期実行不可 |
| req | uv_fs_t* | Yes | FSリクエスト構造体 | NULLの場合UV_EINVAL返却 |
| path | const char* | Yes（stat/lstat） | 対象ファイルパス | NULLでないことをassertで検証 |
| file | uv_file | Yes（fstat） | 対象ファイルディスクリプタ | 有効なFDであること |
| cb | uv_fs_cb | No | 完了コールバック | NULLの場合は同期実行 |

### 入力データソース

ユーザーがAPI呼び出し時に指定するファイルパスまたはファイルディスクリプタ。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| st_dev | uint64_t | デバイスID |
| st_mode | uint64_t | ファイルモード（パーミッションとファイルタイプ） |
| st_nlink | uint64_t | ハードリンク数 |
| st_uid | uint64_t | 所有者ユーザーID |
| st_gid | uint64_t | 所有者グループID |
| st_rdev | uint64_t | 特殊ファイルのデバイスID |
| st_ino | uint64_t | iノード番号 |
| st_size | uint64_t | ファイルサイズ（バイト） |
| st_blksize | uint64_t | I/Oブロックサイズ |
| st_blocks | uint64_t | 割り当てられたブロック数 |
| st_flags | uint64_t | ファイルフラグ（BSD系のみ） |
| st_gen | uint64_t | ファイル生成番号（BSD系のみ） |
| st_atim | uv_timespec_t | 最終アクセス時刻 |
| st_mtim | uv_timespec_t | 最終変更時刻 |
| st_ctim | uv_timespec_t | 最終ステータス変更時刻 |
| st_birthtim | uv_timespec_t | 作成時刻 |

### 出力先

uv_fs_t構造体のstatbufフィールド（uv_stat_t型）に格納される。非同期モードではコールバック関数の引数として渡されるuv_fs_t経由でアクセスする。uv_fs_get_statbuf()アクセサでも取得可能。

## 処理フロー

### 処理シーケンス

```
1. INITマクロによるリクエスト初期化
   └─ fs_type設定（STAT/FSTAT/LSTAT）、result/ptr/path/bufsの初期化
2. パスまたはファイルディスクリプタの設定
   └─ stat/lstat: PATHマクロでパスを設定（非同期時はstrdup）
   └─ fstat: req->fileにFDを設定
3. io_uring最適化の試行（Linux、非同期モードのみ）
   └─ uv__iou_fs_statx()によるio_uring経由のstatx実行試行
4. POSTマクロによる実行モード分岐
   └─ 非同期: スレッドプールにuv__fs_workを投入
   └─ 同期: uv__fs_workを直接呼び出し
5. uv__fs_work内でのstat実行
   └─ STAT: uv__fs_stat() → statx優先、フォールバックでstat()
   └─ FSTAT: uv__fs_fstat() → statx優先、フォールバックでfstat()
   └─ LSTAT: uv__fs_lstat() → statx優先、フォールバックでlstat()
6. 結果変換
   └─ uv__to_stat()またはuv__statx_to_stat()でuv_stat_tに変換
7. ポインタ設定
   └─ r == 0の場合、req->ptr = &req->statbufに設定
```

### フローチャート

```mermaid
flowchart TD
    A[uv_fs_stat/fstat/lstat呼び出し] --> B[INITマクロ: リクエスト初期化]
    B --> C{stat種別}
    C -->|stat/lstat| D[PATHマクロ: パス設定]
    C -->|fstat| E[req->file設定]
    D --> F{cb != NULL?}
    E --> F
    F -->|Yes| G{io_uring利用可能?}
    G -->|Yes| H[io_uring経由でstatx実行]
    G -->|No| I[スレッドプールに投入]
    F -->|No| J[同期実行: uv__fs_work直接呼び出し]
    I --> K[uv__fs_work実行]
    J --> K
    K --> L{Linux && statx利用可能?}
    L -->|Yes| M[statxシステムコール]
    L -->|No| N[stat/fstat/lstat呼び出し]
    M --> O[uv__statx_to_stat変換]
    N --> P[uv__to_stat変換]
    O --> Q[req->ptr = &req->statbuf]
    P --> Q
    H --> R[結果返却]
    Q --> R
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-101 | statx優先使用 | Linuxではstatxシステムコールを優先的に使用し、EINVAL/EPERM/ENOSYS/EOPNOTSUPPの場合はstat()にフォールバックする | Linux環境 |
| BR-102 | lstatのシンボリックリンク非追跡 | lstatではAT_SYMLINK_NOFOLLOWフラグを使用し、シンボリックリンク自体の情報を返す | uv_fs_lstat呼び出し時 |
| BR-103 | statbufポインタ設定 | stat/fstat/lstatの結果が成功（r==0）の場合、req->ptrにreq->statbufへのポインタを設定する | 処理成功時 |
| BR-104 | 同期・非同期モード切替 | cbがNULLの場合は同期実行、非NULLの場合はスレッドプール経由で非同期実行 | 常時 |

### 計算ロジック

タイムスタンプ変換：OS固有のstat構造体からuv_stat_tへの変換では、プラットフォームごとに異なるタイムスタンプフィールド名を適切にマッピングする。Apple環境ではst_atimespec、Android環境ではst_atime+st_atimensec、GNU/BSD環境ではst_atimからuv_stat_tのst_atimへ変換する。

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

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

該当なし（ファイルシステムからのメタデータ読み取りのみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | パラメータエラー | reqがNULL | 有効なリクエスト構造体を渡す |
| UV_ENOENT | ファイル不在 | 指定パスが存在しない | パスの正当性を確認する |
| UV_EACCES | 権限エラー | パスの途中ディレクトリに検索権限がない | 権限を確認する |
| UV_EBADF | 不正FD | fstatに無効なFDが渡された | 有効なFDを確認する |
| UV_ENOMEM | メモリ不足 | 非同期モードでのパスコピーに失敗 | メモリを解放する |
| UV_ECANCELED | キャンセル | uv_cancel()でリクエストがキャンセルされた | 必要に応じて再実行 |

### リトライ仕様

EINTRで中断された場合、uv__fs_work内のdo-whileループで自動的にリトライされる。stat系はretry_on_eintrがtrue（UV_FS_CLOSEとUV_FS_READ以外）であるため、リトライが行われる。

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

該当なし（読み取り専用操作）

## パフォーマンス要件

- Linux環境ではstatxシステムコールを優先使用し、1回のシステムコールで誕生時刻（btime）を含む全情報を取得する
- io_uring対応環境では非同期statxをio_uring経由で実行し、スレッドプールのスレッドを消費しない
- 同期モードではスレッドプールを使用せず直接システムコールを呼び出すため、オーバーヘッドが小さい

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

- 対象ファイルの読み取り権限がなくてもメタデータは取得可能（POSIXの仕様に準拠）
- シンボリックリンクの追跡によるシンボリックリンク攻撃を避けるにはlstatを使用する
- 非同期モードでのパスコピーにより、呼び出し元がパスを変更しても安全に動作する

## 備考

- statxが利用できない環境では自動的にstat/fstat/lstatにフォールバックする
- st_flagsとst_genはBSD系OS（FreeBSD、NetBSD、macOS）でのみ有効な値が設定される
- st_birthtimは全プラットフォームで設定されるが、サポートされないOSではst_ctimの値がコピーされる
- コールバック内でuv_fs_req_cleanup()を呼び出してリソースを解放する必要がある

---

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

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

### 推奨読解順序

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

まず、stat結果を格納するデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | uv_stat_t構造体の定義（384-401行目）。全フィールドがuint64_t型で統一されている |
| 1-2 | uv.h | `include/uv.h` | uv_fs_t構造体の定義（1450-1460行目）。statbufフィールドがuv_stat_t型 |
| 1-3 | uv.h | `include/uv.h` | uv_timespec_t構造体（366-369行目）。タイムスタンプのsec/nsec |

**読解のコツ**: uv_stat_tはPOSIXのstruct statをプラットフォーム非依存にしたラッパー構造体である。全フィールドがuint64_t型に統一されているのが特徴で、32bit/64bitの差異を吸収している。

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

APIの公開関数が処理の起点となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | uv.h | `include/uv.h` | uv_fs_stat()宣言（1558-1561行目）、uv_fs_fstat()宣言（1562-1565行目）、uv_fs_lstat()宣言（1621-1624行目） |
| 2-2 | fs.c | `src/unix/fs.c` | uv_fs_stat()実装（2157-2164行目）。INIT/PATH/POSTマクロのパターン |
| 2-3 | fs.c | `src/unix/fs.c` | uv_fs_fstat()実装（1876-1883行目）。io_uring最適化の分岐 |
| 2-4 | fs.c | `src/unix/fs.c` | uv_fs_lstat()実装（1938-1945行目）。io_uring最適化の分岐 |

**主要処理フロー**:
1. **90-104行目**: INITマクロ -- リクエスト構造体の初期化（fs_type、result、ptr等）
2. **106-117行目**: PATHマクロ -- パスの設定（非同期時はstrdup）
3. **139-155行目**: POSTマクロ -- 非同期ならスレッドプール投入、同期なら直接実行

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

statの実際のシステムコール呼び出し部分。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fs.c | `src/unix/fs.c` | uv__fs_stat()実装（1574-1587行目）。statx優先、stat()フォールバック |
| 3-2 | fs.c | `src/unix/fs.c` | uv__fs_fstat()実装（1606-1619行目）。FD指定版 |
| 3-3 | fs.c | `src/unix/fs.c` | uv__fs_lstat()実装（1590-1603行目）。シンボリックリンク非追跡版 |
| 3-4 | fs.c | `src/unix/fs.c` | uv__fs_statx()実装（1513-1571行目）。Linuxのstatxシステムコール |
| 3-5 | fs.c | `src/unix/fs.c` | uv__to_stat()実装（1435-1510行目）。struct stat → uv_stat_t変換 |

**主要処理フロー**:
- **1574-1587行目**: uv__fs_stat -- statxを試行し、UV_ENOSYSならstat()にフォールバック
- **1513-1571行目**: uv__fs_statx -- Linux上でstatxシステムコールを使用。EINVAL/EPERM/ENOSYS/EOPNOTSUPPの場合にUV_ENOSYSを返却
- **1435-1510行目**: uv__to_stat -- プラットフォームごとの条件コンパイルでタイムスタンプフィールドを適切に変換

#### Step 4: ディスパッチャを理解する

uv__fs_workが全FSオペレーションのディスパッチャである。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | fs.c | `src/unix/fs.c` | uv__fs_work()実装（1681-1750行目）。switchによるFS操作のディスパッチ |
| 4-2 | fs.c | `src/unix/fs.c` | uv__fs_done()実装（1753-1765行目）。非同期完了時のコールバック呼び出し |

**主要処理フロー**:
- **1708行目**: FSTAT -> uv__fs_fstat(req->file, &req->statbuf)
- **1713行目**: LSTAT -> uv__fs_lstat(req->path, &req->statbuf)
- **1729行目**: STAT -> uv__fs_stat(req->path, &req->statbuf)
- **1745-1749行目**: 成功時にreq->ptr = &req->statbufを設定

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

```
uv_fs_stat() / uv_fs_fstat() / uv_fs_lstat()
    |
    +-- INIT(STAT/FSTAT/LSTAT)  ... リクエスト初期化
    +-- PATH / req->file設定   ... パラメータ設定
    +-- [Linux非同期] uv__iou_fs_statx()  ... io_uring最適化
    +-- POST
         |
         +-- [非同期] uv__work_submit()
         |       +-- uv__fs_work()
         |       |       +-- uv__fs_stat() / uv__fs_fstat() / uv__fs_lstat()
         |       |       |       +-- uv__fs_statx()  ... Linux statx
         |       |       |       +-- uv__to_stat()    ... stat結果変換
         |       |       +-- req->ptr = &req->statbuf
         |       +-- uv__fs_done()
         |               +-- req->cb(req)
         |
         +-- [同期] uv__fs_work()  ... 直接呼び出し
```

### データフロー図

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

path (const char*)  ──► uv_fs_stat()                    ──► uv_fs_t.statbuf (uv_stat_t)
                         |                                    |
                         v                                    +-- st_dev, st_ino
                    uv__fs_stat()                             +-- st_mode, st_nlink
                         |                                    +-- st_uid, st_gid
                    +----+----+                               +-- st_size, st_blksize
                    v         v                               +-- st_blocks
              uv__fs_statx  stat()                            +-- st_atim, st_mtim
                    |         |                               +-- st_ctim, st_birthtim
                    v         v                               +-- st_flags, st_gen
            uv__statx_to_stat  uv__to_stat
                    |         |
                    +----+----+
                         v
                  req->statbuf に格納
                  req->ptr = &req->statbuf
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | uv_stat_t、uv_fs_t、API宣言 |
| fs.c | `src/unix/fs.c` | ソース | Unix系のstat/fstat/lstat実装 |
| fs.c | `src/win/fs.c` | ソース | Windows版のstat/fstat/lstat実装 |
| uv-common.c | `src/uv-common.c` | ソース | 共通ユーティリティ |
| internal.h | `src/unix/internal.h` | ヘッダー | Unix内部関数宣言 |
