# 機能設計書 169-グループ情報取得

## 概要

本ドキュメントは、libuv の `uv_os_get_group()` / `uv_os_free_group()` APIによるグループ情報（グループ名、GID、メンバー一覧）の取得・解放機能について記述する。

### 本機能の処理概要

本機能は、POSIXのグループデータベース（/etc/group等）から指定GIDのグループ情報を取得し、`uv_group_t`構造体に格納するためのクロスプラットフォームAPIを提供する。

**業務上の目的・背景**：グループ名、GID、グループメンバー一覧などの情報は、ファイルアクセス権の判定、グループベースの権限制御、ユーザー管理機能に必要となる。本機能はPOSIXの`getgrgid_r()`とWindowsのグループ情報APIの差異を吸収し、統一的なインターフェースを提供する。

**機能の利用シーン**：ファイルのグループ所有者名の解決、グループベースのアクセス制御の実装、グループメンバー一覧の取得、システム管理ツールでのグループ情報表示に利用される。

**主要な処理内容**：
1. `uv_os_get_group()`: 指定GIDのグループ情報（グループ名、GID、メンバー一覧）を取得する
2. `uv_os_free_group()`: 取得したグループ情報のメモリを解放する
3. 内部的に`getgrgid_r()`を呼び出し、バッファが不足する場合は自動的に拡大する
4. グループメンバー一覧をNULL終端の文字列ポインタ配列として構築する

**関連システム・外部連携**：POSIX `getgrgid_r()`（Unix）、Windows `NetGroupGetInfo()` / `NetLocalGroupGetMembers()`を使用する。

**権限による制御**：/etc/groupの読み取り権限は通常全ユーザーに開かれている。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 29 | その他ユーティリティ | 主機能 | uv_os_get_group()/free_group()によるグループ情報取得のAPI定義 |

## 機能種別

システム情報取得・メモリ管理

## 入力仕様

### 入力パラメータ

#### uv_os_get_group()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| grp | uv_group_t* | Yes | グループ情報格納先 | NULLでないこと |
| gid | uv_uid_t | Yes | 取得対象のグループID | 有効なGID |

#### uv_os_free_group()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| grp | uv_group_t* | Yes | 解放するグループ情報 | NULLの場合は何もしない |

### 入力データソース

OSグループデータベース（/etc/group、NIS、LDAP等）

## 出力仕様

### 出力データ

#### uv_os_get_group()

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 成功時0、エラー時負のエラーコード |

#### uv_group_t 構造体

| フィールド | 型 | 説明 |
|-----------|-----|------|
| groupname | char* | グループ名 |
| gid | unsigned long | グループID |
| members | char** | メンバーユーザー名のNULL終端配列 |

### 出力先

呼び出し元のuv_group_t構造体に格納（動的メモリ確保）

## 処理フロー

### 処理シーケンス

```
uv_os_get_group():
1. 入力バリデーション（grp != NULL）
2. バッファサイズ2000バイトから開始
3. uv__malloc()でバッファを確保
4. getgrgid_r(gid, &gp, buf, bufsize, &result)を呼び出す
   └─ EINTRの場合はリトライ
5. ERANGEの場合はバッファサイズを2倍にして再試行
6. 結果がNULLの場合UV_ENOENTを返す
7. グループ名サイズとメンバー配列サイズを計算
   └─ メンバー数をカウントし、各メンバー名の文字列サイズ + ポインタサイズを合算
8. 単一のuv__malloc()で全データ領域を確保
9. メンバーポインタ配列とメンバー名文字列をコピー
10. グループ名をコピー
11. GIDを設定
12. 一時バッファを解放して成功を返す

uv_os_free_group():
1. grpがNULLなら何もしない
2. grp->membersをuv__free()で解放（メンバー配列とグループ名は同一ブロック）
3. members, groupnameポインタをNULLに設定
```

### フローチャート

```mermaid
flowchart TD
    A[uv_os_get_group grp, gid] --> B{grp == NULL?}
    B -->|Yes| C[UV_EINVAL返却]
    B -->|No| D[bufsize = 2000]
    D --> E[buf = uv__malloc bufsize]
    E --> F{メモリ確保成功?}
    F -->|No| G[UV_ENOMEM返却]
    F -->|Yes| H[getgrgid_r gid, &gp, buf, bufsize, &result]
    H --> I{r == EINTR?}
    I -->|Yes| H
    I -->|No| J{r == ERANGE?}
    J -->|Yes| K[uv__free buf, bufsize *= 2]
    K --> E
    J -->|No| L{r != 0?}
    L -->|Yes| M[UV__ERR r 返却]
    L -->|No| N{result == NULL?}
    N -->|Yes| O[UV_ENOENT返却]
    N -->|No| P[メンバー数カウント + サイズ計算]
    P --> Q[uv__malloc name_size + mem_size]
    Q --> R[メンバー配列構築]
    R --> S[グループ名コピー, GID設定]
    S --> T[uv__free buf, return 0]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | バッファ自動拡大 | getgrgid_r()がERANGEを返した場合、バッファを2倍に拡大して再試行 | ERANGE発生時 |
| BR-02 | EINTR再試行 | getgrgid_r()がEINTRを返した場合、自動的にリトライ | EINTR発生時 |
| BR-03 | NULL終端メンバー配列 | members配列の最後はNULLポインタで終端される | 常時 |
| BR-04 | 単一アロケーション | members配列、メンバー名文字列、グループ名は単一のuv__malloc()で確保 | メモリ確保時 |
| BR-05 | Android制限 | Android API Level 24未満ではUV_ENOSYSを返す | Android環境 |

### 計算ロジック

メモリサイズ計算：
```
mem_size = sizeof(char*)  // NULL終端用
for each member:
    mem_size += strlen(member_name) + 1 + sizeof(char*)
total_size = name_size + mem_size
```

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

該当なし（OSのグループデータベースはシステムリソース）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | バリデーションエラー | grpがNULL | 有効なポインタを指定する |
| UV_ENOMEM | メモリ不足 | uv__malloc()が失敗 | メモリを解放してリトライ |
| UV_ENOENT | グループ未存在 | 指定GIDのグループが見つからない | 存在するGIDを指定する |
| UV_ENOSYS | 未サポート | Android API Level 24未満 | サポートされる環境で実行する |

### リトライ仕様

getgrgid_r()がEINTRを返した場合は自動的にリトライする。

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

該当なし

## パフォーマンス要件

getgrgid_r()はNSS経由でグループ情報を取得するため、リモートソース使用時はネットワーク遅延が発生する可能性がある。メンバー数が多い場合はメモリサイズ計算とコピーに時間がかかる。

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

- グループメンバー一覧は通常公開情報だが、セキュリティポリシーによっては制限される場合がある
- 大量のメンバーを持つグループの場合、メモリ使用量が増大する可能性がある

## 備考

- Android API Level 24未満では`getgrgid_r()`が利用できないため、UV_ENOSYSを返す
- 初期バッファサイズは2000バイト
- members配列の構造: [ptr0][ptr1]...[ptrN][NULL][str0\0][str1\0]...[strN\0][groupname\0]
- `include/uv.h` L1239-1243 で構造体定義、L1318-1319 でAPI定義

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | L1239-1243: uv_group_s構造体定義（groupname, gid, members） |
| 1-2 | uv.h | `include/uv.h` | L1318-1319: uv_os_get_group()/uv_os_free_group()のAPI宣言 |

**読解のコツ**: `members`フィールドは`char**`型で、NULL終端のポインタ配列。各ポインタはメンバーユーザー名の文字列を指す。全データ（ポインタ配列 + 文字列 + グループ名）が単一のメモリブロックに格納されている点が重要。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | core.c | `src/unix/core.c` | L1423-1505: uv_os_get_group()のUnix実装 |

**主要処理フロー**:
1. **1424-1426行目**: Android API 24未満チェック（UV_ENOSYS）
2. **1438-1439行目**: grpのNULLチェック
3. **1444行目**: bufsize=2000でループ開始
4. **1450-1452行目**: getgrgid_r()呼び出し（EINTRリトライ）
5. **1467-1474行目**: メンバー数カウントとメモリサイズ計算
6. **1476行目**: 単一メモリブロック確保
7. **1482-1490行目**: メンバーポインタ配列と文字列のコピー
8. **1494-1496行目**: グループ名のコピー
9. **1499行目**: GID設定

#### Step 3: 解放処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | uv-common.c | `src/uv-common.c` | L150-161: uv_os_free_group()の実装 |

**主要処理フロー**:
- **151-152行目**: grpがNULLなら即return
- **158行目**: `uv__free(grp->members)` で全メモリを解放
- **159-160行目**: members, groupnameをNULLに設定

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

```
uv_os_get_group(grp, gid) [src/unix/core.c:1423]
    |
    +-- uv__malloc(bufsize) [バッファ確保]
    +-- getgrgid_r(gid, &gp, buf, bufsize, &result) [POSIX]
    |      +-- (EINTR) -> リトライ
    |      +-- (ERANGE) -> bufsize *= 2, 再試行
    +-- uv__malloc(name_size + mem_size) [データ領域確保]
    +-- strcpy/memcpy [メンバー・グループ名コピー]
    +-- uv__free(buf) [一時バッファ解放]

uv_os_free_group(grp) [src/uv-common.c:150]
    |
    +-- uv__free(grp->members) [全データ解放]
```

### データフロー図

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

grp (uv_group_t*)  ───> getgrgid_r() でグループDB参照   ───> grp->groupname
gid (uv_uid_t)          メモリ確保 + データコピー             grp->gid
                         メンバーポインタ配列構築              grp->members (char**)
                                                              戻り値 (0 or エラー)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | 構造体定義（L1239-1243）、API宣言（L1318-1319） |
| core.c | `src/unix/core.c` | ソース | Unix実装（L1423-1505） |
| uv-common.c | `src/uv-common.c` | ソース | uv_os_free_group()（L150-161） |
| util.c | `src/win/util.c` | ソース | Windows実装 |
